diff --git a/dtool/Config.pp b/dtool/Config.pp index 8c351e1e69..841d91578c 100644 --- a/dtool/Config.pp +++ b/dtool/Config.pp @@ -709,13 +709,20 @@ #define XF86DGA_LIBS Xxf86dga #defer HAVE_XF86DGA $[libtest $[XF86DGA_LPATH],$[XF86DGA_LIBS]] -// This defines if we have XF86DGA installed. This +// This defines if we have XRANDR installed. This // enables resolution switching in x11display. #define XRANDR_IPATH /usr/include/X11/extensions #define XRANDR_LPATH /usr/lib #define XRANDR_LIBS Xrandr #defer HAVE_XRANDR $[libtest $[XRANDR_LPATH],$[XRANDR_LIBS]] +// This defines if we have XCURSOR installed. This +// enables resolution switching in x11display. +#define XCURSOR_IPATH /usr/include/X11/extensions +#define XCURSOR_LPATH /usr/lib +#define XCURSOR_LIBS Xcursor +#defer HAVE_XCURSOR $[libtest $[XCURSOR_LPATH],$[XCURSOR_LIBS]] + // How about GLX? #define GLX_IPATH #define GLX_LPATH diff --git a/dtool/LocalSetup.pp b/dtool/LocalSetup.pp index 90e068488a..3c8db69c1f 100644 --- a/dtool/LocalSetup.pp +++ b/dtool/LocalSetup.pp @@ -413,6 +413,9 @@ $[cdefine HAVE_XF86DGA] /* Define if we have the XRandR extension. */ $[cdefine HAVE_XRANDR] +/* Define if we have the XCursor extension. */ +$[cdefine HAVE_XCURSOR] + /* Define if we want to compile the threading code. */ $[cdefine HAVE_THREADS] diff --git a/dtool/pptempl/Global.pp b/dtool/pptempl/Global.pp index 84626682fb..2276a7b640 100644 --- a/dtool/pptempl/Global.pp +++ b/dtool/pptempl/Global.pp @@ -171,6 +171,13 @@ #define xrandr_libs $[XRANDR_LIBS] #endif +#if $[HAVE_XCURSOR] + #define xcursor_ipath $[wildcard $[XCURSOR_IPATH]] + #define xcursor_lpath $[wildcard $[XCURSOR_LPATH]] + #define xcursor_cflags $[XCURSOR_CFLAGS] + #define xcursor_libs $[XCURSOR_LIBS] +#endif + #if $[HAVE_MESA] #define mesa_ipath $[wildcard $[MESA_IPATH]] #define mesa_lpath $[wildcard $[MESA_LPATH]] diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 0bc789762f..c23ecd6b26 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -69,7 +69,7 @@ PkgListSet(["PYTHON", "DIRECT", # Python support "ARTOOLKIT", "OPENCV", "DIRECTCAM", # Augmented Reality "NPAPI", "AWESOMIUM", # Browser embedding "GTK2", "WX", # Toolkit support - "OSMESA", "X11", "XF86DGA", "XRANDR", # Unix platform support + "OSMESA", "X11", "XF86DGA", "XRANDR", "XCURSOR", # Unix platform support "PANDATOOL", "PVIEW", "DEPLOYTOOLS", # Toolchain "CONTRIB" # Experimental ]) @@ -356,6 +356,7 @@ if (COMPILER=="MSVC"): PkgDisable("X11") PkgDisable("XRANDR") PkgDisable("XF86DGA") + PkgDisable("XCURSOR") PkgDisable("GLES") PkgDisable("GLES2") PkgDisable("EGL") @@ -572,6 +573,7 @@ if (COMPILER=="LINUX"): 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 (RUNTIME): # For the runtime, all packages are required @@ -1410,6 +1412,7 @@ DTOOL_CONFIG=[ ("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'), @@ -1518,6 +1521,7 @@ def WriteConfigSettings(): 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' @@ -3316,7 +3320,7 @@ if (sys.platform != "win32" and sys.platform != "darwin" and PkgSkip("GL")==0 an TargetAdd('libpandagl.dll', input='glxdisplay_composite.obj') TargetAdd('libpandagl.dll', input='libp3glstuff.dll') TargetAdd('libpandagl.dll', input=COMMON_PANDA_LIBS) - TargetAdd('libpandagl.dll', opts=['MODULE', 'GL', 'NVIDIACG', 'CGGL', 'X11', 'XRANDR', 'XF86DGA']) + TargetAdd('libpandagl.dll', opts=['MODULE', 'GL', 'NVIDIACG', 'CGGL', 'X11', 'XRANDR', 'XF86DGA', 'XCURSOR']) # # DIRECTORY: panda/src/osxdisplay/ @@ -3375,7 +3379,7 @@ if (PkgSkip("EGL")==0 and PkgSkip("GLES")==0 and PkgSkip("X11")==0 and not RUNTI TargetAdd('libpandagles.dll', input='pandagles_egldisplay_composite1.obj') TargetAdd('libpandagles.dll', input='libp3glstuff.dll') TargetAdd('libpandagles.dll', input=COMMON_PANDA_LIBS) - TargetAdd('libpandagles.dll', opts=['MODULE', 'GLES', 'EGL', 'X11', 'XRANDR', 'XF86DGA']) + TargetAdd('libpandagles.dll', opts=['MODULE', 'GLES', 'EGL', 'X11', 'XRANDR', 'XF86DGA', 'XCURSOR']) # # DIRECTORY: panda/src/egldisplay/ @@ -3395,7 +3399,7 @@ if (PkgSkip("EGL")==0 and PkgSkip("GLES2")==0 and PkgSkip("X11")==0 and not RUNT TargetAdd('libpandagles2.dll', input='pandagles2_egldisplay_composite1.obj') TargetAdd('libpandagles2.dll', input='libp3glstuff.dll') TargetAdd('libpandagles2.dll', input=COMMON_PANDA_LIBS) - TargetAdd('libpandagles2.dll', opts=['MODULE', 'GLES2', 'EGL', 'X11', 'XRANDR', 'XF86DGA']) + TargetAdd('libpandagles2.dll', opts=['MODULE', 'GLES2', 'EGL', 'X11', 'XRANDR', 'XF86DGA', 'XCURSOR']) # # DIRECTORY: panda/src/ode/ @@ -3574,7 +3578,7 @@ if (not RUNTIME and (sys.platform == "win32" or sys.platform == "darwin" or PkgS TargetAdd('libtinydisplay.dll', opts=['WINIMM', 'WINGDI', 'WINKERNEL', 'WINOLDNAMES', 'WINUSER', 'WINMM']) else: TargetAdd('libtinydisplay.dll', input='x11display_composite.obj') - TargetAdd('libtinydisplay.dll', opts=['X11', 'XRANDR', 'XF86DGA']) + TargetAdd('libtinydisplay.dll', opts=['X11', 'XRANDR', 'XF86DGA', 'XCURSOR']) TargetAdd('libtinydisplay.dll', input='tinydisplay_composite1.obj') TargetAdd('libtinydisplay.dll', input='tinydisplay_composite2.obj') TargetAdd('libtinydisplay.dll', input='tinydisplay_ztriangle_1.obj') diff --git a/panda/src/x11display/Sources.pp b/panda/src/x11display/Sources.pp index 2b8213e8f6..401b7f6277 100644 --- a/panda/src/x11display/Sources.pp +++ b/panda/src/x11display/Sources.pp @@ -2,7 +2,7 @@ #define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \ dtoolutil:c dtoolbase:c dtool:m -#define USE_PACKAGES x11 xf86dga xrandr +#define USE_PACKAGES x11 xf86dga xrandr xcursor #begin lib_target #define TARGET x11display diff --git a/panda/src/x11display/x11GraphicsWindow.cxx b/panda/src/x11display/x11GraphicsWindow.cxx index eb34ff8205..d20f636290 100644 --- a/panda/src/x11display/x11GraphicsWindow.cxx +++ b/panda/src/x11display/x11GraphicsWindow.cxx @@ -32,6 +32,11 @@ #include #include #include + +#ifdef HAVE_XCURSOR +#include +#endif + #ifdef HAVE_XF86DGA #include #endif @@ -624,7 +629,21 @@ set_properties_now(WindowProperties &properties) { _awaiting_configure = true; } + // Load a custom cursor from a file. + if (properties.has_cursor_filename()) { + Filename filename = properties.get_cursor_filename(); + Cursor cursor = get_cursor(filename); + + _properties.set_cursor_filename(filename); + // Note that if the cursor fails to load, cursor will be None + XDefineCursor(_display, _xwindow, cursor); + + properties.clear_cursor_filename(); + } + // We hide the cursor by setting it to an invisible pixmap. + // Do this check after setting the custom cursor, to hide the + // custom cursor if necessary. if (properties.has_cursor_hidden()) { _properties.set_cursor_hidden(properties.get_cursor_hidden()); if (properties.get_cursor_hidden()) { @@ -1803,6 +1822,7 @@ get_mouse_button(XButtonEvent &button_event) { return MouseButton::button(index - 1); } } + //////////////////////////////////////////////////////////////////// // Function: x11GraphicsWindow::check_event // Access: Private, Static @@ -1818,3 +1838,53 @@ check_event(Display *display, XEvent *event, char *arg) { // We accept any event that is sent to our window. return (event->xany.window == self->_xwindow); } + +//////////////////////////////////////////////////////////////////// +// Function: x11GraphicsWindow::get_cursor +// Access: Private +// Description: Loads and returns an Cursor corresponding to the +// indicated filename. If the file cannot be loaded, +// returns None. +//////////////////////////////////////////////////////////////////// +Cursor x11GraphicsWindow:: +get_cursor(const Filename &filename) { + // First, look for the unresolved filename in our index. + pmap::iterator fi = _cursor_filenames.find(filename); + if (fi != _cursor_filenames.end()) { + return fi->second; + } + + // If it wasn't found, resolve the filename and search for that. + Filename resolved = filename; + if (!resolved.resolve_filename(get_model_path())) { + // The filename doesn't exist. + x11display_cat.warning() + << "Could not find cursor filename " << filename << "\n"; + return None; + } + fi = _cursor_filenames.find(resolved); + if (fi != _cursor_filenames.end()) { + _cursor_filenames[filename] = (*fi).second; + return fi->second; + } + + Filename os = resolved.to_os_specific(); + +#ifdef HAVE_XCURSOR + Cursor h = XcursorFilenameLoadCursor(_display, os.c_str()); + + if (h == None) { + x11display_cat.warning() + << "x11 cursor filename '" << os << "' could not be loaded!!\n"; + } +#else + // Can't support loading cursor from image, so fall back to default + Cursor h = None; +#endif + + _cursor_filenames[filename] = h; + _cursor_filenames[resolved] = h; + return h; +} + + diff --git a/panda/src/x11display/x11GraphicsWindow.h b/panda/src/x11display/x11GraphicsWindow.h index eb27097192..cff763a64b 100644 --- a/panda/src/x11display/x11GraphicsWindow.h +++ b/panda/src/x11display/x11GraphicsWindow.h @@ -73,6 +73,9 @@ protected: void open_raw_mice(); void poll_raw_mice(); + +private: + Cursor get_cursor(const Filename &filename); protected: Display *_display; @@ -124,6 +127,11 @@ public: private: static TypeHandle _type_handle; + + // Since the Panda API requests icons and cursors by filename, we + // need a table mapping filenames to handles, so we can avoid + // re-reading the file each time we change icons. + pmap _cursor_filenames; }; #include "x11GraphicsWindow.I"