24 bool x11GraphicsPipe::_error_handlers_installed =
false;
25 x11GraphicsPipe::ErrorHandlerFunc *x11GraphicsPipe::_prev_error_handler;
26 x11GraphicsPipe::IOErrorHandlerFunc *x11GraphicsPipe::_prev_io_error_handler;
27 bool x11GraphicsPipe::_x_error_messages_enabled =
true;
28 int x11GraphicsPipe::_x_error_count = 0;
36 x11GraphicsPipe(
const std::string &display) :
39 _XF86DGADirectVideo(nullptr) {
41 std::string display_spec = display;
42 if (display_spec.empty()) {
43 display_spec = display_cfg;
45 if (display_spec.empty()) {
48 if (display_spec.empty()) {
49 display_spec =
":0.0";
54 setlocale(LC_ALL,
"");
59 setlocale(LC_NUMERIC,
"C");
62 _supported_types = OT_window | OT_buffer | OT_texture_buffer;
65 _root = (X11_Window)
nullptr;
67 _hidden_cursor = None;
75 install_error_handlers();
77 _display = XOpenDisplay(display_spec.c_str());
79 x11display_cat.error()
80 <<
"Could not open display \"" << display_spec <<
"\".\n";
89 if (!XSupportsLocale()) {
90 x11display_cat.warning()
91 <<
"X does not support locale " << setlocale(LC_ALL,
nullptr) <<
"\n";
93 XSetLocaleModifiers(
"");
95 _screen = DefaultScreen(_display);
96 _root = RootWindow(_display, _screen);
97 _display_width = DisplayWidth(_display, _screen);
98 _display_height = DisplayHeight(_display, _screen);
102 void *xf86dga = dlopen(
"libXxf86dga.so.1", RTLD_NOW | RTLD_LOCAL);
103 if (xf86dga !=
nullptr) {
104 pfn_XF86DGAQueryVersion _XF86DGAQueryVersion = (pfn_XF86DGAQueryVersion)dlsym(xf86dga,
"XF86DGAQueryVersion");
105 _XF86DGADirectVideo = (pfn_XF86DGADirectVideo)dlsym(xf86dga,
"XF86DGADirectVideo");
107 int major_ver, minor_ver;
108 if (_XF86DGAQueryVersion ==
nullptr || _XF86DGADirectVideo ==
nullptr) {
109 x11display_cat.warning()
110 <<
"libXxf86dga.so.1 does not provide required functions; relative mouse mode will not work.\n";
112 }
else if (!_XF86DGAQueryVersion(_display, &major_ver, &minor_ver)) {
113 _XF86DGADirectVideo =
nullptr;
116 _XF86DGADirectVideo =
nullptr;
117 if (x11display_cat.is_debug()) {
118 x11display_cat.debug()
119 <<
"cannot dlopen libXxf86dga.so.1; cursor changing will not work.\n";
124 void *xcursor = dlopen(
"libXcursor.so.1", RTLD_NOW | RTLD_LOCAL);
125 if (xcursor !=
nullptr) {
126 pfn_XcursorGetDefaultSize _XcursorGetDefaultSize = (pfn_XcursorGetDefaultSize)dlsym(xcursor,
"XcursorGetDefaultSize");
127 _XcursorXcFileLoadImages = (pfn_XcursorXcFileLoadImages)dlsym(xcursor,
"XcursorXcFileLoadImages");
128 _XcursorImagesLoadCursor = (pfn_XcursorImagesLoadCursor)dlsym(xcursor,
"XcursorImagesLoadCursor");
129 _XcursorImagesDestroy = (pfn_XcursorImagesDestroy)dlsym(xcursor,
"XcursorImagesDestroy");
130 _XcursorImageCreate = (pfn_XcursorImageCreate)dlsym(xcursor,
"XcursorImageCreate");
131 _XcursorImageLoadCursor = (pfn_XcursorImageLoadCursor)dlsym(xcursor,
"XcursorImageLoadCursor");
132 _XcursorImageDestroy = (pfn_XcursorImageDestroy)dlsym(xcursor,
"XcursorImageDestroy");
134 if (_XcursorGetDefaultSize ==
nullptr || _XcursorXcFileLoadImages ==
nullptr ||
135 _XcursorImagesLoadCursor ==
nullptr || _XcursorImagesDestroy ==
nullptr ||
136 _XcursorImageCreate ==
nullptr || _XcursorImageLoadCursor ==
nullptr ||
137 _XcursorImageDestroy ==
nullptr) {
139 x11display_cat.warning()
140 <<
"libXcursor.so.1 does not provide required functions; cursor changing will not work.\n";
142 }
else if (x_cursor_size.
get_value() >= 0) {
143 _xcursor_size = x_cursor_size;
145 _xcursor_size = _XcursorGetDefaultSize(_display);
149 if (x11display_cat.is_debug()) {
150 x11display_cat.debug()
151 <<
"cannot dlopen libXcursor.so.1; cursor changing will not work.\n";
156 void *xrandr = dlopen(
"libXrandr.so.2", RTLD_NOW | RTLD_LOCAL);
157 if (xrandr !=
nullptr) {
158 pfn_XRRQueryExtension _XRRQueryExtension = (pfn_XRRQueryExtension)dlsym(xrandr,
"XRRQueryExtension");
159 pfn_XRRQueryVersion _XRRQueryVersion = (pfn_XRRQueryVersion)dlsym(xrandr,
"XRRQueryVersion");
161 _XRRSizes = (pfn_XRRSizes)dlsym(xrandr,
"XRRSizes");
162 _XRRRates = (pfn_XRRRates)dlsym(xrandr,
"XRRRates");
163 _XRRGetScreenInfo = (pfn_XRRGetScreenInfo)dlsym(xrandr,
"XRRGetScreenInfo");
164 _XRRConfigCurrentConfiguration = (pfn_XRRConfigCurrentConfiguration)dlsym(xrandr,
"XRRConfigCurrentConfiguration");
165 _XRRSetScreenConfig = (pfn_XRRSetScreenConfig)dlsym(xrandr,
"XRRSetScreenConfig");
167 int event, error, major, minor;
168 if (_XRRQueryExtension ==
nullptr || _XRRSizes ==
nullptr || _XRRRates ==
nullptr ||
169 _XRRGetScreenInfo ==
nullptr || _XRRConfigCurrentConfiguration ==
nullptr ||
170 _XRRSetScreenConfig ==
nullptr || _XRRQueryVersion ==
nullptr) {
171 _have_xrandr =
false;
172 x11display_cat.warning()
173 <<
"libXrandr.so.2 does not provide required functions; resolution setting will not work.\n";
175 else if (_XRRQueryExtension(_display, &event, &error) &&
176 _XRRQueryVersion(_display, &major, &minor)) {
178 if (x11display_cat.is_debug()) {
179 x11display_cat.debug()
180 <<
"Found RandR extension " << major <<
"." << minor <<
"\n";
183 if (major > 1 || (major == 1 && minor >= 2)) {
184 if (major > 1 || (major == 1 && minor >= 3)) {
185 _XRRGetScreenResourcesCurrent = (pfn_XRRGetScreenResources)
186 dlsym(xrandr,
"XRRGetScreenResourcesCurrent");
189 _XRRGetScreenResourcesCurrent = (pfn_XRRGetScreenResources)
190 dlsym(xrandr,
"XRRGetScreenResources");
193 _XRRFreeScreenResources = (pfn_XRRFreeScreenResources)dlsym(xrandr,
"XRRFreeScreenResources");
194 _XRRGetCrtcInfo = (pfn_XRRGetCrtcInfo)dlsym(xrandr,
"XRRGetCrtcInfo");
195 _XRRFreeCrtcInfo = (pfn_XRRFreeCrtcInfo)dlsym(xrandr,
"XRRFreeCrtcInfo");
197 _XRRGetScreenResourcesCurrent =
nullptr;
198 _XRRFreeScreenResources =
nullptr;
199 _XRRGetCrtcInfo =
nullptr;
200 _XRRFreeCrtcInfo =
nullptr;
203 _have_xrandr =
false;
204 if (x11display_cat.is_debug()) {
205 x11display_cat.debug()
206 <<
"RandR extension not supported; resolution setting will not work.\n";
210 _have_xrandr =
false;
211 if (x11display_cat.is_debug()) {
212 x11display_cat.debug()
213 <<
"cannot dlopen libXrandr.so.2; resolution setting will not work.\n";
221 if (
auto res = get_screen_resources()) {
222 if (x11display_cat.is_debug()) {
223 x11display_cat.debug()
224 <<
"Using XRRScreenResources to obtain display modes\n";
226 _display_information->_total_display_modes = res->nmode;
227 _display_information->_display_mode_array =
new DisplayMode[res->nmode];
228 for (
int i = 0; i < res->nmode; ++i) {
231 DisplayMode *dm = _display_information->_display_mode_array + i;
232 dm->width = mode.width;
233 dm->height = mode.height;
234 dm->bits_per_pixel = -1;
235 dm->fullscreen_only =
false;
237 if (mode.hTotal && mode.vTotal) {
238 dm->refresh_rate = (double)mode.dotClock /
239 ((
double)mode.hTotal * (double)mode.vTotal);
241 dm->refresh_rate = 0;
245 if (x11display_cat.is_debug()) {
246 x11display_cat.debug()
247 <<
"Using XRRSizes and XRRRates to obtain display modes\n";
250 int num_sizes, num_rates;
252 xrrs = _XRRSizes(_display, 0, &num_sizes);
253 _display_information->_total_display_modes = 0;
254 for (
int i = 0; i < num_sizes; ++i) {
255 _XRRRates(_display, 0, i, &num_rates);
256 _display_information->_total_display_modes += num_rates;
261 _display_information->_display_mode_array =
new DisplayMode[_display_information->_total_display_modes];
262 for (
int i = 0; i < num_sizes; ++i) {
264 rates = _XRRRates(_display, 0, i, &num_rates);
265 for (
int j = 0; j < num_rates; ++j) {
266 DisplayMode* dm = _display_information->_display_mode_array + counter;
267 dm->width = xrrs[i].width;
268 dm->height = xrrs[i].height;
269 dm->refresh_rate = rates[j];
270 dm->bits_per_pixel = -1;
271 dm->fullscreen_only =
false;
279 _im = XOpenIM(_display,
nullptr,
nullptr,
nullptr);
280 if (_im == (XIM)
nullptr) {
282 XSetLocaleModifiers(
"@im=none");
283 _im = XOpenIM(_display,
nullptr,
nullptr,
nullptr);
284 if (_im == (XIM)
nullptr) {
285 x11display_cat.warning()
286 <<
"Couldn't open input method.\n";
304 _wm_delete_window = XInternAtom(_display,
"WM_DELETE_WINDOW",
false);
305 _net_wm_pid = XInternAtom(_display,
"_NET_WM_PID",
false);
306 _net_wm_window_type = XInternAtom(_display,
"_NET_WM_WINDOW_TYPE",
false);
307 _net_wm_window_type_splash = XInternAtom(_display,
"_NET_WM_WINDOW_TYPE_SPLASH",
false);
308 _net_wm_window_type_fullscreen = XInternAtom(_display,
"_NET_WM_WINDOW_TYPE_FULLSCREEN",
false);
309 _net_wm_state = XInternAtom(_display,
"_NET_WM_STATE",
false);
310 _net_wm_state_fullscreen = XInternAtom(_display,
"_NET_WM_STATE_FULLSCREEN",
false);
311 _net_wm_state_above = XInternAtom(_display,
"_NET_WM_STATE_ABOVE",
false);
312 _net_wm_state_below = XInternAtom(_display,
"_NET_WM_STATE_BELOW",
false);
313 _net_wm_state_add = XInternAtom(_display,
"_NET_WM_STATE_ADD",
false);
314 _net_wm_state_remove = XInternAtom(_display,
"_NET_WM_STATE_REMOVE",
false);
315 _net_wm_bypass_compositor = XInternAtom(_display,
"_NET_WM_BYPASS_COMPOSITOR",
false);
323 release_hidden_cursor();
328 XCloseDisplay(_display);
339 if (_have_xrandr && _XRRGetScreenResourcesCurrent !=
nullptr) {
340 res = _XRRGetScreenResourcesCurrent(_display, _root);
343 return std::unique_ptr<XRRScreenResources, pfn_XRRFreeScreenResources>(res, _XRRFreeScreenResources);
353 if (_have_xrandr && _XRRGetCrtcInfo !=
nullptr) {
354 info = _XRRGetCrtcInfo(_display, res, crtc);
357 return std::unique_ptr<XRRCrtcInfo, pfn_XRRFreeCrtcInfo>(info, _XRRFreeCrtcInfo);
369 int &x,
int &y,
int &width,
int &height) {
372 width = DisplayWidth(_display, _screen);
373 height = DisplayHeight(_display, _screen);
376 for (
int i = 0; i < res->ncrtc; ++i) {
377 RRCrtc crtc = res->crtcs[i];
379 if (point[0] >= info->x && point[0] < info->x + (
int)info->width &&
380 point[1] >= info->y && point[1] < info->y + (
int)info->height) {
384 width = (int)info->width;
385 height = (
int)info->height;
400 GraphicsPipe::PreferredWindowThread
419 void x11GraphicsPipe::
420 make_hidden_cursor() {
421 nassertv(_hidden_cursor == None);
423 unsigned int x_size, y_size;
424 XQueryBestCursor(_display, _root, 1, 1, &x_size, &y_size);
426 Pixmap empty = XCreatePixmap(_display, _root, x_size, y_size, 1);
429 memset(&black, 0,
sizeof(black));
431 _hidden_cursor = XCreatePixmapCursor(_display, empty, empty,
432 &black, &black, x_size, y_size);
433 XFreePixmap(_display, empty);
440 void x11GraphicsPipe::
441 release_hidden_cursor() {
442 if (_hidden_cursor != None) {
443 XFreeCursor(_display, _hidden_cursor);
444 _hidden_cursor = None;
455 void x11GraphicsPipe::
456 install_error_handlers() {
457 if (_error_handlers_installed) {
461 _prev_error_handler = (ErrorHandlerFunc *)XSetErrorHandler(error_handler);
462 _prev_io_error_handler = (IOErrorHandlerFunc *)XSetIOErrorHandler(io_error_handler);
463 _error_handlers_installed =
true;
469 int x11GraphicsPipe::
470 error_handler(X11_Display *display, XErrorEvent *error) {
473 static const int msg_len = 80;
475 XGetErrorText(display, error->error_code, msg, msg_len);
477 if (!_x_error_messages_enabled) {
478 if (x11display_cat.is_debug()) {
479 x11display_cat.debug()
485 x11display_cat.error()
500 int x11GraphicsPipe::
501 io_error_handler(X11_Display *display) {
502 x11display_cat.fatal()
503 <<
"X fatal error on display " << (
void *)display <<
"\n";