From 28bb737597d527ef4184b5f935da7e316a19c2f4 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 24 Dec 2016 22:21:18 +0100 Subject: [PATCH] Load X11 extensions dynamically; don't expect them to be there at compile time Add x-cursor-size variable for overriding XCursor size. --- makepanda/makepanda.py | 22 +--- panda/src/display/get_x11.h | 13 -- panda/src/x11display/config_x11display.cxx | 5 + panda/src/x11display/config_x11display.h | 1 + panda/src/x11display/x11GraphicsPipe.I | 32 +++++ panda/src/x11display/x11GraphicsPipe.cxx | 140 +++++++++++++++++---- panda/src/x11display/x11GraphicsPipe.h | 56 +++++++++ panda/src/x11display/x11GraphicsWindow.cxx | 140 +++++++++++---------- panda/src/x11display/x11GraphicsWindow.h | 14 +-- 9 files changed, 288 insertions(+), 135 deletions(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index f2746881bd..f84beca1bf 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -88,7 +88,7 @@ PkgListSet(["PYTHON", "DIRECT", # Python support "MFC", "WX", "FLTK", # Used for web plug-in only "ROCKET", "AWESOMIUM", # GUI libraries "CARBON", "COCOA", # Mac OS X toolkits - "X11", "XF86DGA", "XRANDR", "XCURSOR", # Unix platform support + "X11", # Unix platform support "PANDATOOL", "PVIEW", "DEPLOYTOOLS", # Toolchain "SKEL", # Example SKEL project "PANDAFX", # Some distortion special lenses @@ -516,9 +516,6 @@ IncDirectory("ALWAYS", GetOutputDir()+"/include") if (COMPILER == "MSVC"): PkgDisable("X11") - PkgDisable("XRANDR") - PkgDisable("XF86DGA") - PkgDisable("XCURSOR") PkgDisable("GLES") PkgDisable("GLES2") PkgDisable("EGL") @@ -843,9 +840,6 @@ if (COMPILER=="GCC"): SmartPkgEnable("CGGL", "", ("CgGL"), "Cg/cgGL.h") if not RUNTIME: SmartPkgEnable("X11", "x11", "X11", ("X11", "X11/Xlib.h")) - SmartPkgEnable("XRANDR", "xrandr", "Xrandr", "X11/extensions/Xrandr.h") - SmartPkgEnable("XF86DGA", "xxf86dga", "Xxf86dga", "X11/extensions/xf86dga.h") - SmartPkgEnable("XCURSOR", "xcursor", "Xcursor", "X11/Xcursor/Xcursor.h") if GetHost() != "darwin": # Workaround for an issue where pkg-config does not include this path @@ -2194,9 +2188,6 @@ DTOOL_CONFIG=[ ("PHAVE_STDINT_H", '1', '1'), ("HAVE_RTTI", '1', '1'), ("HAVE_X11", 'UNDEF', '1'), - ("HAVE_XRANDR", 'UNDEF', '1'), - ("HAVE_XF86DGA", 'UNDEF', '1'), - ("HAVE_XCURSOR", 'UNDEF', '1'), ("IS_LINUX", 'UNDEF', '1'), ("IS_OSX", 'UNDEF', 'UNDEF'), ("IS_FREEBSD", 'UNDEF', 'UNDEF'), @@ -2301,9 +2292,6 @@ def WriteConfigSettings(): dtool_config["PHAVE_SYS_MALLOC_H"] = '1' dtool_config["HAVE_OPENAL_FRAMEWORK"] = '1' dtool_config["HAVE_X11"] = 'UNDEF' # We might have X11, but we don't need it. - dtool_config["HAVE_XRANDR"] = 'UNDEF' - dtool_config["HAVE_XF86DGA"] = 'UNDEF' - dtool_config["HAVE_XCURSOR"] = 'UNDEF' dtool_config["HAVE_GLX"] = 'UNDEF' dtool_config["IS_LINUX"] = 'UNDEF' dtool_config["HAVE_VIDEO4LINUX"] = 'UNDEF' @@ -4581,7 +4569,7 @@ if (GetTarget() not in ['windows', 'darwin'] and PkgSkip("GL")==0 and PkgSkip("X TargetAdd('libpandagl.dll', input='p3glgsg_glgsg.obj') TargetAdd('libpandagl.dll', input='p3glxdisplay_composite1.obj') TargetAdd('libpandagl.dll', input=COMMON_PANDA_LIBS) - TargetAdd('libpandagl.dll', opts=['MODULE', 'GL', 'NVIDIACG', 'CGGL', 'X11', 'XRANDR', 'XF86DGA', 'XCURSOR']) + TargetAdd('libpandagl.dll', opts=['MODULE', 'GL', 'NVIDIACG', 'CGGL', 'X11']) # # DIRECTORY: panda/src/cocoadisplay/ @@ -4656,7 +4644,7 @@ if (PkgSkip("EGL")==0 and PkgSkip("GLES")==0 and PkgSkip("X11")==0 and not RUNTI TargetAdd('libpandagles.dll', input='p3glesgsg_glesgsg.obj') TargetAdd('libpandagles.dll', input='pandagles_egldisplay_composite1.obj') TargetAdd('libpandagles.dll', input=COMMON_PANDA_LIBS) - TargetAdd('libpandagles.dll', opts=['MODULE', 'GLES', 'EGL', 'X11', 'XRANDR', 'XF86DGA', 'XCURSOR']) + TargetAdd('libpandagles.dll', opts=['MODULE', 'GLES', 'EGL', 'X11']) # # DIRECTORY: panda/src/egldisplay/ @@ -4674,7 +4662,7 @@ if (PkgSkip("EGL")==0 and PkgSkip("GLES2")==0 and PkgSkip("X11")==0 and not RUNT TargetAdd('libpandagles2.dll', input='p3gles2gsg_gles2gsg.obj') TargetAdd('libpandagles2.dll', input='pandagles2_egldisplay_composite1.obj') TargetAdd('libpandagles2.dll', input=COMMON_PANDA_LIBS) - TargetAdd('libpandagles2.dll', opts=['MODULE', 'GLES2', 'EGL', 'X11', 'XRANDR', 'XF86DGA', 'XCURSOR']) + TargetAdd('libpandagles2.dll', opts=['MODULE', 'GLES2', 'EGL', 'X11']) # # DIRECTORY: panda/src/ode/ @@ -4970,7 +4958,7 @@ if (not RUNTIME and (GetTarget() in ('windows', 'darwin') or PkgSkip("X11")==0) TargetAdd('libp3tinydisplay.dll', opts=['WINIMM', 'WINGDI', 'WINKERNEL', 'WINOLDNAMES', 'WINUSER', 'WINMM']) else: TargetAdd('libp3tinydisplay.dll', input='p3x11display_composite1.obj') - TargetAdd('libp3tinydisplay.dll', opts=['X11', 'XRANDR', 'XF86DGA', 'XCURSOR']) + TargetAdd('libp3tinydisplay.dll', opts=['X11']) TargetAdd('libp3tinydisplay.dll', input='p3tinydisplay_composite1.obj') TargetAdd('libp3tinydisplay.dll', input='p3tinydisplay_composite2.obj') TargetAdd('libp3tinydisplay.dll', input='p3tinydisplay_ztriangle_1.obj') diff --git a/panda/src/display/get_x11.h b/panda/src/display/get_x11.h index c188164598..f9112766d7 100644 --- a/panda/src/display/get_x11.h +++ b/panda/src/display/get_x11.h @@ -49,19 +49,6 @@ struct XVisualInfo; #include #include #include - -#ifdef HAVE_XRANDR -#include -#endif // HAVE_XRANDR - -#ifdef HAVE_XCURSOR -#include -#endif - -#ifdef HAVE_XF86DGA -#include -#endif - #include "post_x11_include.h" #endif // CPPPARSER diff --git a/panda/src/x11display/config_x11display.cxx b/panda/src/x11display/config_x11display.cxx index 13b225e418..c2b89c42b2 100644 --- a/panda/src/x11display/config_x11display.cxx +++ b/panda/src/x11display/config_x11display.cxx @@ -60,6 +60,11 @@ ConfigVariableInt x_wheel_right_button "mouse button number does the system report when one scrolls " "to the right?")); +ConfigVariableInt x_cursor_size +("x-cursor-size", -1, + PRC_DESC("This sets the cursor size when using XCursor to change the mouse " + "cursor. The default is to use the default size for the display.")); + ConfigVariableString x_wm_class_name ("x-wm-class-name", "", PRC_DESC("Specify the value to use for the res_name field of the window's " diff --git a/panda/src/x11display/config_x11display.h b/panda/src/x11display/config_x11display.h index 88fb2f2133..bc40aad627 100644 --- a/panda/src/x11display/config_x11display.h +++ b/panda/src/x11display/config_x11display.h @@ -32,6 +32,7 @@ extern ConfigVariableInt x_wheel_down_button; extern ConfigVariableInt x_wheel_left_button; extern ConfigVariableInt x_wheel_right_button; +extern ConfigVariableInt x_cursor_size; extern ConfigVariableString x_wm_class_name; extern ConfigVariableString x_wm_class; diff --git a/panda/src/x11display/x11GraphicsPipe.I b/panda/src/x11display/x11GraphicsPipe.I index cb452bef23..fb56700299 100644 --- a/panda/src/x11display/x11GraphicsPipe.I +++ b/panda/src/x11display/x11GraphicsPipe.I @@ -57,6 +57,38 @@ get_hidden_cursor() { return _hidden_cursor; } +/** + * Returns true if relative mouse mode is supported on this display. + */ +INLINE bool x11GraphicsPipe:: +supports_relative_mouse() const { + return (_XF86DGADirectVideo != NULL); +} + +/** + * Enables relative mouse mode for this display. Returns false if unsupported. + */ +INLINE bool x11GraphicsPipe:: +enable_relative_mouse() { + if (_XF86DGADirectVideo != NULL) { + x11display_cat.info() << "Enabling relative mouse using XF86DGA extension\n"; + _XF86DGADirectVideo(_display, _screen, XF86DGADirectMouse); + return true; + } + return false; +} + +/** + * Disables relative mouse mode for this display. + */ +INLINE void x11GraphicsPipe:: +disable_relative_mouse() { + if (_XF86DGADirectVideo != NULL) { + x11display_cat.info() << "Disabling relative mouse using XF86DGA extension\n"; + _XF86DGADirectVideo(_display, _screen, 0); + } +} + /** * Globally disables the printing of error messages that are raised by the X11 * system, for instance in order to test whether a particular X11 operation diff --git a/panda/src/x11display/x11GraphicsPipe.cxx b/panda/src/x11display/x11GraphicsPipe.cxx index 9eee9f6d7a..a0d4e8ffae 100644 --- a/panda/src/x11display/x11GraphicsPipe.cxx +++ b/panda/src/x11display/x11GraphicsPipe.cxx @@ -17,6 +17,8 @@ #include "frameBufferProperties.h" #include "displayInformation.h" +#include + TypeHandle x11GraphicsPipe::_type_handle; bool x11GraphicsPipe::_error_handlers_installed = false; @@ -31,7 +33,11 @@ LightReMutex x11GraphicsPipe::_x_mutex; * */ x11GraphicsPipe:: -x11GraphicsPipe(const string &display) { +x11GraphicsPipe(const string &display) : + _have_xrandr(false), + _xcursor_size(-1), + _XF86DGADirectVideo(NULL) { + string display_spec = display; if (display_spec.empty()) { display_spec = display_cfg; @@ -86,34 +92,116 @@ x11GraphicsPipe(const string &display) { _display_height = DisplayHeight(_display, _screen); _is_valid = true; -#ifdef HAVE_XRANDR - // Use Xrandr to fill in the supported resolution list. - int num_sizes, num_rates; - XRRScreenSize *xrrs; - xrrs = XRRSizes(_display, 0, &num_sizes); - _display_information->_total_display_modes = 0; - for (int i = 0; i < num_sizes; ++i) { - XRRRates(_display, 0, i, &num_rates); - _display_information->_total_display_modes += num_rates; - } + // Dynamically load the xf86dga extension. + void *xf86dga = dlopen("libXxf86dga.so.1", RTLD_NOW | RTLD_LOCAL); + if (xf86dga != NULL) { + pfn_XF86DGAQueryVersion _XF86DGAQueryVersion = (pfn_XF86DGAQueryVersion)dlsym(xf86dga, "XF86DGAQueryVersion"); + _XF86DGADirectVideo = (pfn_XF86DGADirectVideo)dlsym(xf86dga, "XF86DGADirectVideo"); - short *rates; - short counter = 0; - _display_information->_display_mode_array = new DisplayMode[_display_information->_total_display_modes]; - for (int i = 0; i < num_sizes; ++i) { - int num_rates; - rates = XRRRates(_display, 0, i, &num_rates); - for (int j = 0; j < num_rates; ++j) { - DisplayMode* dm = _display_information->_display_mode_array + counter; - dm->width = xrrs[i].width; - dm->height = xrrs[i].height; - dm->refresh_rate = rates[j]; - dm->bits_per_pixel = -1; - dm->fullscreen_only = false; - ++counter; + int major_ver, minor_ver; + if (_XF86DGAQueryVersion == NULL || _XF86DGADirectVideo == NULL) { + x11display_cat.warning() + << "libXxf86dga.so.1 does not provide required functions; relative mouse mode will not work.\n"; + + } else if (!_XF86DGAQueryVersion(_display, &major_ver, &minor_ver)) { + _XF86DGADirectVideo = NULL; + } + } else { + _XF86DGADirectVideo = NULL; + if (x11display_cat.is_debug()) { + x11display_cat.debug() + << "cannot dlopen libXxf86dga.so.1; cursor changing will not work.\n"; + } + } + + // Dynamically load the XCursor extension. + void *xcursor = dlopen("libXcursor.so.1", RTLD_NOW | RTLD_LOCAL); + if (xcursor != NULL) { + pfn_XcursorGetDefaultSize _XcursorGetDefaultSize = (pfn_XcursorGetDefaultSize)dlsym(xcursor, "XcursorGetDefaultSize"); + _XcursorXcFileLoadImages = (pfn_XcursorXcFileLoadImages)dlsym(xcursor, "XcursorXcFileLoadImages"); + _XcursorImagesLoadCursor = (pfn_XcursorImagesLoadCursor)dlsym(xcursor, "XcursorImagesLoadCursor"); + _XcursorImagesDestroy = (pfn_XcursorImagesDestroy)dlsym(xcursor, "XcursorImagesDestroy"); + _XcursorImageCreate = (pfn_XcursorImageCreate)dlsym(xcursor, "XcursorImageCreate"); + _XcursorImageLoadCursor = (pfn_XcursorImageLoadCursor)dlsym(xcursor, "XcursorImageLoadCursor"); + _XcursorImageDestroy = (pfn_XcursorImageDestroy)dlsym(xcursor, "XcursorImageDestroy"); + + if (_XcursorGetDefaultSize == NULL || _XcursorXcFileLoadImages == NULL || + _XcursorImagesLoadCursor == NULL || _XcursorImagesDestroy == NULL || + _XcursorImageCreate == NULL || _XcursorImageLoadCursor == NULL || + _XcursorImageDestroy == NULL) { + _xcursor_size = -1; + x11display_cat.warning() + << "libXcursor.so.1 does not provide required functions; cursor changing will not work.\n"; + + } else if (x_cursor_size.get_value() >= 0) { + _xcursor_size = x_cursor_size; + } else { + _xcursor_size = _XcursorGetDefaultSize(_display); + } + } else { + _xcursor_size = -1; + if (x11display_cat.is_debug()) { + x11display_cat.debug() + << "cannot dlopen libXcursor.so.1; cursor changing will not work.\n"; + } + } + + // Dynamically load the XRandr extension. + void *xrandr = dlopen("libXrandr.so.2", RTLD_NOW | RTLD_LOCAL); + if (xrandr != NULL) { + pfn_XRRQueryExtension _XRRQueryExtension = (pfn_XRRQueryExtension)dlsym(xrandr, "XRRQueryExtension"); + _XRRSizes = (pfn_XRRSizes)dlsym(xrandr, "XRRSizes"); + _XRRRates = (pfn_XRRRates)dlsym(xrandr, "XRRRates"); + _XRRGetScreenInfo = (pfn_XRRGetScreenInfo)dlsym(xrandr, "XRRGetScreenInfo"); + _XRRConfigCurrentConfiguration = (pfn_XRRConfigCurrentConfiguration)dlsym(xrandr, "XRRConfigCurrentConfiguration"); + _XRRSetScreenConfig = (pfn_XRRSetScreenConfig)dlsym(xrandr, "XRRSetScreenConfig"); + + if (_XRRQueryExtension == NULL || _XRRSizes == NULL || _XRRRates == NULL || + _XRRGetScreenInfo == NULL || _XRRConfigCurrentConfiguration == NULL || + _XRRSetScreenConfig == NULL) { + _have_xrandr = false; + x11display_cat.warning() + << "libXrandr.so.2 does not provide required functions; resolution setting will not work.\n"; + } else { + int event, error; + _have_xrandr = _XRRQueryExtension(_display, &event, &error); + } + } else { + _have_xrandr = false; + if (x11display_cat.is_debug()) { + x11display_cat.debug() + << "cannot dlopen libXrandr.so.2; resolution setting will not work.\n"; + } + } + + // Use Xrandr to fill in the supported resolution list. + if (_have_xrandr) { + int num_sizes, num_rates; + XRRScreenSize *xrrs; + xrrs = _XRRSizes(_display, 0, &num_sizes); + _display_information->_total_display_modes = 0; + for (int i = 0; i < num_sizes; ++i) { + _XRRRates(_display, 0, i, &num_rates); + _display_information->_total_display_modes += num_rates; + } + + short *rates; + short counter = 0; + _display_information->_display_mode_array = new DisplayMode[_display_information->_total_display_modes]; + for (int i = 0; i < num_sizes; ++i) { + int num_rates; + rates = _XRRRates(_display, 0, i, &num_rates); + for (int j = 0; j < num_rates; ++j) { + DisplayMode* dm = _display_information->_display_mode_array + counter; + dm->width = xrrs[i].width; + dm->height = xrrs[i].height; + dm->refresh_rate = rates[j]; + dm->bits_per_pixel = -1; + dm->fullscreen_only = false; + ++counter; + } } } -#endif // Connect to an input method for supporting international text entry. _im = XOpenIM(_display, NULL, NULL, NULL); diff --git a/panda/src/x11display/x11GraphicsPipe.h b/panda/src/x11display/x11GraphicsPipe.h index ab06a9b692..4da09d3144 100644 --- a/panda/src/x11display/x11GraphicsPipe.h +++ b/panda/src/x11display/x11GraphicsPipe.h @@ -21,6 +21,22 @@ #include "lightReMutex.h" #include "windowHandle.h" #include "get_x11.h" +#include "config_x11display.h" + +// Excerpt the few definitions we need for the extensions. +#define XF86DGADirectMouse 0x0004 + +typedef struct _XcursorFile XcursorFile; +typedef struct _XcursorImage XcursorImage; +typedef struct _XcursorImages XcursorImages; + +typedef unsigned short Rotation; +typedef unsigned short SizeID; +typedef struct _XRRScreenConfiguration XRRScreenConfiguration; +typedef struct { + int width, height; + int mwidth, mheight; +} XRRScreenSize; class FrameBufferProperties; @@ -40,6 +56,10 @@ public: INLINE X11_Cursor get_hidden_cursor(); + INLINE bool supports_relative_mouse() const; + INLINE bool enable_relative_mouse(); + INLINE void disable_relative_mouse(); + static INLINE int disable_x_error_messages(); static INLINE int enable_x_error_messages(); static INLINE int get_x_error_count(); @@ -61,6 +81,38 @@ public: Atom _net_wm_state_add; Atom _net_wm_state_remove; + // Extension functions. + typedef int (*pfn_XcursorGetDefaultSize)(X11_Display *); + typedef XcursorImages *(*pfn_XcursorXcFileLoadImages)(XcursorFile *, int); + typedef X11_Cursor (*pfn_XcursorImagesLoadCursor)(X11_Display *, const XcursorImages *); + typedef void (*pfn_XcursorImagesDestroy)(XcursorImages *); + typedef XcursorImage *(*pfn_XcursorImageCreate)(int, int); + typedef X11_Cursor (*pfn_XcursorImageLoadCursor)(X11_Display *, const XcursorImage *); + typedef void (*pfn_XcursorImageDestroy)(XcursorImage *); + + int _xcursor_size; + pfn_XcursorXcFileLoadImages _XcursorXcFileLoadImages; + pfn_XcursorImagesLoadCursor _XcursorImagesLoadCursor; + pfn_XcursorImagesDestroy _XcursorImagesDestroy; + pfn_XcursorImageCreate _XcursorImageCreate; + pfn_XcursorImageLoadCursor _XcursorImageLoadCursor; + pfn_XcursorImageDestroy _XcursorImageDestroy; + + typedef Bool (*pfn_XRRQueryExtension)(X11_Display *, int*, int*); + typedef XRRScreenSize *(*pfn_XRRSizes)(X11_Display*, int, int*); + typedef short *(*pfn_XRRRates)(X11_Display*, int, int, int*); + typedef XRRScreenConfiguration *(*pfn_XRRGetScreenInfo)(X11_Display*, X11_Window); + typedef SizeID (*pfn_XRRConfigCurrentConfiguration)(XRRScreenConfiguration*, Rotation*); + typedef Status (*pfn_XRRSetScreenConfig)(X11_Display*, XRRScreenConfiguration *, + Drawable, int, Rotation, Time); + + bool _have_xrandr; + pfn_XRRSizes _XRRSizes; + pfn_XRRRates _XRRRates; + pfn_XRRGetScreenInfo _XRRGetScreenInfo; + pfn_XRRConfigCurrentConfiguration _XRRConfigCurrentConfiguration; + pfn_XRRSetScreenConfig _XRRSetScreenConfig; + protected: X11_Display *_display; int _screen; @@ -69,6 +121,10 @@ protected: X11_Cursor _hidden_cursor; + typedef Bool (*pfn_XF86DGAQueryVersion)(X11_Display *, int*, int*); + typedef Status (*pfn_XF86DGADirectVideo)(X11_Display *, int, int); + pfn_XF86DGADirectVideo _XF86DGADirectVideo; + private: void make_hidden_cursor(); void release_hidden_cursor(); diff --git a/panda/src/x11display/x11GraphicsWindow.cxx b/panda/src/x11display/x11GraphicsWindow.cxx index 732932a1e4..3ea2cd3fb0 100644 --- a/panda/src/x11display/x11GraphicsWindow.cxx +++ b/panda/src/x11display/x11GraphicsWindow.cxx @@ -38,7 +38,24 @@ #include #endif -#ifdef HAVE_XCURSOR +struct _XcursorFile { + void *closure; + int (*read)(XcursorFile *, unsigned char *, int); + int (*write)(XcursorFile *, unsigned char *, int); + int (*seek)(XcursorFile *, long, int); +}; + +typedef struct _XcursorImage { + unsigned int version; + unsigned int size; + unsigned int width; + unsigned int height; + unsigned int xhot; + unsigned int yhot; + unsigned int delay; + unsigned int *pixels; +} XcursorImage; + static int xcursor_read(XcursorFile *file, unsigned char *buf, int len) { istream* str = (istream*) file->closure; str->read((char*) buf, len); @@ -66,7 +83,6 @@ static int xcursor_seek(XcursorFile *file, long offset, int whence) { return str->tellg(); } -#endif TypeHandle x11GraphicsWindow::_type_handle; @@ -92,14 +108,14 @@ x11GraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe, _xwindow = (X11_Window)NULL; _ic = (XIC)NULL; _visual_info = NULL; - -#ifdef HAVE_XRANDR _orig_size_id = -1; - int event, error; - _have_xrandr = XRRQueryExtension(_display, &event, &error); -#else - _have_xrandr = false; -#endif + + if (x11_pipe->_have_xrandr) { + // We may still need these functions after the pipe is already destroyed, + // so we copy them into the x11GraphicsWindow. + _XRRGetScreenInfo = x11_pipe->_XRRGetScreenInfo; + _XRRSetScreenConfig = x11_pipe->_XRRSetScreenConfig; + } _awaiting_configure = false; _dga_mouse_enabled = false; @@ -474,10 +490,9 @@ set_properties_now(WindowProperties &properties) { if (is_fullscreen != want_fullscreen || (is_fullscreen && properties.has_size())) { if (want_fullscreen) { - if (_have_xrandr) { -#ifdef HAVE_XRANDR - XRRScreenConfiguration* conf = XRRGetScreenInfo(_display, x11_pipe->get_root()); - SizeID old_size_id = XRRConfigCurrentConfiguration(conf, &_orig_rotation); + if (x11_pipe->_have_xrandr) { + XRRScreenConfiguration* conf = _XRRGetScreenInfo(_display, x11_pipe->get_root()); + SizeID old_size_id = x11_pipe->_XRRConfigCurrentConfiguration(conf, &_orig_rotation); SizeID new_size_id = (SizeID) -1; int num_sizes = 0, reqsizex, reqsizey; if (properties.has_size()) { @@ -488,7 +503,7 @@ set_properties_now(WindowProperties &properties) { reqsizey = _properties.get_y_size(); } XRRScreenSize *xrrs; - xrrs = XRRSizes(_display, 0, &num_sizes); + xrrs = x11_pipe->_XRRSizes(_display, 0, &num_sizes); for (int i = 0; i < num_sizes; ++i) { if (xrrs[i].width == reqsizex && xrrs[i].height == reqsizey) { @@ -502,14 +517,13 @@ set_properties_now(WindowProperties &properties) { } else { if (new_size_id != old_size_id) { - XRRSetScreenConfig(_display, conf, x11_pipe->get_root(), new_size_id, _orig_rotation, CurrentTime); + _XRRSetScreenConfig(_display, conf, x11_pipe->get_root(), new_size_id, _orig_rotation, CurrentTime); if (_orig_size_id == (SizeID) -1) { // Remember the original resolution so we can switch back to it. _orig_size_id = old_size_id; } } } -#endif } else { // If we don't have Xrandr support, we fake the fullscreen support by // setting the window size to the desktop size. @@ -517,15 +531,13 @@ set_properties_now(WindowProperties &properties) { x11_pipe->get_display_height()); } } else { -#ifdef HAVE_XRANDR // Change the resolution back to what it was. Don't remove the SizeID // typecast! - if (_have_xrandr && _orig_size_id != (SizeID) -1) { - XRRScreenConfiguration* conf = XRRGetScreenInfo(_display, x11_pipe->get_root()); - XRRSetScreenConfig(_display, conf, x11_pipe->get_root(), _orig_size_id, _orig_rotation, CurrentTime); + if (_orig_size_id != (SizeID) -1) { + XRRScreenConfiguration *conf = _XRRGetScreenInfo(_display, x11_pipe->get_root()); + _XRRSetScreenConfig(_display, conf, x11_pipe->get_root(), _orig_size_id, _orig_rotation, CurrentTime); _orig_size_id = (SizeID) -1; } -#endif // Set the origin back to what it was if (!properties.has_origin() && _properties.has_origin()) { properties.set_origin(_properties.get_x_origin(), _properties.get_y_origin()); @@ -686,23 +698,17 @@ set_properties_now(WindowProperties &properties) { switch (properties.get_mouse_mode()) { case WindowProperties::M_absolute: XUngrabPointer(_display, CurrentTime); -#ifdef HAVE_XF86DGA if (_dga_mouse_enabled) { - x11display_cat.info() << "Disabling relative mouse using XF86DGA extension\n"; - XF86DGADirectVideo(_display, _screen, 0); + x11_pipe->disable_relative_mouse(); _dga_mouse_enabled = false; } -#endif _properties.set_mouse_mode(WindowProperties::M_absolute); properties.clear_mouse_mode(); break; case WindowProperties::M_relative: -#ifdef HAVE_XF86DGA if (!_dga_mouse_enabled) { - int major_ver, minor_ver; - if (XF86DGAQueryVersion(_display, &major_ver, &minor_ver)) { - + if (x11_pipe->supports_relative_mouse()) { X11_Cursor cursor = None; if (_properties.get_cursor_hidden()) { x11GraphicsPipe *x11_pipe; @@ -714,8 +720,7 @@ set_properties_now(WindowProperties &properties) { GrabModeAsync, _xwindow, cursor, CurrentTime) != GrabSuccess) { x11display_cat.error() << "Failed to grab pointer!\n"; } else { - x11display_cat.info() << "Enabling relative mouse using XF86DGA extension\n"; - XF86DGADirectVideo(_display, _screen, XF86DGADirectMouse); + x11_pipe->enable_relative_mouse(); _properties.set_mouse_mode(WindowProperties::M_relative); properties.clear_mouse_mode(); @@ -730,25 +735,24 @@ set_properties_now(WindowProperties &properties) { _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y); } } else { - x11display_cat.info() << "XF86DGA extension not available\n"; + x11display_cat.info() + << "XF86DGA extension not available, cannot enable relative mouse mode\n"; _dga_mouse_enabled = false; } } -#endif break; case WindowProperties::M_confined: { -#ifdef HAVE_XF86DGA + x11GraphicsPipe *x11_pipe; + DCAST_INTO_V(x11_pipe, _pipe); + if (_dga_mouse_enabled) { - XF86DGADirectVideo(_display, _screen, 0); + x11_pipe->disable_relative_mouse(); _dga_mouse_enabled = false; } -#endif X11_Cursor cursor = None; if (_properties.get_cursor_hidden()) { - x11GraphicsPipe *x11_pipe; - DCAST_INTO_V(x11_pipe, _pipe); cursor = x11_pipe->get_hidden_cursor(); } @@ -813,10 +817,9 @@ close_window() { XFlush(_display); } -#ifdef HAVE_XRANDR // Change the resolution back to what it was. Don't remove the SizeID // typecast! - if (_have_xrandr && _orig_size_id != (SizeID) -1) { + if (_orig_size_id != (SizeID) -1) { X11_Window root; if (_pipe != NULL) { x11GraphicsPipe *x11_pipe; @@ -827,11 +830,10 @@ close_window() { // closed. Oh well, let's get the root window by ourselves. root = RootWindow(_display, _screen); } - XRRScreenConfiguration* conf = XRRGetScreenInfo(_display, root); - XRRSetScreenConfig(_display, conf, root, _orig_size_id, _orig_rotation, CurrentTime); + XRRScreenConfiguration *conf = _XRRGetScreenInfo(_display, root); + _XRRSetScreenConfig(_display, conf, root, _orig_size_id, _orig_rotation, CurrentTime); _orig_size_id = -1; } -#endif GraphicsWindow::close_window(); } @@ -859,15 +861,14 @@ open_window() { _properties.set_size(100, 100); } -#ifdef HAVE_XRANDR - if (_properties.get_fullscreen() && _have_xrandr) { - XRRScreenConfiguration* conf = XRRGetScreenInfo(_display, x11_pipe->get_root()); + if (_properties.get_fullscreen() && x11_pipe->_have_xrandr) { + XRRScreenConfiguration* conf = _XRRGetScreenInfo(_display, x11_pipe->get_root()); if (_orig_size_id == (SizeID) -1) { - _orig_size_id = XRRConfigCurrentConfiguration(conf, &_orig_rotation); + _orig_size_id = x11_pipe->_XRRConfigCurrentConfiguration(conf, &_orig_rotation); } int num_sizes, new_size_id = -1; XRRScreenSize *xrrs; - xrrs = XRRSizes(_display, 0, &num_sizes); + xrrs = x11_pipe->_XRRSizes(_display, 0, &num_sizes); for (int i = 0; i < num_sizes; ++i) { if (xrrs[i].width == _properties.get_x_size() && xrrs[i].height == _properties.get_y_size()) { @@ -882,12 +883,11 @@ open_window() { return false; } if (new_size_id != _orig_size_id) { - XRRSetScreenConfig(_display, conf, x11_pipe->get_root(), new_size_id, _orig_rotation, CurrentTime); + _XRRSetScreenConfig(_display, conf, x11_pipe->get_root(), new_size_id, _orig_rotation, CurrentTime); } else { _orig_size_id = -1; } } -#endif X11_Window parent_window = x11_pipe->get_root(); WindowHandle *window_handle = _properties.get_parent_window(); @@ -2081,11 +2081,15 @@ check_event(X11_Display *display, XEvent *event, char *arg) { */ X11_Cursor x11GraphicsWindow:: get_cursor(const Filename &filename) { -#ifndef HAVE_XCURSOR - x11display_cat.info() - << "XCursor support not enabled in build; cannot change mouse cursor.\n"; - return None; -#else // HAVE_XCURSOR + x11GraphicsPipe *x11_pipe; + DCAST_INTO_R(x11_pipe, _pipe, None); + + if (x11_pipe->_xcursor_size == -1) { + x11display_cat.info() + << "libXcursor.so.1 not available; cannot change mouse cursor.\n"; + return None; + } + // First, look for the unresolved filename in our index. pmap::iterator fi = _cursor_filenames.find(filename); if (fi != _cursor_filenames.end()) { @@ -2135,10 +2139,10 @@ get_cursor(const Filename &filename) { xcfile.write = &xcursor_write; xcfile.seek = &xcursor_seek; - XcursorImages *images = XcursorXcFileLoadImages(&xcfile, XcursorGetDefaultSize(_display)); + XcursorImages *images = x11_pipe->_XcursorXcFileLoadImages(&xcfile, x11_pipe->_xcursor_size); if (images != NULL) { - h = XcursorImagesLoadCursor(_display, images); - XcursorImagesDestroy(images); + h = x11_pipe->_XcursorImagesLoadCursor(_display, images); + x11_pipe->_XcursorImagesDestroy(images); } } else if (memcmp(magic, "\0\0\1\0", 4) == 0 @@ -2159,18 +2163,19 @@ get_cursor(const Filename &filename) { _cursor_filenames[resolved] = h; return h; -#endif // HAVE_XCURSOR } -#ifdef HAVE_XCURSOR /** * Reads a Windows .ico or .cur file from the indicated stream and returns it * as an X11 Cursor. If the file cannot be loaded, returns None. */ X11_Cursor x11GraphicsWindow:: read_ico(istream &ico) { - // Local structs, this is just POD, make input easier - typedef struct { + x11GraphicsPipe *x11_pipe; + DCAST_INTO_R(x11_pipe, _pipe, None); + + // Local structs, this is just POD, make input easier + typedef struct { uint16_t reserved, type, count; } IcoHeader; @@ -2204,7 +2209,7 @@ read_ico(istream &ico) { XcursorImage *image = NULL; X11_Cursor ret = None; - int def_size = XcursorGetDefaultSize(_display); + int def_size = x11_pipe->_xcursor_size; // Get our header, note that ICO = type 1 and CUR = type 2. ico.read(reinterpret_cast(&header), sizeof(IcoHeader)); @@ -2240,7 +2245,7 @@ read_ico(istream &ico) { } img.set_maxval(255); - image = XcursorImageCreate(img.get_x_size(), img.get_y_size()); + image = x11_pipe->_XcursorImageCreate(img.get_x_size(), img.get_y_size()); xel *ptr = img.get_array(); xelval *alpha = img.get_alpha_array(); @@ -2285,7 +2290,7 @@ read_ico(istream &ico) { ico.read(andBmp, andBmpSize); if (!ico.good()) goto cleanup; - image = XcursorImageCreate(infoHeader.width, infoHeader.height / 2); + image = x11_pipe->_XcursorImageCreate(infoHeader.width, infoHeader.height / 2); // Support all the formats that GIMP supports. switch (bitsPerPixel) { @@ -2370,10 +2375,10 @@ read_ico(istream &ico) { image->yhot = 0; } - ret = XcursorImageLoadCursor(_display, image); + ret = x11_pipe->_XcursorImageLoadCursor(_display, image); cleanup: - XcursorImageDestroy(image); + x11_pipe->_XcursorImageDestroy(image); delete[] entries; delete[] palette; delete[] xorBmp; @@ -2381,4 +2386,3 @@ cleanup: return ret; } -#endif // HAVE_XCURSOR diff --git a/panda/src/x11display/x11GraphicsWindow.h b/panda/src/x11display/x11GraphicsWindow.h index fe160284f8..5b55bf3619 100644 --- a/panda/src/x11display/x11GraphicsWindow.h +++ b/panda/src/x11display/x11GraphicsWindow.h @@ -20,11 +20,6 @@ #include "graphicsWindow.h" #include "buttonHandle.h" -#ifdef HAVE_XRANDR -typedef unsigned short Rotation; -typedef unsigned short SizeID; -#endif - /** * Interfaces to the X11 window system. */ @@ -76,9 +71,7 @@ protected: private: X11_Cursor get_cursor(const Filename &filename); -#ifdef HAVE_XCURSOR X11_Cursor read_ico(istream &ico); -#endif protected: X11_Display *_display; @@ -87,12 +80,8 @@ protected: Colormap _colormap; XIC _ic; XVisualInfo *_visual_info; - - bool _have_xrandr; -#ifdef HAVE_XRANDR Rotation _orig_rotation; SizeID _orig_size_id; -#endif LVecBase2i _fixed_size; @@ -109,6 +98,9 @@ protected: }; pvector _mouse_device_info; + x11GraphicsPipe::pfn_XRRGetScreenInfo _XRRGetScreenInfo; + x11GraphicsPipe::pfn_XRRSetScreenConfig _XRRSetScreenConfig; + public: static TypeHandle get_class_type() { return _type_handle;