25 bool x11GraphicsPipe::_error_handlers_installed =
false;
26 x11GraphicsPipe::ErrorHandlerFunc *x11GraphicsPipe::_prev_error_handler;
27 x11GraphicsPipe::IOErrorHandlerFunc *x11GraphicsPipe::_prev_io_error_handler;
28 bool x11GraphicsPipe::_x_error_messages_enabled =
true;
29 int x11GraphicsPipe::_x_error_count = 0;
37 x11GraphicsPipe(
const std::string &display) :
40 _XF86DGADirectVideo(nullptr) {
42 std::string display_spec = display;
43 if (display_spec.empty()) {
44 display_spec = display_cfg;
46 if (display_spec.empty()) {
49 if (display_spec.empty()) {
50 display_spec =
":0.0";
55 setlocale(LC_ALL,
"");
60 setlocale(LC_NUMERIC,
"C");
63 _supported_types = OT_window | OT_buffer | OT_texture_buffer;
66 _root = (X11_Window)
nullptr;
68 _hidden_cursor = None;
76 install_error_handlers();
78 _display = XOpenDisplay(display_spec.c_str());
80 x11display_cat.error()
81 <<
"Could not open display \"" << display_spec <<
"\".\n";
90 if (!XSupportsLocale()) {
91 x11display_cat.warning()
92 <<
"X does not support locale " << setlocale(LC_ALL,
nullptr) <<
"\n";
94 XSetLocaleModifiers(
"");
96 _screen = DefaultScreen(_display);
97 _root = RootWindow(_display, _screen);
98 _display_width = DisplayWidth(_display, _screen);
99 _display_height = DisplayHeight(_display, _screen);
103 void *xf86dga = dlopen(
"libXxf86dga.so.1", RTLD_NOW | RTLD_LOCAL);
104 if (xf86dga !=
nullptr) {
105 pfn_XF86DGAQueryVersion _XF86DGAQueryVersion = (pfn_XF86DGAQueryVersion)dlsym(xf86dga,
"XF86DGAQueryVersion");
106 _XF86DGADirectVideo = (pfn_XF86DGADirectVideo)dlsym(xf86dga,
"XF86DGADirectVideo");
108 int major_ver, minor_ver;
109 if (_XF86DGAQueryVersion ==
nullptr || _XF86DGADirectVideo ==
nullptr) {
110 x11display_cat.warning()
111 <<
"libXxf86dga.so.1 does not provide required functions; relative mouse mode will not work.\n";
113 }
else if (!_XF86DGAQueryVersion(_display, &major_ver, &minor_ver)) {
114 _XF86DGADirectVideo =
nullptr;
117 _XF86DGADirectVideo =
nullptr;
118 if (x11display_cat.is_debug()) {
119 x11display_cat.debug()
120 <<
"cannot dlopen libXxf86dga.so.1; cursor changing will not work.\n";
125 void *xcursor = dlopen(
"libXcursor.so.1", RTLD_NOW | RTLD_LOCAL);
126 if (xcursor !=
nullptr) {
127 pfn_XcursorGetDefaultSize _XcursorGetDefaultSize = (pfn_XcursorGetDefaultSize)dlsym(xcursor,
"XcursorGetDefaultSize");
128 _XcursorXcFileLoadImages = (pfn_XcursorXcFileLoadImages)dlsym(xcursor,
"XcursorXcFileLoadImages");
129 _XcursorImagesLoadCursor = (pfn_XcursorImagesLoadCursor)dlsym(xcursor,
"XcursorImagesLoadCursor");
130 _XcursorImagesDestroy = (pfn_XcursorImagesDestroy)dlsym(xcursor,
"XcursorImagesDestroy");
131 _XcursorImageCreate = (pfn_XcursorImageCreate)dlsym(xcursor,
"XcursorImageCreate");
132 _XcursorImageLoadCursor = (pfn_XcursorImageLoadCursor)dlsym(xcursor,
"XcursorImageLoadCursor");
133 _XcursorImageDestroy = (pfn_XcursorImageDestroy)dlsym(xcursor,
"XcursorImageDestroy");
135 if (_XcursorGetDefaultSize ==
nullptr || _XcursorXcFileLoadImages ==
nullptr ||
136 _XcursorImagesLoadCursor ==
nullptr || _XcursorImagesDestroy ==
nullptr ||
137 _XcursorImageCreate ==
nullptr || _XcursorImageLoadCursor ==
nullptr ||
138 _XcursorImageDestroy ==
nullptr) {
140 x11display_cat.warning()
141 <<
"libXcursor.so.1 does not provide required functions; cursor changing will not work.\n";
143 }
else if (x_cursor_size.
get_value() >= 0) {
144 _xcursor_size = x_cursor_size;
146 _xcursor_size = _XcursorGetDefaultSize(_display);
150 if (x11display_cat.is_debug()) {
151 x11display_cat.debug()
152 <<
"cannot dlopen libXcursor.so.1; cursor changing will not work.\n";
157 void *xrandr = dlopen(
"libXrandr.so.2", RTLD_NOW | RTLD_LOCAL);
158 if (xrandr !=
nullptr) {
159 pfn_XRRQueryExtension _XRRQueryExtension = (pfn_XRRQueryExtension)dlsym(xrandr,
"XRRQueryExtension");
160 pfn_XRRQueryVersion _XRRQueryVersion = (pfn_XRRQueryVersion)dlsym(xrandr,
"XRRQueryVersion");
162 _XRRSizes = (pfn_XRRSizes)dlsym(xrandr,
"XRRSizes");
163 _XRRRates = (pfn_XRRRates)dlsym(xrandr,
"XRRRates");
164 _XRRGetScreenInfo = (pfn_XRRGetScreenInfo)dlsym(xrandr,
"XRRGetScreenInfo");
165 _XRRConfigCurrentConfiguration = (pfn_XRRConfigCurrentConfiguration)dlsym(xrandr,
"XRRConfigCurrentConfiguration");
166 _XRRSetScreenConfig = (pfn_XRRSetScreenConfig)dlsym(xrandr,
"XRRSetScreenConfig");
168 int event, error, major, minor;
169 if (_XRRQueryExtension ==
nullptr || _XRRSizes ==
nullptr || _XRRRates ==
nullptr ||
170 _XRRGetScreenInfo ==
nullptr || _XRRConfigCurrentConfiguration ==
nullptr ||
171 _XRRSetScreenConfig ==
nullptr || _XRRQueryVersion ==
nullptr) {
172 _have_xrandr =
false;
173 x11display_cat.warning()
174 <<
"libXrandr.so.2 does not provide required functions; resolution setting will not work.\n";
176 else if (_XRRQueryExtension(_display, &event, &error) &&
177 _XRRQueryVersion(_display, &major, &minor)) {
179 if (x11display_cat.is_debug()) {
180 x11display_cat.debug()
181 <<
"Found RandR extension " << major <<
"." << minor <<
"\n";
184 if (major > 1 || (major == 1 && minor >= 2)) {
185 if (major > 1 || (major == 1 && minor >= 3)) {
186 _XRRGetScreenResourcesCurrent = (pfn_XRRGetScreenResources)
187 dlsym(xrandr,
"XRRGetScreenResourcesCurrent");
190 _XRRGetScreenResourcesCurrent = (pfn_XRRGetScreenResources)
191 dlsym(xrandr,
"XRRGetScreenResources");
194 _XRRFreeScreenResources = (pfn_XRRFreeScreenResources)dlsym(xrandr,
"XRRFreeScreenResources");
195 _XRRGetCrtcInfo = (pfn_XRRGetCrtcInfo)dlsym(xrandr,
"XRRGetCrtcInfo");
196 _XRRFreeCrtcInfo = (pfn_XRRFreeCrtcInfo)dlsym(xrandr,
"XRRFreeCrtcInfo");
198 _XRRGetScreenResourcesCurrent =
nullptr;
199 _XRRFreeScreenResources =
nullptr;
200 _XRRGetCrtcInfo =
nullptr;
201 _XRRFreeCrtcInfo =
nullptr;
204 _have_xrandr =
false;
205 if (x11display_cat.is_debug()) {
206 x11display_cat.debug()
207 <<
"RandR extension not supported; resolution setting will not work.\n";
211 _have_xrandr =
false;
212 if (x11display_cat.is_debug()) {
213 x11display_cat.debug()
214 <<
"cannot dlopen libXrandr.so.2; resolution setting will not work.\n";
222 if (
auto res = get_screen_resources()) {
223 if (x11display_cat.is_debug()) {
224 x11display_cat.debug()
225 <<
"Using XRRScreenResources to obtain display modes\n";
227 _display_information->_total_display_modes = res->nmode;
228 _display_information->_display_mode_array =
new DisplayMode[res->nmode];
229 for (
int i = 0; i < res->nmode; ++i) {
232 DisplayMode *dm = _display_information->_display_mode_array + i;
233 dm->width = mode.width;
234 dm->height = mode.height;
235 dm->bits_per_pixel = -1;
236 dm->fullscreen_only =
false;
238 if (mode.hTotal && mode.vTotal) {
239 dm->refresh_rate = (double)mode.dotClock /
240 ((
double)mode.hTotal * (double)mode.vTotal);
242 dm->refresh_rate = 0;
246 if (x11display_cat.is_debug()) {
247 x11display_cat.debug()
248 <<
"Using XRRSizes and XRRRates to obtain display modes\n";
251 int num_sizes, num_rates;
253 xrrs = _XRRSizes(_display, 0, &num_sizes);
254 _display_information->_total_display_modes = 0;
255 for (
int i = 0; i < num_sizes; ++i) {
256 _XRRRates(_display, 0, i, &num_rates);
257 _display_information->_total_display_modes += num_rates;
262 _display_information->_display_mode_array =
new DisplayMode[_display_information->_total_display_modes];
263 for (
int i = 0; i < num_sizes; ++i) {
265 rates = _XRRRates(_display, 0, i, &num_rates);
266 for (
int j = 0; j < num_rates; ++j) {
267 DisplayMode* dm = _display_information->_display_mode_array + counter;
268 dm->width = xrrs[i].width;
269 dm->height = xrrs[i].height;
270 dm->refresh_rate = rates[j];
271 dm->bits_per_pixel = -1;
272 dm->fullscreen_only =
false;
280 _im = XOpenIM(_display,
nullptr,
nullptr,
nullptr);
281 if (_im == (XIM)
nullptr) {
283 XSetLocaleModifiers(
"@im=none");
284 _im = XOpenIM(_display,
nullptr,
nullptr,
nullptr);
285 if (_im == (XIM)
nullptr) {
286 x11display_cat.warning()
287 <<
"Couldn't open input method.\n";
304 const char *dpi = XGetDefault(_display,
"Xft",
"dpi");
305 if (dpi !=
nullptr) {
306 char *endptr =
nullptr;
307 double result =
pstrtod(dpi, &endptr);
308 if (result != 0 && !cnan(result) && endptr[0] ==
'\0') {
310 set_detected_display_zoom(result);
312 if (x11display_cat.is_debug()) {
313 x11display_cat.debug()
314 <<
"Determined display zoom to be " << result
315 <<
" based on specified Xft.dpi " << dpi <<
"\n";
318 x11display_cat.warning()
319 <<
"Unable to determine display zoom because Xft.dpi is invalid: "
322 }
else if (x11display_cat.is_debug()) {
323 x11display_cat.debug()
324 <<
"Unable to determine display zoom because Xft.dpi was not set.\n";
328 _wm_delete_window = XInternAtom(_display,
"WM_DELETE_WINDOW",
false);
329 _net_wm_pid = XInternAtom(_display,
"_NET_WM_PID",
false);
330 _net_wm_window_type = XInternAtom(_display,
"_NET_WM_WINDOW_TYPE",
false);
331 _net_wm_window_type_splash = XInternAtom(_display,
"_NET_WM_WINDOW_TYPE_SPLASH",
false);
332 _net_wm_window_type_fullscreen = XInternAtom(_display,
"_NET_WM_WINDOW_TYPE_FULLSCREEN",
false);
333 _net_wm_state = XInternAtom(_display,
"_NET_WM_STATE",
false);
334 _net_wm_state_fullscreen = XInternAtom(_display,
"_NET_WM_STATE_FULLSCREEN",
false);
335 _net_wm_state_above = XInternAtom(_display,
"_NET_WM_STATE_ABOVE",
false);
336 _net_wm_state_below = XInternAtom(_display,
"_NET_WM_STATE_BELOW",
false);
337 _net_wm_state_add = XInternAtom(_display,
"_NET_WM_STATE_ADD",
false);
338 _net_wm_state_remove = XInternAtom(_display,
"_NET_WM_STATE_REMOVE",
false);
339 _net_wm_bypass_compositor = XInternAtom(_display,
"_NET_WM_BYPASS_COMPOSITOR",
false);
347 release_hidden_cursor();
352 XCloseDisplay(_display);
363 if (_have_xrandr && _XRRGetScreenResourcesCurrent !=
nullptr) {
364 res = _XRRGetScreenResourcesCurrent(_display, _root);
367 return std::unique_ptr<XRRScreenResources, pfn_XRRFreeScreenResources>(res, _XRRFreeScreenResources);
377 if (_have_xrandr && _XRRGetCrtcInfo !=
nullptr) {
378 info = _XRRGetCrtcInfo(_display, res, crtc);
381 return std::unique_ptr<XRRCrtcInfo, pfn_XRRFreeCrtcInfo>(info, _XRRFreeCrtcInfo);
393 int &x,
int &y,
int &width,
int &height) {
396 width = DisplayWidth(_display, _screen);
397 height = DisplayHeight(_display, _screen);
400 for (
int i = 0; i < res->ncrtc; ++i) {
401 RRCrtc crtc = res->crtcs[i];
403 if (point[0] >= info->x && point[0] < info->x + (
int)info->width &&
404 point[1] >= info->y && point[1] < info->y + (
int)info->height) {
408 width = (int)info->width;
409 height = (
int)info->height;
424 GraphicsPipe::PreferredWindowThread
443 void x11GraphicsPipe::
444 make_hidden_cursor() {
445 nassertv(_hidden_cursor == None);
447 unsigned int x_size, y_size;
448 XQueryBestCursor(_display, _root, 1, 1, &x_size, &y_size);
450 Pixmap empty = XCreatePixmap(_display, _root, x_size, y_size, 1);
453 memset(&black, 0,
sizeof(black));
455 _hidden_cursor = XCreatePixmapCursor(_display, empty, empty,
456 &black, &black, x_size, y_size);
457 XFreePixmap(_display, empty);
464 void x11GraphicsPipe::
465 release_hidden_cursor() {
466 if (_hidden_cursor != None) {
467 XFreeCursor(_display, _hidden_cursor);
468 _hidden_cursor = None;
479 void x11GraphicsPipe::
480 install_error_handlers() {
481 if (_error_handlers_installed) {
485 _prev_error_handler = (ErrorHandlerFunc *)XSetErrorHandler(error_handler);
486 _prev_io_error_handler = (IOErrorHandlerFunc *)XSetIOErrorHandler(io_error_handler);
487 _error_handlers_installed =
true;
493 int x11GraphicsPipe::
494 error_handler(X11_Display *display, XErrorEvent *error) {
497 static const int msg_len = 80;
499 XGetErrorText(display, error->error_code, msg, msg_len);
501 if (!_x_error_messages_enabled) {
502 if (x11display_cat.is_debug()) {
503 x11display_cat.debug()
509 x11display_cat.error()
524 int x11GraphicsPipe::
525 io_error_handler(X11_Display *display) {
526 x11display_cat.fatal()
527 <<
"X fatal error on display " << (
void *)display <<
"\n";