25bool x11GraphicsPipe::_error_handlers_installed =
false;
26x11GraphicsPipe::ErrorHandlerFunc *x11GraphicsPipe::_prev_error_handler;
27x11GraphicsPipe::IOErrorHandlerFunc *x11GraphicsPipe::_prev_io_error_handler;
28bool x11GraphicsPipe::_x_error_messages_enabled =
true;
29int x11GraphicsPipe::_x_error_count = 0;
37x11GraphicsPipe(
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; relative mouse mode 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";
230 RRMode current_mode_id = 0;
231 if (res->ncrtc > 0) {
232 if (
auto info = get_crtc_info(res.get(), res->crtcs[0])) {
233 current_mode_id = info->mode;
237 _display_information->_total_display_modes = res->nmode;
238 _display_information->_display_mode_array =
new DisplayMode[res->nmode];
239 for (
int i = 0; i < res->nmode; ++i) {
242 if (mode.id == current_mode_id) {
243 _display_information->_current_display_mode_index = i;
246 DisplayMode *dm = _display_information->_display_mode_array + i;
247 dm->width = mode.width;
248 dm->height = mode.height;
249 dm->bits_per_pixel = -1;
250 dm->fullscreen_only =
false;
252 if (mode.hTotal && mode.vTotal) {
253 dm->refresh_rate = (double)mode.dotClock /
254 ((
double)mode.hTotal * (double)mode.vTotal);
256 dm->refresh_rate = 0;
260 if (x11display_cat.is_debug()) {
261 x11display_cat.debug()
262 <<
"Using XRRSizes and XRRRates to obtain display modes\n";
265 int num_sizes, num_rates;
267 xrrs = _XRRSizes(_display, 0, &num_sizes);
268 _display_information->_total_display_modes = 0;
269 for (
int i = 0; i < num_sizes; ++i) {
270 _XRRRates(_display, 0, i, &num_rates);
271 _display_information->_total_display_modes += num_rates;
276 _display_information->_display_mode_array =
new DisplayMode[_display_information->_total_display_modes];
277 for (
int i = 0; i < num_sizes; ++i) {
279 rates = _XRRRates(_display, 0, i, &num_rates);
280 for (
int j = 0; j < num_rates; ++j) {
281 DisplayMode* dm = _display_information->_display_mode_array + counter;
282 dm->width = xrrs[i].width;
283 dm->height = xrrs[i].height;
284 dm->refresh_rate = rates[j];
285 dm->bits_per_pixel = -1;
286 dm->fullscreen_only =
false;
294 _im = XOpenIM(_display,
nullptr,
nullptr,
nullptr);
295 if (_im == (XIM)
nullptr) {
297 XSetLocaleModifiers(
"@im=none");
298 _im = XOpenIM(_display,
nullptr,
nullptr,
nullptr);
299 if (_im == (XIM)
nullptr) {
300 x11display_cat.warning()
301 <<
"Couldn't open input method.\n";
318 const char *dpi = XGetDefault(_display,
"Xft",
"dpi");
319 if (dpi !=
nullptr) {
320 char *endptr =
nullptr;
321 double result =
pstrtod(dpi, &endptr);
322 if (result != 0 && !cnan(result) && endptr[0] ==
'\0') {
324 set_detected_display_zoom(result);
326 if (x11display_cat.is_debug()) {
327 x11display_cat.debug()
328 <<
"Determined display zoom to be " << result
329 <<
" based on specified Xft.dpi " << dpi <<
"\n";
332 x11display_cat.warning()
333 <<
"Unable to determine display zoom because Xft.dpi is invalid: "
336 }
else if (x11display_cat.is_debug()) {
337 x11display_cat.debug()
338 <<
"Unable to determine display zoom because Xft.dpi was not set.\n";
342 _wm_delete_window = XInternAtom(_display,
"WM_DELETE_WINDOW",
false);
343 _net_wm_name = XInternAtom(_display,
"_NET_WM_NAME",
false);
344 _net_wm_pid = XInternAtom(_display,
"_NET_WM_PID",
false);
345 _net_wm_window_type = XInternAtom(_display,
"_NET_WM_WINDOW_TYPE",
false);
346 _net_wm_window_type_splash = XInternAtom(_display,
"_NET_WM_WINDOW_TYPE_SPLASH",
false);
347 _net_wm_window_type_fullscreen = XInternAtom(_display,
"_NET_WM_WINDOW_TYPE_FULLSCREEN",
false);
348 _net_wm_state = XInternAtom(_display,
"_NET_WM_STATE",
false);
349 _net_wm_state_fullscreen = XInternAtom(_display,
"_NET_WM_STATE_FULLSCREEN",
false);
350 _net_wm_state_above = XInternAtom(_display,
"_NET_WM_STATE_ABOVE",
false);
351 _net_wm_state_below = XInternAtom(_display,
"_NET_WM_STATE_BELOW",
false);
352 _net_wm_state_add = XInternAtom(_display,
"_NET_WM_STATE_ADD",
false);
353 _net_wm_state_remove = XInternAtom(_display,
"_NET_WM_STATE_REMOVE",
false);
354 _net_wm_bypass_compositor = XInternAtom(_display,
"_NET_WM_BYPASS_COMPOSITOR",
false);
362 release_hidden_cursor();
367 XCloseDisplay(_display);
378 if (_have_xrandr && _XRRGetScreenResourcesCurrent !=
nullptr) {
379 res = _XRRGetScreenResourcesCurrent(_display, _root);
382 return std::unique_ptr<XRRScreenResources, pfn_XRRFreeScreenResources>(res, _XRRFreeScreenResources);
392 if (_have_xrandr && _XRRGetCrtcInfo !=
nullptr) {
393 info = _XRRGetCrtcInfo(_display, res, crtc);
396 return std::unique_ptr<XRRCrtcInfo, pfn_XRRFreeCrtcInfo>(info, _XRRFreeCrtcInfo);
408 int &x,
int &y,
int &width,
int &height) {
411 width = DisplayWidth(_display, _screen);
412 height = DisplayHeight(_display, _screen);
415 for (
int i = 0; i < res->ncrtc; ++i) {
416 RRCrtc crtc = res->crtcs[i];
418 if (point[0] >= info->x && point[0] < info->x + (
int)info->width &&
419 point[1] >= info->y && point[1] < info->y + (
int)info->height) {
423 width = (int)info->width;
424 height = (int)info->height;
439GraphicsPipe::PreferredWindowThread
458void x11GraphicsPipe::
459make_hidden_cursor() {
460 nassertv(_hidden_cursor == None);
462 unsigned int x_size, y_size;
463 XQueryBestCursor(_display, _root, 1, 1, &x_size, &y_size);
465 Pixmap empty = XCreatePixmap(_display, _root, x_size, y_size, 1);
468 memset(&black, 0,
sizeof(black));
470 _hidden_cursor = XCreatePixmapCursor(_display, empty, empty,
471 &black, &black, x_size, y_size);
472 XFreePixmap(_display, empty);
479void x11GraphicsPipe::
480release_hidden_cursor() {
481 if (_hidden_cursor != None) {
482 XFreeCursor(_display, _hidden_cursor);
483 _hidden_cursor = None;
494void x11GraphicsPipe::
495install_error_handlers() {
496 if (_error_handlers_installed) {
500 _prev_error_handler = (ErrorHandlerFunc *)XSetErrorHandler(error_handler);
501 _prev_io_error_handler = (IOErrorHandlerFunc *)XSetIOErrorHandler(io_error_handler);
502 _error_handlers_installed =
true;
509error_handler(X11_Display *display, XErrorEvent *error) {
512 static const int msg_len = 80;
514 XGetErrorText(display, error->error_code, msg, msg_len);
516 if (!_x_error_messages_enabled) {
517 if (x11display_cat.is_debug()) {
518 x11display_cat.debug()
524 x11display_cat.error()
540io_error_handler(X11_Display *display) {
541 x11display_cat.fatal()
542 <<
"X fatal error on display " << (
void *)display <<
"\n";
get_value
Returns the variable's value.
get_environment_variable
Returns the definition of the indicated environment variable, or the empty string if the variable is ...
A lightweight reentrant mutex.
TypeHandle is the identifier used to differentiate C++ class types.
std::unique_ptr< XRRScreenResources, pfn_XRRFreeScreenResources > get_screen_resources() const
Returns an XRRScreenResources object, or null if RandR 1.2 is not supported.
std::unique_ptr< XRRCrtcInfo, pfn_XRRFreeCrtcInfo > get_crtc_info(XRRScreenResources *res, RRCrtc crtc) const
Returns an XRRCrtcInfo object, or null if RandR 1.2 is not supported.
RRCrtc find_fullscreen_crtc(const LPoint2i &point, int &x, int &y, int &width, int &height)
Finds a CRTC for going fullscreen to, at the given origin.
virtual PreferredWindowThread get_preferred_window_thread() const
Returns an indication of the thread in which this GraphicsPipe requires its window processing to be p...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
double pstrtod(const char *nptr, char **endptr)
This function re-implements strtod, to avoid the problems that occur when the LC_NUMERIC locale gets ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.