diff options
Diffstat (limited to 'intern/ghost/intern/GHOST_SystemWayland.cpp')
-rw-r--r-- | intern/ghost/intern/GHOST_SystemWayland.cpp | 438 |
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; } |