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; 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";
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_pid = XInternAtom(_display,
"_NET_WM_PID",
false);
344 _net_wm_window_type = XInternAtom(_display,
"_NET_WM_WINDOW_TYPE",
false);
345 _net_wm_window_type_splash = XInternAtom(_display,
"_NET_WM_WINDOW_TYPE_SPLASH",
false);
346 _net_wm_window_type_fullscreen = XInternAtom(_display,
"_NET_WM_WINDOW_TYPE_FULLSCREEN",
false);
347 _net_wm_state = XInternAtom(_display,
"_NET_WM_STATE",
false);
348 _net_wm_state_fullscreen = XInternAtom(_display,
"_NET_WM_STATE_FULLSCREEN",
false);
349 _net_wm_state_above = XInternAtom(_display,
"_NET_WM_STATE_ABOVE",
false);
350 _net_wm_state_below = XInternAtom(_display,
"_NET_WM_STATE_BELOW",
false);
351 _net_wm_state_add = XInternAtom(_display,
"_NET_WM_STATE_ADD",
false);
352 _net_wm_state_remove = XInternAtom(_display,
"_NET_WM_STATE_REMOVE",
false);
353 _net_wm_bypass_compositor = XInternAtom(_display,
"_NET_WM_BYPASS_COMPOSITOR",
false);
361 release_hidden_cursor();
366 XCloseDisplay(_display);
377 if (_have_xrandr && _XRRGetScreenResourcesCurrent !=
nullptr) {
378 res = _XRRGetScreenResourcesCurrent(_display, _root);
381 return std::unique_ptr<XRRScreenResources, pfn_XRRFreeScreenResources>(res, _XRRFreeScreenResources);
391 if (_have_xrandr && _XRRGetCrtcInfo !=
nullptr) {
392 info = _XRRGetCrtcInfo(_display, res, crtc);
395 return std::unique_ptr<XRRCrtcInfo, pfn_XRRFreeCrtcInfo>(info, _XRRFreeCrtcInfo);
407 int &x,
int &y,
int &width,
int &height) {
410 width = DisplayWidth(_display, _screen);
411 height = DisplayHeight(_display, _screen);
414 for (
int i = 0; i < res->ncrtc; ++i) {
415 RRCrtc crtc = res->crtcs[i];
417 if (point[0] >= info->x && point[0] < info->x + (
int)info->width &&
418 point[1] >= info->y && point[1] < info->y + (
int)info->height) {
422 width = (int)info->width;
423 height = (int)info->height;
438GraphicsPipe::PreferredWindowThread
457void x11GraphicsPipe::
458make_hidden_cursor() {
459 nassertv(_hidden_cursor == None);
461 unsigned int x_size, y_size;
462 XQueryBestCursor(_display, _root, 1, 1, &x_size, &y_size);
464 Pixmap empty = XCreatePixmap(_display, _root, x_size, y_size, 1);
467 memset(&black, 0,
sizeof(black));
469 _hidden_cursor = XCreatePixmapCursor(_display, empty, empty,
470 &black, &black, x_size, y_size);
471 XFreePixmap(_display, empty);
478void x11GraphicsPipe::
479release_hidden_cursor() {
480 if (_hidden_cursor != None) {
481 XFreeCursor(_display, _hidden_cursor);
482 _hidden_cursor = None;
493void x11GraphicsPipe::
494install_error_handlers() {
495 if (_error_handlers_installed) {
499 _prev_error_handler = (ErrorHandlerFunc *)XSetErrorHandler(error_handler);
500 _prev_io_error_handler = (IOErrorHandlerFunc *)XSetIOErrorHandler(io_error_handler);
501 _error_handlers_installed =
true;
508error_handler(X11_Display *display, XErrorEvent *error) {
511 static const int msg_len = 80;
513 XGetErrorText(display, error->error_code, msg, msg_len);
515 if (!_x_error_messages_enabled) {
516 if (x11display_cat.is_debug()) {
517 x11display_cat.debug()
523 x11display_cat.error()
539io_error_handler(X11_Display *display) {
540 x11display_cat.fatal()
541 <<
"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.