Jelajahi Sumber

Load X11 extensions dynamically; don't expect them to be there at compile time
Add x-cursor-size variable for overriding XCursor size.

rdb 9 tahun lalu
induk
melakukan
28bb737597

+ 5 - 17
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')

+ 0 - 13
panda/src/display/get_x11.h

@@ -49,19 +49,6 @@ struct XVisualInfo;
 #include <X11/Xutil.h>
 #include <X11/keysym.h>
 #include <X11/Xatom.h>
-
-#ifdef HAVE_XRANDR
-#include <X11/extensions/Xrandr.h>
-#endif  // HAVE_XRANDR
-
-#ifdef HAVE_XCURSOR
-#include <X11/Xcursor/Xcursor.h>
-#endif
-
-#ifdef HAVE_XF86DGA
-#include <X11/extensions/Xxf86dga.h>
-#endif
-
 #include "post_x11_include.h"
 
 #endif  // CPPPARSER

+ 5 - 0
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 "

+ 1 - 0
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;
 

+ 32 - 0
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

+ 113 - 25
panda/src/x11display/x11GraphicsPipe.cxx

@@ -17,6 +17,8 @@
 #include "frameBufferProperties.h"
 #include "displayInformation.h"
 
+#include <dlfcn.h>
+
 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");
+
+    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";
+    }
   }
 
-  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;
+  // 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);

+ 56 - 0
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();

+ 72 - 68
panda/src/x11display/x11GraphicsWindow.cxx

@@ -38,7 +38,24 @@
 #include <linux/input.h>
 #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<Filename, X11_Cursor>::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<char *>(&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

+ 3 - 11
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<MouseDeviceInfo> _mouse_device_info;
 
+  x11GraphicsPipe::pfn_XRRGetScreenInfo _XRRGetScreenInfo;
+  x11GraphicsPipe::pfn_XRRSetScreenConfig _XRRSetScreenConfig;
+
 public:
   static TypeHandle get_class_type() {
     return _type_handle;