[Bf-blender-cvs] [35b2b9b6e60] master: Fix T98793: Wayland clamps cursor movement fails with gnome-shell

Campbell Barton noreply at git.blender.org
Sat Jun 18 07:07:54 CEST 2022


Commit: 35b2b9b6e6079902d78602afce10e2e3bb9e6b40
Author: Campbell Barton
Date:   Sat Jun 18 15:02:18 2022 +1000
Branches: master
https://developer.blender.org/rB35b2b9b6e6079902d78602afce10e2e3bb9e6b40

Fix T98793: Wayland clamps cursor movement fails with gnome-shell

The current gnome-shell (v42.2) has a bug where grabbing the cursor
doesn't scale the region when confining it to the window.

For Hi-DPI displays this means the cursor may be confined to a quarter
of the window, making grab unusable.

Even though this has been fixed up-stream the issue remains in the
latest release - so workaround the problem by implementing window
confined grab using a software cursor.

This is only used gnome-shell for displays that use Hi-DPI scaling.

===================================================================

M	intern/ghost/GHOST_C-api.h
M	intern/ghost/GHOST_IWindow.h
M	intern/ghost/intern/GHOST_C-api.cpp
M	intern/ghost/intern/GHOST_SystemWayland.cpp
M	intern/ghost/intern/GHOST_SystemWayland.h
M	intern/ghost/intern/GHOST_Window.cpp
M	intern/ghost/intern/GHOST_Window.h
M	intern/ghost/intern/GHOST_WindowWayland.cpp
M	intern/ghost/intern/GHOST_WindowWayland.h
M	source/blender/windowmanager/intern/wm_draw.c

===================================================================

diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index d27be40af0c..08ca9603985 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -404,8 +404,9 @@ extern GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle,
 
 void GHOST_GetCursorGrabState(GHOST_WindowHandle windowhandle,
                               GHOST_TGrabCursorMode *r_mode,
-                              GHOST_TAxisFlag *r_wrap_axis,
-                              int r_bounds[4]);
+                              GHOST_TAxisFlag *r_axis_flag,
+                              int r_bounds[4],
+                              bool *r_use_software_cursor);
 
 /**
  * Grabs the cursor for a modal operation, to keep receiving
diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h
index 7927190de04..f9552246e89 100644
--- a/intern/ghost/GHOST_IWindow.h
+++ b/intern/ghost/GHOST_IWindow.h
@@ -258,7 +258,10 @@ class GHOST_IWindow {
 
   virtual void getCursorGrabState(GHOST_TGrabCursorMode &mode,
                                   GHOST_TAxisFlag &axis_flag,
-                                  GHOST_Rect &bounds) = 0;
+                                  GHOST_Rect &bounds,
+                                  bool &use_software_cursor) = 0;
+
+  virtual bool getCursorGrabUseSoftwareDisplay() = 0;
 
   /**
    * Test if the standard cursor shape is supported by current platform.
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index c8127f59941..032ecd6aab5 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -379,15 +379,18 @@ GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle,
 void GHOST_GetCursorGrabState(GHOST_WindowHandle windowhandle,
                               GHOST_TGrabCursorMode *r_mode,
                               GHOST_TAxisFlag *r_axis_flag,
-                              int r_bounds[4])
+                              int r_bounds[4],
+                              bool *r_use_software_cursor)
 {
   GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
   GHOST_Rect bounds_rect;
-  window->getCursorGrabState(*r_mode, *r_axis_flag, bounds_rect);
+  bool use_software_cursor;
+  window->getCursorGrabState(*r_mode, *r_axis_flag, bounds_rect, use_software_cursor);
   r_bounds[0] = bounds_rect.m_l;
   r_bounds[1] = bounds_rect.m_t;
   r_bounds[2] = bounds_rect.m_r;
   r_bounds[3] = bounds_rect.m_b;
+  *r_use_software_cursor = use_software_cursor;
 }
 
 GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle,
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index 2b0abd2cc41..2d1337df1de 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -44,6 +44,24 @@
 
 static GHOST_WindowWayland *window_from_surface(struct wl_surface *surface);
 
+/**
+ * GNOME (mutter 42.2 had a bug with confine not respecting scale - Hi-DPI), See: T98793.
+ * Even though this has been fixed, at time of writing it's not yet in a release.
+ * Workaround the problem by implementing confine with a software cursor.
+ * While this isn't ideal, it's not adding a lot of overhead as software
+ * cursors are already used for warping (which WAYLAND doesn't support).
+ */
+#define USE_GNOME_CONFINE_HACK
+/**
+ * Always use software confine (not just in GNOME).
+ * Useful for developing with compositors that don't need this workaround.
+ */
+// #define USE_GNOME_CONFINE_HACK_ALWAYS_ON
+
+#ifdef USE_GNOME_CONFINE_HACK
+static bool use_gnome_confine_hack = false;
+#endif
+
 /* -------------------------------------------------------------------- */
 /** \name Private Types & Defines
  * \{ */
@@ -156,6 +174,11 @@ struct input_t {
    * \endcode
    */
   wl_fixed_t xy[2] = {0, 0};
+
+#ifdef USE_GNOME_CONFINE_HACK
+  bool xy_software_confine = false;
+#endif
+
   GHOST_Buttons buttons = GHOST_Buttons();
   struct cursor_t cursor;
 
@@ -590,6 +613,21 @@ static void relative_pointer_handle_relative_motion(
   input->xy[0] += dx / scale;
   input->xy[1] += dy / scale;
 
+#ifdef USE_GNOME_CONFINE_HACK
+  if (input->xy_software_confine) {
+    GHOST_Rect bounds;
+    win->getClientBounds(bounds);
+    /* Needed or the cursor is considered outside the window and doesn't restore the location. */
+    bounds.m_r -= 1;
+    bounds.m_b -= 1;
+
+    bounds.m_l = wl_fixed_from_int(bounds.m_l) / scale;
+    bounds.m_t = wl_fixed_from_int(bounds.m_t) / scale;
+    bounds.m_r = wl_fixed_from_int(bounds.m_r) / scale;
+    bounds.m_b = wl_fixed_from_int(bounds.m_b) / scale;
+    bounds.clampPoint(input->xy[0], input->xy[1]);
+  }
+#endif
   input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
                                                  GHOST_kEventCursorMove,
                                                  win,
@@ -1868,6 +1906,13 @@ static void xdg_output_handle_logical_size(void *data,
      * detected otherwise), then override if necessary. */
     if ((output->size_logical[0] == width) && (output->scale_fractional == wl_fixed_from_int(1))) {
       GHOST_PRINT("xdg_output scale did not match, overriding with wl_output scale");
+
+#ifdef USE_GNOME_CONFINE_HACK
+      /* Use a bug in GNOME to check GNOME is in use. If the bug is fixed this won't cause an issue
+       * as T98793 has been fixed up-stream too, but not in a release at time of writing. */
+      use_gnome_confine_hack = true;
+#endif
+
       return;
     }
   }
@@ -2695,6 +2740,49 @@ bool GHOST_SystemWayland::supportsWindowPosition()
   return false;
 }
 
+bool GHOST_SystemWayland::getCursorGrabUseSoftwareDisplay(const GHOST_TGrabCursorMode mode)
+{
+  if (d->inputs.empty()) {
+    return false;
+  }
+  if (mode == GHOST_kGrabWrap) {
+    return true;
+  }
+#ifdef USE_GNOME_CONFINE_HACK
+  if (mode == GHOST_kGrabNormal) {
+    const input_t *input = d->inputs[0];
+    return input->xy_software_confine;
+  }
+#endif
+  return false;
+}
+
+#ifdef USE_GNOME_CONFINE_HACK
+static bool setCursorGrab_use_software_confine(const GHOST_TGrabCursorMode mode,
+                                               wl_surface *surface)
+{
+#  ifndef USE_GNOME_CONFINE_HACK_ALWAYS_ON
+  if (use_gnome_confine_hack == false) {
+    return false;
+  }
+#  endif
+  if (mode != GHOST_kGrabNormal) {
+    return false;
+  }
+  GHOST_WindowWayland *win = window_from_surface(surface);
+  if (!win) {
+    return false;
+  }
+
+#  ifndef USE_GNOME_CONFINE_HACK_ALWAYS_ON
+  if (win->scale() <= 1) {
+    return false;
+  }
+#  endif
+  return true;
+}
+#endif
+
 GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mode,
                                                   const GHOST_TGrabCursorMode mode_current,
                                                   wl_surface *surface)
@@ -2715,19 +2803,28 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
 
   input_t *input = d->inputs[0];
 
+#ifdef USE_GNOME_CONFINE_HACK
+  const bool was_software_confine = input->xy_software_confine;
+  const bool use_software_confine = setCursorGrab_use_software_confine(mode, surface);
+#else
+  const bool was_software_confine = false;
+  const bool use_software_confine = false;
+#endif
+
+  /* Warping happens to require software cursor which also hides. */
 #define MODE_NEEDS_LOCK(m) ((m) == GHOST_kGrabWrap || (m) == GHOST_kGrabHide)
-#define MODE_NEEDS_HIDE(m) ((m) == GHOST_kGrabHide)
+#define MODE_NEEDS_HIDE(m) (((m) == GHOST_kGrabHide) || ((m) == GHOST_kGrabWrap))
 #define MODE_NEEDS_CONFINE(m) ((m) == GHOST_kGrabNormal)
 
-  const bool was_lock = MODE_NEEDS_LOCK(mode_current);
-  const bool use_lock = MODE_NEEDS_LOCK(mode);
+  const bool was_lock = MODE_NEEDS_LOCK(mode_current) || was_software_confine;
+  const bool use_lock = MODE_NEEDS_LOCK(mode) || use_software_confine;
 
   /* Check for wrap as #supportsCursorWarp isn't supported. */
-  const bool was_hide = MODE_NEEDS_HIDE(mode_current) || (mode_current == GHOST_kGrabWrap);
-  const bool use_hide = MODE_NEEDS_HIDE(mode) || (mode == GHOST_kGrabWrap);
+  const bool was_hide = MODE_NEEDS_HIDE(mode_current) || was_software_confine;
+  const bool use_hide = MODE_NEEDS_HIDE(mode) || use_software_confine;
 
-  const bool was_confine = MODE_NEEDS_CONFINE(mode_current);
-  const bool use_confine = MODE_NEEDS_CONFINE(mode);
+  const bool was_confine = MODE_NEEDS_CONFINE(mode_current) && (was_software_confine == false);
+  const bool use_confine = MODE_NEEDS_CONFINE(mode) && (use_software_confine == false);
 
 #undef MODE_NEEDS_LOCK
 #undef MODE_NEEDS_HIDE
@@ -2788,6 +2885,15 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
           wl_surface_commit(surface);
         }
       }
+#ifdef USE_GNOME_CONFINE_HACK
+      else if (mode_current == GHOST_kGrabNormal) {
+        if (input->xy_software_confine) {
+          zwp_locked_pointer_v1_set_cursor_position_hint(
+              input->locked_pointer, input->xy[0], input->xy[1]);
+          wl_surface_commit(surface);
+        }
+      }
+#endif
 
       zwp_locked_pointer_v1_destroy(input->locked_pointer);
       input->locked_pointer = nullptr;
@@ -2836,6 +2942,10 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
     }
   }
 
+#ifdef USE_GNOME_CONFINE_HACK
+  input->xy_software_confine = use_software_confine;
+#endif
+
   return GHOST_kSuccess;
 }
 
diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h
index 762ceb80e38..6faff8d57c1 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.h
+++ b/intern/ghost/intern/GHOST_SystemWayland.h
@@ -127,6 +127,8 @@ class GHOST_SystemWayland : public GHOST_System {
   bool supportsCursorWarp();
   bool supportsWindowPosition();
 
+  bool getCursorGrabUseSoftwareDisplay(const GHOST_TGrabCursorMode mode);
+
   GHOST_TSuccess setCursorGrab(const GHOST_TGrabCursorMode mode,
                                const GHOST_TGrabCursorMode mode_current,
                                wl_surface *surface);
diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp
index

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list