Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/ghost/intern/GHOST_SystemWayland.cpp')
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp438
1 files changed, 358 insertions, 80 deletions
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index d8fbe875f67..33afb5f3155 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -26,15 +26,18 @@
#include <unordered_map>
#include <unordered_set>
-#include "GHOST_WaylandCursorSettings.h"
-#include <pointer-constraints-client-protocol.h>
-#include <relative-pointer-client-protocol.h>
-#include <tablet-client-protocol.h>
#include <wayland-cursor.h>
-#include <xdg-output-client-protocol.h>
+
+#include "GHOST_WaylandCursorSettings.h"
#include <xkbcommon/xkbcommon.h>
+/* Generated by `wayland-scanner`. */
+#include <pointer-constraints-unstable-v1-client-protocol.h>
+#include <relative-pointer-unstable-v1-client-protocol.h>
+#include <tablet-unstable-v2-client-protocol.h>
+#include <xdg-output-unstable-v1-client-protocol.h>
+
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
@@ -44,6 +47,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
* \{ */
@@ -78,6 +99,14 @@ 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;
struct wl_cursor_image wl_image = {0};
@@ -87,7 +116,9 @@ struct cursor_t {
std::string theme_name;
/** Outputs on which the cursor is visible. */
std::unordered_set<const output_t *> outputs;
- int scale = 1;
+
+ int theme_scale = 1;
+ int custom_scale = 1;
};
/**
@@ -125,6 +156,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;
@@ -153,9 +190,14 @@ struct input_t {
* wl_fixed_to_int(scale * input->xy[0]),
* wl_fixed_to_int(scale * input->xy[1]),
* };
- * \endocde
+ * \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;
@@ -496,7 +538,7 @@ static GHOST_TTabletMode tablet_tool_map_type(enum zwp_tablet_tool_v2_type wl_ta
static const int default_cursor_size = 24;
-static const std::unordered_map<GHOST_TStandardCursor, std::string> cursors = {
+static const std::unordered_map<GHOST_TStandardCursor, const char *> cursors = {
{GHOST_kStandardCursorDefault, "left_ptr"},
{GHOST_kStandardCursorRightArrow, "right_ptr"},
{GHOST_kStandardCursorLeftArrow, "left_ptr"},
@@ -590,6 +632,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,
@@ -1039,9 +1096,11 @@ static bool update_cursor_scale(cursor_t &cursor, wl_shm *shm)
}
}
- if (scale > 0 && cursor.scale != scale) {
- cursor.scale = scale;
- wl_surface_set_buffer_scale(cursor.wl_surface, scale);
+ if (scale > 0 && cursor.theme_scale != scale) {
+ cursor.theme_scale = scale;
+ if (!cursor.is_custom) {
+ wl_surface_set_buffer_scale(cursor.wl_surface, scale);
+ }
wl_cursor_theme_destroy(cursor.wl_theme);
cursor.wl_theme = wl_cursor_theme_load(cursor.theme_name.c_str(), scale * cursor.size, shm);
return true;
@@ -1123,12 +1182,13 @@ static void pointer_handle_leave(void *data,
uint32_t /*serial*/,
struct wl_surface *surface)
{
+ /* First clear the `focus_pointer`, since the window won't exist when closing the window. */
+ static_cast<input_t *>(data)->focus_pointer = nullptr;
+
GHOST_IWindow *win = window_from_surface(surface);
if (!win) {
return;
}
-
- static_cast<input_t *>(data)->focus_pointer = nullptr;
static_cast<GHOST_WindowWayland *>(win)->deactivate();
}
@@ -1860,16 +1920,21 @@ static void xdg_output_handle_logical_size(void *data,
if (output->size_logical[0] != 0 && output->size_logical[1] != 0) {
/* Original comment from SDL. */
- /* FIXME: GNOME has a bug where the logical size does not account for
+ /* FIXME(@flibit): GNOME has a bug where the logical size does not account for
* scale, resulting in bogus viewport sizes.
*
* Until this is fixed, validate that _some_ kind of scaling is being
* done (we can't match exactly because fractional scaling can't be
- * detected otherwise), then override if necessary.
- * -flibit
- */
+ * 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;
}
}
@@ -1968,7 +2033,7 @@ static void output_handle_done(void *data, struct wl_output * /*wl_output*/)
int32_t size_native[2];
if (output->transform & WL_OUTPUT_TRANSFORM_90) {
size_native[0] = output->size_native[1];
- size_native[1] = output->size_native[1];
+ size_native[1] = output->size_native[0];
}
else {
size_native[0] = output->size_native[0];
@@ -2317,16 +2382,33 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorPosition(int32_t /*x*/, int32_t /*y
void GHOST_SystemWayland::getMainDisplayDimensions(uint32_t &width, uint32_t &height) const
{
- if (getNumDisplays() > 0) {
- /* We assume first output as main. */
- width = uint32_t(d->outputs[0]->size_native[0]) / d->outputs[0]->scale;
- height = uint32_t(d->outputs[0]->size_native[1]) / d->outputs[0]->scale;
+ if (getNumDisplays() == 0) {
+ return;
}
+ /* We assume first output as main. */
+ width = uint32_t(d->outputs[0]->size_native[0]);
+ height = uint32_t(d->outputs[0]->size_native[1]);
}
void GHOST_SystemWayland::getAllDisplayDimensions(uint32_t &width, uint32_t &height) const
{
- getMainDisplayDimensions(width, height);
+ int32_t xy_min[2] = {INT32_MAX, INT32_MAX};
+ int32_t xy_max[2] = {INT32_MIN, INT32_MIN};
+
+ for (const output_t *output : d->outputs) {
+ int32_t xy[2] = {0, 0};
+ if (output->has_position_logical) {
+ xy[0] = output->position_logical[0];
+ xy[1] = output->position_logical[1];
+ }
+ xy_min[0] = std::min(xy_min[0], xy[0]);
+ xy_min[1] = std::min(xy_min[1], xy[1]);
+ xy_max[0] = std::max(xy_max[0], xy[0] + output->size_native[0]);
+ xy_max[1] = std::max(xy_max[1], xy[1] + output->size_native[1]);
+ }
+
+ width = xy_max[0] - xy_min[0];
+ height = xy_max[1] - xy_min[1];
}
GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GLSettings /*glSettings*/)
@@ -2466,47 +2548,152 @@ 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)
+{
+ const cursor_t *c = &input->cursor;
+ const int scale = c->is_custom ? c->custom_scale : c->theme_scale;
+ const int32_t hotspot_x = int32_t(c->wl_image.hotspot_x) / scale;
+ const int32_t hotspot_y = int32_t(c->wl_image.hotspot_y) / 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);
+ }
+}
+
+/**
+ * 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)
{
- cursor_t *c = &input->cursor;
+ const cursor_t *c = &input->cursor;
+ const int scale = c->is_custom ? c->custom_scale : c->theme_scale;
- c->visible = (buffer != nullptr);
+ 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);
- 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;
+ /* This is a requirement of WAYLAND, when this isn't the case,
+ * it causes Blender's window to close intermittently. */
+ GHOST_ASSERT((image_size_x % scale) == 0 && (image_size_y % scale) == 0,
+ "The size must be a multiple of the scale!");
+ const int32_t hotspot_x = int32_t(c->wl_image.hotspot_x) / scale;
+ const int32_t hotspot_y = int32_t(c->wl_image.hotspot_y) / scale;
+
+ wl_surface_set_buffer_scale(c->wl_surface, 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);
- wl_surface_commit(c->wl_surface);
-
/* Set the cursor for all tablet tools as well. */
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));
+
/* 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, 1);
+ wl_surface_set_buffer_scale(tool_input->cursor_surface, 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);
+ }
+}
- wl_surface_commit(tool_input->cursor_surface);
+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)
@@ -2514,8 +2701,10 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape)
if (d->inputs.empty()) {
return GHOST_kFailure;
}
- const std::string cursor_name = cursors.count(shape) ? cursors.at(shape) :
- cursors.at(GHOST_kStandardCursorDefault);
+ auto cursor_find = cursors.find(shape);
+ const char *cursor_name = (cursor_find == cursors.end()) ?
+ cursors.at(GHOST_kStandardCursorDefault) :
+ (*cursor_find).second;
input_t *input = d->inputs[0];
cursor_t *c = &input->cursor;
@@ -2526,7 +2715,7 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape)
c->theme_name.c_str(), c->size, d->inputs[0]->system->shm());
}
- wl_cursor *cursor = wl_cursor_theme_get_cursor(c->wl_theme, cursor_name.c_str());
+ wl_cursor *cursor = wl_cursor_theme_get_cursor(c->wl_theme, cursor_name);
if (!cursor) {
GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl);
@@ -2539,17 +2728,27 @@ 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;
}
GHOST_TSuccess GHOST_SystemWayland::hasCursorShape(GHOST_TStandardCursor cursorShape)
{
- return GHOST_TSuccess(cursors.count(cursorShape) && !cursors.at(cursorShape).empty());
+ auto cursor_find = cursors.find(cursorShape);
+ if (cursor_find == cursors.end()) {
+ return GHOST_kFailure;
+ }
+ const char *value = (*cursor_find).second;
+ if (*value == '\0') {
+ return GHOST_kFailure;
+ }
+ return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap,
@@ -2602,6 +2801,7 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap,
nullptr, cursor->file_buffer->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (cursor->file_buffer->data == MAP_FAILED) {
+ cursor->file_buffer->data = nullptr;
close(fd);
return GHOST_kFailure;
}
@@ -2646,37 +2846,49 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap,
}
}
+ cursor->visible = true;
+ cursor->is_custom = true;
+ cursor->custom_scale = 1; /* TODO: support Hi-DPI custom cursors. */
cursor->wl_buffer = buffer;
cursor->wl_image.width = uint32_t(sizex);
cursor->wl_image.height = uint32_t(sizey);
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;
}
-GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(bool visible)
+GHOST_TSuccess GHOST_SystemWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitmap)
{
- if (d->inputs.empty()) {
+ cursor_t *cursor = &d->inputs[0]->cursor;
+ if (cursor->file_buffer->data == nullptr) {
+ return GHOST_kFailure;
+ }
+ if (!cursor->is_custom) {
return GHOST_kFailure;
}
- input_t *input = d->inputs[0];
+ bitmap->data_size[0] = cursor->wl_image.width;
+ bitmap->data_size[1] = cursor->wl_image.height;
- 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);
- }
+ bitmap->hot_spot[0] = cursor->wl_image.hotspot_x;
+ bitmap->hot_spot[1] = cursor->wl_image.hotspot_y;
+
+ bitmap->data = (uint8_t *)static_cast<void *>(cursor->file_buffer->data);
+
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(bool visible)
+{
+ if (d->inputs.empty()) {
+ return GHOST_kFailure;
}
+ input_t *input = d->inputs[0];
+ cursor_visible_set(input, visible, input->cursor.is_hardware, CURSOR_VISIBLE_ALWAYS_SET);
return GHOST_kSuccess;
}
@@ -2693,6 +2905,60 @@ bool GHOST_SystemWayland::supportsWindowPosition()
return false;
}
+bool GHOST_SystemWayland::getCursorGrabUseSoftwareDisplay(const GHOST_TGrabCursorMode mode)
+{
+ if (d->inputs.empty()) {
+ return false;
+ }
+
+#ifdef USE_GNOME_CONFINE_HACK
+ input_t *input = d->inputs[0];
+ const bool use_software_confine = input->xy_software_confine;
+#else
+ const bool use_software_confine = false;
+#endif
+
+ return cursor_is_software(mode, use_software_confine);
+}
+
+#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
+
+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,
wl_surface *surface)
@@ -2705,7 +2971,6 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
if (d->inputs.empty()) {
return GHOST_kFailure;
}
-
/* No change, success. */
if (mode == mode_current) {
return GHOST_kSuccess;
@@ -2713,32 +2978,33 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
input_t *input = d->inputs[0];
-#define MODE_NEEDS_LOCK(m) ((m) == GHOST_kGrabWrap || (m) == GHOST_kGrabHide)
-#define MODE_NEEDS_HIDE(m) ((m) == GHOST_kGrabHide)
-#define MODE_NEEDS_CONFINE(m) ((m) == GHOST_kGrabNormal)
+#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
- const bool was_lock = MODE_NEEDS_LOCK(mode_current);
- const bool use_lock = MODE_NEEDS_LOCK(mode);
+ const struct input_grab_state_t grab_state_prev = input_grab_state_from_mode(
+ mode_current, was_software_confine);
+ const struct input_grab_state_t grab_state_next = input_grab_state_from_mode(
+ 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 use_visible = !(((mode == GHOST_kGrabHide) || (mode == GHOST_kGrabWrap)) ||
+ use_software_confine);
- const bool was_confine = MODE_NEEDS_CONFINE(mode_current);
- const bool use_confine = MODE_NEEDS_CONFINE(mode);
+ const bool is_hardware_cursor = !cursor_is_software(mode, use_software_confine);
-#undef MODE_NEEDS_LOCK
-#undef MODE_NEEDS_HIDE
-#undef MODE_NEEDS_CONFINE
-
- if (!use_hide) {
- setCursorVisibility(true);
- }
+ /* Only hide so the cursor is not made visible before it's location is restored.
+ * This function is called again at the end of this function which only shows. */
+ cursor_visible_set(input, use_visible, is_hardware_cursor, CURSOR_VISIBLE_ONLY_HIDE);
/* Switching from one grab mode to another,
* in this case disable the current locks as it makes logic confusing,
* postpone changing the cursor to avoid flickering. */
- if (!use_lock) {
+ if (!grab_state_next.use_lock) {
if (input->relative_pointer) {
zwp_relative_pointer_v1_destroy(input->relative_pointer);
input->relative_pointer = nullptr;
@@ -2786,13 +3052,22 @@ 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 (was_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;
}
}
- if (!use_confine) {
+ if (!grab_state_next.use_confine) {
if (input->confined_pointer) {
zwp_confined_pointer_v1_destroy(input->confined_pointer);
input->confined_pointer = nullptr;
@@ -2800,8 +3075,8 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
}
if (mode != GHOST_kGrabDisable) {
- if (use_lock) {
- if (!was_lock) {
+ if (grab_state_next.use_lock) {
+ if (!grab_state_prev.use_lock) {
/* TODO(@campbellbarton): As WAYLAND does not support warping the pointer it may not be
* possible to support #GHOST_kGrabWrap by pragmatically settings it's coordinates.
* An alternative could be to draw the cursor in software (and hide the real cursor),
@@ -2818,8 +3093,8 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
}
}
- else if (use_confine) {
- if (!was_confine) {
+ else if (grab_state_next.use_confine) {
+ if (!grab_state_prev.use_confine) {
input->confined_pointer = zwp_pointer_constraints_v1_confine_pointer(
d->pointer_constraints,
surface,
@@ -2828,12 +3103,15 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
}
}
-
- if (use_hide && !was_hide) {
- setCursorVisibility(false);
- }
}
+ /* Only show so the cursor is made visible as the last step. */
+ cursor_visible_set(input, use_visible, is_hardware_cursor, CURSOR_VISIBLE_ONLY_SHOW);
+
+#ifdef USE_GNOME_CONFINE_HACK
+ input->xy_software_confine = use_software_confine;
+#endif
+
return GHOST_kSuccess;
}