GHOST/Wayland: non-wrapping grab no longer locks the cursor

Grab which didn't wrap would lock the cursor, making actions such
as resizing areas lock the cursor in-place.

Confine the cursor to the window instead.

This behavior was also used for X11 when grabbing the cursor was first
supported but could lock the system if Blender froze while grabbing so
it was disabled [0].

For Wayland this shouldn't be a problem as compositors implement grab
in a way that prevents the client from locking the system.

[0]: 3e3d2b7a4c
This commit is contained in:
Campbell Barton 2022-06-08 11:28:31 +10:00
parent 173a15bcda
commit b3e0101a35
Notes: blender-bot 2023-05-03 10:14:48 +02:00
Referenced by issue #98714, Sculpting and hair particle edit broken on Wayland
1 changed files with 61 additions and 22 deletions

View File

@ -112,6 +112,7 @@ struct input_t {
struct zwp_relative_pointer_v1 *relative_pointer;
struct zwp_locked_pointer_v1 *locked_pointer;
struct zwp_confined_pointer_v1 *confined_pointer;
struct xkb_context *xkb_context;
struct xkb_state *xkb_state;
@ -1376,6 +1377,7 @@ static void global_add(void *data,
input->data_source->buffer_out = nullptr;
input->relative_pointer = nullptr;
input->locked_pointer = nullptr;
input->confined_pointer = nullptr;
input->seat = static_cast<wl_seat *>(
wl_registry_bind(wl_registry, name, &wl_seat_interface, 4));
display->inputs.push_back(input);
@ -1939,15 +1941,31 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
input_t *input = d->inputs[0];
if (mode_current == GHOST_kGrabHide) {
#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)
const bool was_lock = MODE_NEEDS_LOCK(mode_current);
const bool use_lock = MODE_NEEDS_LOCK(mode);
const bool was_hide = MODE_NEEDS_HIDE(mode_current);
const bool use_hide = MODE_NEEDS_HIDE(mode);
const bool was_confine = MODE_NEEDS_CONFINE(mode_current);
const bool use_confine = MODE_NEEDS_CONFINE(mode);
#undef MODE_NEEDS_LOCK
#undef MODE_NEEDS_HIDE
#undef MODE_NEEDS_CONFINE
if (!use_hide) {
setCursorVisibility(true);
}
if ((mode == GHOST_kGrabDisable) ||
/* 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. */
(mode_current != GHOST_kGrabDisable)) {
/* 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 (input->relative_pointer) {
zwp_relative_pointer_v1_destroy(input->relative_pointer);
input->relative_pointer = nullptr;
@ -1958,23 +1976,44 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
}
}
if (mode != GHOST_kGrabDisable) {
/* 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),
* or just accept a locked cursor on WAYLAND. */
input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
d->relative_pointer_manager, input->pointer);
zwp_relative_pointer_v1_add_listener(
input->relative_pointer, &relative_pointer_listener, input);
input->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
d->pointer_constraints,
surface,
input->pointer,
nullptr,
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
if (!use_confine) {
if (input->confined_pointer) {
zwp_confined_pointer_v1_destroy(input->confined_pointer);
input->confined_pointer = nullptr;
}
}
if (mode == GHOST_kGrabHide) {
if (mode != GHOST_kGrabDisable) {
if (use_lock) {
if (!was_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),
* or just accept a locked cursor on WAYLAND. */
input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
d->relative_pointer_manager, input->pointer);
zwp_relative_pointer_v1_add_listener(
input->relative_pointer, &relative_pointer_listener, input);
input->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
d->pointer_constraints,
surface,
input->pointer,
nullptr,
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
}
}
else if (use_confine) {
if (!was_confine) {
input->confined_pointer = zwp_pointer_constraints_v1_confine_pointer(
d->pointer_constraints,
surface,
input->pointer,
nullptr,
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
}
}
if (use_hide && !was_hide) {
setCursorVisibility(false);
}
}