[Bf-blender-cvs] [6e8217d35e0] master: GHOST/Wayland: refactor cursor handling & fix errors hiding the cursor

Campbell Barton noreply at git.blender.org
Mon Jun 20 04:12:41 CEST 2022


Commit: 6e8217d35e0ba920abf423f3e442c33c36ed1bef
Author: Campbell Barton
Date:   Mon Jun 20 11:18:40 2022 +1000
Branches: master
https://developer.blender.org/rB6e8217d35e0ba920abf423f3e442c33c36ed1bef

GHOST/Wayland: refactor cursor handling & fix errors hiding the cursor

- Support showing & hiding the cursor without setting the buffer,
  needed to switch between software and hardware cursor.
- Track the state of the software/hardware cursor.

This resolves glitches switching between cursors sometimes hiding the
cursor.

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

M	intern/ghost/intern/GHOST_SystemWayland.cpp

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

diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index db8bfceda9b..6a4d1827a80 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -96,6 +96,13 @@ struct buffer_t {
 
 struct cursor_t {
   bool visible = false;
+  /**
+   * When false, hide the hardware cursor, while the cursor is still considered to be `visible`,
+   * since the grab-mode determines the state of the software cursor,
+   * this may change - removing the need for a software cursor and in this case it's important
+   * the hardware cursor is used.
+   */
+  bool is_hardware = true;
   bool is_custom = false;
   struct wl_surface *wl_surface = nullptr;
   struct wl_buffer *wl_buffer = nullptr;
@@ -144,6 +151,12 @@ struct key_repeat_payload_t {
   GHOST_TEventKeyData key_data = {GHOST_kKeyUnknown};
 };
 
+/** Internal variables used to track grab-state. */
+struct input_grab_state_t {
+  bool use_lock = false;
+  bool use_confine = false;
+};
+
 struct input_t {
   GHOST_SystemWayland *system = nullptr;
 
@@ -2528,11 +2541,48 @@ void GHOST_SystemWayland::setSelection(const std::string &selection)
   this->selection = selection;
 }
 
-static void set_cursor_buffer(input_t *input, wl_buffer *buffer)
+/**
+ * Show the buffer defined by #cursor_buffer_set without changing anything else,
+ * so #cursor_buffer_hide can be used to display it again.
+ *
+ * The caller is responsible for setting `input->cursor.visible`.
+ */
+static void cursor_buffer_show(const input_t *input)
 {
-  cursor_t *c = &input->cursor;
+  const cursor_t *c = &input->cursor;
+  const int32_t hotspot_x = int32_t(c->wl_image.hotspot_x) / c->scale;
+  const int32_t hotspot_y = int32_t(c->wl_image.hotspot_y) / c->scale;
+  wl_pointer_set_cursor(
+      input->wl_pointer, input->pointer_serial, c->wl_surface, hotspot_x, hotspot_y);
+  for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : input->tablet_tools) {
+    tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(
+        zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2));
+    zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2,
+                                  input->tablet_serial,
+                                  tool_input->cursor_surface,
+                                  hotspot_x,
+                                  hotspot_y);
+  }
+}
 
-  c->visible = (buffer != nullptr);
+/**
+ * Hide the buffer defined by #cursor_buffer_set without changing anything else,
+ * so #cursor_buffer_show can be used to display it again.
+ *
+ * The caller is responsible for setting `input->cursor.visible`.
+ */
+static void cursor_buffer_hide(const input_t *input)
+{
+  wl_pointer_set_cursor(input->wl_pointer, input->pointer_serial, nullptr, 0, 0);
+  for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : input->tablet_tools) {
+    zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2, input->tablet_serial, nullptr, 0, 0);
+  }
+}
+
+static void cursor_buffer_set(const input_t *input, wl_buffer *buffer)
+{
+  const cursor_t *c = &input->cursor;
+  const bool visible = (c->visible && c->is_hardware);
 
   const int32_t image_size_x = int32_t(c->wl_image.width);
   const int32_t image_size_y = int32_t(c->wl_image.height);
@@ -2540,16 +2590,14 @@ static void set_cursor_buffer(input_t *input, wl_buffer *buffer)
   const int32_t hotspot_x = int32_t(c->wl_image.hotspot_x) / c->scale;
   const int32_t hotspot_y = int32_t(c->wl_image.hotspot_y) / c->scale;
 
-  if (buffer) {
-    wl_surface_set_buffer_scale(c->wl_surface, c->scale);
-    wl_surface_attach(c->wl_surface, buffer, 0, 0);
-    wl_surface_damage(c->wl_surface, 0, 0, image_size_x, image_size_y);
-    wl_surface_commit(c->wl_surface);
-  }
+  wl_surface_set_buffer_scale(c->wl_surface, c->scale);
+  wl_surface_attach(c->wl_surface, buffer, 0, 0);
+  wl_surface_damage(c->wl_surface, 0, 0, image_size_x, image_size_y);
+  wl_surface_commit(c->wl_surface);
 
   wl_pointer_set_cursor(input->wl_pointer,
                         input->pointer_serial,
-                        c->visible ? c->wl_surface : nullptr,
+                        visible ? c->wl_surface : nullptr,
                         hotspot_x,
                         hotspot_y);
 
@@ -2558,23 +2606,81 @@ static void set_cursor_buffer(input_t *input, wl_buffer *buffer)
     tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(
         zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2));
 
-    if (buffer) {
-      /* FIXME: for some reason cursor scale is applied twice (when the scale isn't 1x),
-       * this happens both in gnome-shell & KDE. Setting the surface scale here doesn't help. */
-      wl_surface_set_buffer_scale(tool_input->cursor_surface, c->scale);
-      wl_surface_attach(tool_input->cursor_surface, buffer, 0, 0);
-      wl_surface_damage(tool_input->cursor_surface, 0, 0, image_size_x, image_size_y);
-      wl_surface_commit(tool_input->cursor_surface);
-    }
+    /* FIXME: for some reason cursor scale is applied twice (when the scale isn't 1x),
+     * this happens both in gnome-shell & KDE. Setting the surface scale here doesn't help. */
+    wl_surface_set_buffer_scale(tool_input->cursor_surface, c->scale);
+    wl_surface_attach(tool_input->cursor_surface, buffer, 0, 0);
+    wl_surface_damage(tool_input->cursor_surface, 0, 0, image_size_x, image_size_y);
+    wl_surface_commit(tool_input->cursor_surface);
 
     zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2,
                                   input->tablet_serial,
-                                  c->visible ? tool_input->cursor_surface : nullptr,
+                                  visible ? tool_input->cursor_surface : nullptr,
                                   hotspot_x,
                                   hotspot_y);
   }
 }
 
+enum eCursorSetMode {
+  CURSOR_VISIBLE_ALWAYS_SET = 1,
+  CURSOR_VISIBLE_ONLY_HIDE,
+  CURSOR_VISIBLE_ONLY_SHOW,
+};
+
+static void cursor_visible_set(input_t *input,
+                               const bool visible,
+                               const bool is_hardware,
+                               const enum eCursorSetMode set_mode)
+{
+  cursor_t *cursor = &input->cursor;
+  const bool was_visible = cursor->is_hardware && cursor->visible;
+  const bool use_visible = is_hardware && visible;
+
+  if (set_mode == CURSOR_VISIBLE_ALWAYS_SET) {
+    /* Pass. */
+  }
+  else if ((set_mode == CURSOR_VISIBLE_ONLY_SHOW)) {
+    if (!use_visible) {
+      return;
+    }
+  }
+  else if ((set_mode == CURSOR_VISIBLE_ONLY_HIDE)) {
+    if (use_visible) {
+      return;
+    }
+  }
+
+  if (use_visible) {
+    if (!was_visible) {
+      cursor_buffer_show(input);
+    }
+  }
+  else {
+    if (was_visible) {
+      cursor_buffer_hide(input);
+    }
+  }
+  cursor->visible = visible;
+  cursor->is_hardware = is_hardware;
+}
+
+static bool cursor_is_software(const GHOST_TGrabCursorMode mode, const bool use_software_confine)
+{
+  if (mode == GHOST_kGrabWrap) {
+    return true;
+  }
+#ifdef USE_GNOME_CONFINE_HACK
+  if (mode == GHOST_kGrabNormal) {
+    if (use_software_confine) {
+      return true;
+    }
+  }
+#else
+  (void)use_software_confine;
+#endif
+  return false;
+}
+
 GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape)
 {
   if (d->inputs.empty()) {
@@ -2605,11 +2711,12 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape)
     return GHOST_kFailure;
   }
 
+  c->visible = true;
   c->is_custom = false;
   c->wl_buffer = buffer;
   c->wl_image = *image;
 
-  set_cursor_buffer(input, buffer);
+  cursor_buffer_set(input, buffer);
 
   return GHOST_kSuccess;
 }
@@ -2714,6 +2821,7 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap,
     }
   }
 
+  cursor->visible = true;
   cursor->is_custom = true;
   cursor->wl_buffer = buffer;
   cursor->wl_image.width = uint32_t(sizex);
@@ -2721,7 +2829,7 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap,
   cursor->wl_image.hotspot_x = uint32_t(hotX);
   cursor->wl_image.hotspot_y = uint32_t(hotY);
 
-  set_cursor_buffer(d->inputs[0], buffer);
+  cursor_buffer_set(d->inputs[0], buffer);
 
   return GHOST_kSuccess;
 }
@@ -2754,19 +2862,7 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(bool visible)
   }
 
   input_t *input = d->inputs[0];
-
-  cursor_t *cursor = &input->cursor;
-  if (visible) {
-    if (!cursor->visible) {
-      set_cursor_buffer(input, cursor->wl_buffer);
-    }
-  }
-  else {
-    if (cursor->visible) {
-      set_cursor_buffer(input, nullptr);
-    }
-  }
-
+  cursor_visible_set(input, visible, input->cursor.is_hardware, CURSOR_VISIBLE_ALWAYS_SET);
   return GHOST_kSuccess;
 }
 
@@ -2788,16 +2884,15 @@ bool GHOST_SystemWayland::getCursorGrabUseSoftwareDisplay(const GHOST_TGrabCurso
   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;
-  }
+  input_t *input = d->inputs[0];
+  const bool use_software_confine = input->xy_software_confine;
+#else
+  const bool use_software_confine = false;
 #endif
-  return false;
+
+  return cursor_is_software(mode, use_software_confine);
 }
 
 #ifdef USE_GNOME_CONFINE_HACK
@@ -2826,6 +2921,18 @@ static bool setCursorGrab_use_software_confine(const GHOST_TGrabCursorMode mode,
 }
 #endif
 
+static input_grab_state_t input_grab_state_from_mode(const GHOST_TGrabCursorMode mode,
+                                                     const bool use_software_confine)
+{
+  /* Initialize all members. */
+  const struct input_grab_state_t grab_state = {
+      /* Warping happens to require software cursor which also hides. */
+      .use_lock = (mode == GHOST_kGrabWrap || mode == GHOST_kGrabHide) || use_software_confine,
+      .use_confine = (mode == GHOST_kGrabNormal) && (use_software_confine == false),
+  };
+  return grab_state;
+}
+
 GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mode,
                                                   const GHOST_TGrabCursorMode mode_current,
        

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list