Fix T53004: XWayland ignores cursor-warp calls
[blender.git] / intern / ghost / intern / GHOST_SystemX11.cpp
index 8fff565338f8066555ad4a6b8ff39ecab61037cd..9b617a34e1a2623a54a7e840585a8f673a7d1616 100644 (file)
 #include <X11/XF86keysym.h>
 #endif
 
+#ifdef WITH_X11_XFIXES
+#  include <X11/extensions/Xfixes.h>
+/* Workaround for XWayland grab glitch: T53004. */
+#define WITH_XWAYLAND_HACK
+#endif
+
 /* for XIWarpPointer */
 #ifdef WITH_X11_XINPUT
 #  include <X11/extensions/XInput2.h>
@@ -95,6 +101,10 @@ static GHOST_TKey convertXKey(KeySym key);
 static char *txt_cut_buffer = NULL;
 static char *txt_select_buffer = NULL;
 
+#ifdef WITH_XWAYLAND_HACK
+static bool use_xwayland_hack = false;
+#endif
+
 using namespace std;
 
 GHOST_SystemX11::
@@ -176,7 +186,11 @@ GHOST_SystemX11(
        if (use_xkb) {
                XkbSetDetectableAutoRepeat(m_display, true, NULL);
        }
-       
+
+#ifdef WITH_XWAYLAND_HACK
+       use_xwayland_hack = getenv("WAYLAND_DISPLAY") != NULL;
+#endif
+
 #ifdef WITH_X11_XINPUT
        /* detect if we have xinput (for reuse) */
        {
@@ -1472,23 +1486,21 @@ getButtons(
        return GHOST_kSuccess;
 }
 
-
-GHOST_TSuccess
-GHOST_SystemX11::
-getCursorPosition(
-               GHOST_TInt32& x,
-               GHOST_TInt32& y) const
+static GHOST_TSuccess getCursorPosition_impl(
+        Display *display,
+        GHOST_TInt32& x,
+        GHOST_TInt32& y,
+        Window *child_return)
 {
-
-       Window root_return, child_return;
        int rx, ry, wx, wy;
        unsigned int mask_return;
+       Window root_return;
 
        if (XQueryPointer(
-               m_display,
-               RootWindow(m_display, DefaultScreen(m_display)),
+               display,
+               RootWindow(display, DefaultScreen(display)),
                &root_return,
-               &child_return,
+               child_return,
                &rx, &ry,
                &wx, &wy,
                &mask_return
@@ -1498,10 +1510,20 @@ getCursorPosition(
        else {
                x = rx;
                y = ry;
-       }       
+       }
        return GHOST_kSuccess;
 }
 
+GHOST_TSuccess
+GHOST_SystemX11::
+getCursorPosition(
+               GHOST_TInt32& x,
+               GHOST_TInt32& y) const
+{
+       Window child_return;
+       return getCursorPosition_impl(m_display, x, y, &child_return);
+}
+
 
 GHOST_TSuccess
 GHOST_SystemX11::
@@ -1515,13 +1537,29 @@ setCursorPosition(
         * current pointer position. */
 
        int cx, cy;
+
+#ifdef WITH_XWAYLAND_HACK
+       Window child_return = None;
+       if (getCursorPosition_impl(m_display, cx, cy, &child_return) == GHOST_kFailure) {
+               return GHOST_kFailure;
+       }
+#else
        if (getCursorPosition(cx, cy) == GHOST_kFailure) {
                return GHOST_kFailure;
        }
+#endif
 
        int relx = x - cx;
        int rely = y - cy;
 
+#ifdef WITH_XWAYLAND_HACK
+       if (use_xwayland_hack) {
+               if (child_return != None) {
+                       XFixesHideCursor(m_display, child_return);
+               }
+       }
+#endif
+
 #ifdef WITH_X11_XINPUT
        if ((m_xinput_version.present) &&
            (m_xinput_version.major_version >= 2))
@@ -1538,6 +1576,14 @@ setCursorPosition(
                XWarpPointer(m_display, None, None, 0, 0, 0, 0, relx, rely);
        }
 
+#ifdef WITH_XWAYLAND_HACK
+       if (use_xwayland_hack) {
+               if (child_return != None) {
+                       XFixesShowCursor(m_display, child_return);
+               }
+       }
+#endif
+
        XSync(m_display, 0); /* Sync to process all requests */
        
        return GHOST_kSuccess;