From 9f2d6f64130a7699045318ff4c4c1bcd6f18c378 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sun, 9 Aug 2026 03:32:38 +1000 Subject: [PATCH] [client] wayland: constrain pointer only during capture Remove the persistent confined-pointer workaround that emulated cursor warping on Wayland. Normal pointer motion now uses absolute input only. Create relative and locked pointer objects only during capture. Preserve the request across pointer capability changes, and suppress relative events until the compositor confirms the lock. On uncapture, publish the current absolute position instead of trying to warp the host cursor. --- client/displayservers/Wayland/input.c | 527 ++++-------------------- client/displayservers/Wayland/wayland.c | 11 +- client/displayservers/Wayland/wayland.h | 10 +- client/include/app.h | 3 - client/src/app.c | 57 +-- client/src/core.c | 36 +- client/src/main.c | 6 - client/src/main.h | 3 - doc/usage.rst | 2 - 9 files changed, 124 insertions(+), 531 deletions(-) diff --git a/client/displayservers/Wayland/input.c b/client/displayservers/Wayland/input.c index 4e9c5595..1e63bb9c 100644 --- a/client/displayservers/Wayland/input.c +++ b/client/displayservers/Wayland/input.c @@ -21,7 +21,6 @@ #include "wayland.h" #include -#include #include #include #include @@ -70,9 +69,6 @@ static void pointerMotionHandler(void * data, struct wl_pointer * pointer, MTRACE("abs time=%u pos=%.3f,%.3f", time, wlWm.motion.x, wlWm.motion.y); app_updateCursorPos(wlWm.motion.x, wlWm.motion.y); - - if (!wlWm.warpSupport && !wlWm.relativePointer) - app_handleMouseBasic(); } static void pointerEnterHandler(void * data, struct wl_pointer * pointer, @@ -95,18 +91,6 @@ static void pointerEnterHandler(void * data, struct wl_pointer * pointer, wlMotionAbs(&wlWm.motion, wl_fixed_to_double(sxW), wl_fixed_to_double(syW)); app_updateCursorPos(wlWm.motion.x, wlWm.motion.y); - - if (wlWm.warpSupport) - { - app_handleMouseRelative(0.0, 0.0, 0.0, 0.0); - return; - } - - if (wlWm.relativePointer) - return; - - app_resyncMouseBasic(); - app_handleMouseBasic(); } static void pointerLeaveHandler(void * data, struct wl_pointer * pointer, @@ -195,100 +179,6 @@ static const struct wl_pointer_listener pointerListener = { .axis = pointerAxisHandler, }; -static void confinedHandler(void * data, - struct zwp_confined_pointer_v1 * pointer) -{ - bool valid; - LG_LOCK(wlWm.surfaceLock); - valid = pointer == wlWm.confinedPointer; - if (valid) - atomic_store_explicit(&wlWm.confActive, true, memory_order_release); - LG_UNLOCK(wlWm.surfaceLock); - MTRACE("conf active=1 id=%u valid=%d", proxyId(pointer), valid); - - if (valid) - app_handleGrabEvent(true); -} - -static void unconfinedHandler(void * data, - struct zwp_confined_pointer_v1 * pointer) -{ - bool valid; - LG_LOCK(wlWm.surfaceLock); - valid = pointer == wlWm.confinedPointer; - if (valid) - atomic_store_explicit(&wlWm.confActive, false, memory_order_release); - LG_UNLOCK(wlWm.surfaceLock); - MTRACE("conf active=0 id=%u valid=%d", proxyId(pointer), valid); - - if (valid) - app_handleGrabEvent(false); -} - -static const struct zwp_confined_pointer_v1_listener confinedListener = { - .confined = confinedHandler, - .unconfined = unconfinedHandler, -}; - -static struct zwp_confined_pointer_v1 * createConfine( - struct wl_region * region); -static bool queueConfSync(void); - -static void confSyncHandler(void * data, struct wl_callback * callback, - uint32_t serial) -{ - bool notify = false; - bool valid = false; - const uint32_t id = proxyId(callback); - uint32_t confId = 0; - uint64_t confSeq = 0; - - LG_LOCK(wlWm.surfaceLock); - if (callback == wlWm.confSync) - { - valid = true; - wl_callback_destroy(callback); - wlWm.confSync = NULL; - atomic_store_explicit(&wlWm.confActive, false, - memory_order_release); - notify = wlWm.inputLive; - - if (wlWm.inputLive && wlWm.confReq && wlWm.pointer && - wlWm.pointerConstraints && !wlWm.confinedPointer && - !wlWm.lockedPointer) - { - wlWm.confinedPointer = createConfine(NULL); - confId = proxyId(wlWm.confinedPointer); - confSeq = app_mouseSeq(); - } - } - LG_UNLOCK(wlWm.surfaceLock); - - MTRACE("conf sync id=%u serial=%u valid=%d notify=%d", id, serial, - valid, notify); - MLOG(confSeq, "conf req id=%u why=sync", confId); - - if (notify) - app_handleGrabEvent(false); -} - -static const struct wl_callback_listener confSyncListener = { - .done = confSyncHandler, -}; - -static bool queueConfSync(void) -{ - if (wlWm.confSync) - return true; - - wlWm.confSync = wl_display_sync(wlWm.display); - if (!wlWm.confSync) - return false; - - wl_callback_add_listener(wlWm.confSync, &confSyncListener, NULL); - return true; -} - static void lockedHandler(void * data, struct zwp_locked_pointer_v1 * pointer) { @@ -318,17 +208,6 @@ static const struct zwp_locked_pointer_v1_listener lockedListener = { .unlocked = unlockedHandler, }; -static struct zwp_confined_pointer_v1 * createConfine( - struct wl_region * region) -{ - struct zwp_confined_pointer_v1 * pointer = - zwp_pointer_constraints_v1_confine_pointer( - wlWm.pointerConstraints, wlWm.surface, wlWm.pointer, region, - ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); - zwp_confined_pointer_v1_add_listener(pointer, &confinedListener, NULL); - return pointer; -} - static struct zwp_locked_pointer_v1 * createLock(void) { struct zwp_locked_pointer_v1 * pointer = @@ -344,6 +223,9 @@ static void relativePointerMotionHandler(void * data, wl_fixed_t dxW, wl_fixed_t dyW, wl_fixed_t dxUnaccelW, wl_fixed_t dyUnaccelW) { + if (!atomic_load_explicit(&wlWm.lockActive, memory_order_acquire)) + return; + const double dx = wl_fixed_to_double(dxW); const double dy = wl_fixed_to_double(dyW); MTRACE("rel time=%u:%u delta=%.3f,%.3f raw=%.3f,%.3f " @@ -509,23 +391,66 @@ static const struct wl_keyboard_listener keyboardListener = { .modifiers = keyboardModifiersHandler, }; -static void waylandCleanUpPointer(bool notify) +static void ensureCapturePointer(bool requestCapture) { - bool event = false; - uint32_t lockId = 0; - uint32_t confId = 0; - uint64_t lockSeq = 0; - uint64_t confSeq = 0; + uint32_t relativeId = 0; + uint32_t lockId = 0; + uint64_t lockSeq = 0; + bool captureRequested = false; + bool havePointer = false; + bool haveRelativeManager = false; + bool haveConstraints = false; INTERLOCKED_SECTION(wlWm.surfaceLock, { - if (wlWm.confSync) - { - wl_callback_destroy(wlWm.confSync); - wlWm.confSync = NULL; - } + if (requestCapture) + wlWm.captureRequested = true; + captureRequested = wlWm.captureRequested; + havePointer = !!wlWm.pointer; + haveRelativeManager = !!wlWm.relativePointerManager; + haveConstraints = !!wlWm.pointerConstraints; + + if (captureRequested && havePointer && haveRelativeManager && + haveConstraints) + { + if (!wlWm.relativePointer) + { + wlWm.relativePointer = + zwp_relative_pointer_manager_v1_get_relative_pointer( + wlWm.relativePointerManager, wlWm.pointer); + zwp_relative_pointer_v1_add_listener(wlWm.relativePointer, + &relativePointerListener, NULL); + relativeId = proxyId(wlWm.relativePointer); + } + + if (!wlWm.lockedPointer) + { + atomic_store_explicit(&wlWm.lockActive, false, + memory_order_release); + wlWm.lockedPointer = createLock(); + lockId = proxyId(wlWm.lockedPointer); + lockSeq = app_mouseSeq(); + } + } + }); + + if (relativeId) + MTRACE("rel req id=%u why=capture", relativeId); + + MLOG(lockSeq, "lock req id=%u why=capture", lockId); + if (captureRequested && + (!havePointer || !haveRelativeManager || !haveConstraints)) + MTRACE("capture skip pointer=%d relMgr=%d constraints=%d", + havePointer, haveRelativeManager, haveConstraints); +} + +static void waylandCleanUpPointer(bool notify) +{ + uint32_t lockId = 0; + uint64_t lockSeq = 0; + INTERLOCKED_SECTION(wlWm.surfaceLock, + { atomic_store_explicit(&wlWm.lockActive, false, memory_order_release); - atomic_store_explicit(&wlWm.confActive, false, memory_order_release); if (wlWm.lockedPointer) { @@ -535,14 +460,6 @@ static void waylandCleanUpPointer(bool notify) lockSeq = app_mouseSeq(); } - if (wlWm.confinedPointer) - { - confId = proxyId(wlWm.confinedPointer); - zwp_confined_pointer_v1_destroy(wlWm.confinedPointer); - wlWm.confinedPointer = NULL; - confSeq = app_mouseSeq(); - } - if (wlWm.relativePointer) { zwp_relative_pointer_v1_destroy(wlWm.relativePointer); @@ -552,18 +469,12 @@ static void waylandCleanUpPointer(bool notify) wl_pointer_destroy(wlWm.pointer); wlWm.pointer = NULL; wlWm.pointerInSurface = false; - - event = notify && wlWm.inputLive; }); MLOG(lockSeq, "lock destroy id=%u why=pointer", lockId); - MLOG(confSeq, "conf destroy id=%u why=pointer", confId); - if (event) - { + if (notify) app_handleEnterEvent(false); - app_handleGrabEvent(false); - } } // Seat-handling listeners. @@ -575,31 +486,12 @@ static void handlePointerCapability(uint32_t capabilities) waylandCleanUpPointer(true); else if (hasPointer && !wlWm.pointer) { + LG_LOCK(wlWm.surfaceLock); wlWm.pointer = wl_seat_get_pointer(wlWm.seat); wl_pointer_add_listener(wlWm.pointer, &pointerListener, NULL); + LG_UNLOCK(wlWm.surfaceLock); waylandSetPointer(wlWm.cursorId); - - if (wlWm.warpSupport) - { - wlWm.relativePointer = - zwp_relative_pointer_manager_v1_get_relative_pointer( - wlWm.relativePointerManager, wlWm.pointer); - zwp_relative_pointer_v1_add_listener(wlWm.relativePointer, - &relativePointerListener, NULL); - } - - if (app_isCaptureMode()) - waylandCapturePointer(); - else - { - bool confReq; - INTERLOCKED_SECTION(wlWm.surfaceLock, - { - confReq = wlWm.confReq; - }); - if (confReq) - waylandGrabPointer(); - } + ensureCapturePointer(false); } } @@ -645,7 +537,6 @@ bool waylandInputInit(bool allowNoInput) if (allowNoInput) { DEBUG_WARN("Compositor missing wl_seat, input will be disabled"); - wlWm.warpSupport = false; return true; } @@ -653,13 +544,6 @@ bool waylandInputInit(bool allowNoInput) return false; } - if (wlWm.warpSupport && (!wlWm.relativePointerManager || !wlWm.pointerConstraints)) - { - DEBUG_WARN("Cursor warp is requested, but cannot be honoured due to lack " - "of zwp_relative_pointer_manager_v1 or zwp_pointer_constraints_v1"); - wlWm.warpSupport = false; - } - if (!wlWm.relativePointerManager) DEBUG_WARN("zwp_relative_pointer_manager_v1 not exported by compositor, " "mouse will not be captured"); @@ -672,14 +556,10 @@ bool waylandInputInit(bool allowNoInput) DEBUG_WARN("zwp_keyboard_shortcuts_inhibit_manager_v1 not exported by " "compositor, keyboard will not be grabbed"); - MTRACE("input seat=1 warp=%d relMgr=%d constraints=%d", - wlWm.warpSupport, !!wlWm.relativePointerManager, + MTRACE("input seat=1 relMgr=%d constraints=%d", + !!wlWm.relativePointerManager, !!wlWm.pointerConstraints); - LG_LOCK(wlWm.surfaceLock); - wlWm.inputLive = true; - LG_UNLOCK(wlWm.surfaceLock); - wlWm.xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!wlWm.xkb) DEBUG_WARN("Failed to initialize xkb, keyboard input will not work"); @@ -692,10 +572,6 @@ bool waylandInputInit(bool allowNoInput) void waylandInputFree(void) { - LG_LOCK(wlWm.surfaceLock); - wlWm.inputLive = false; - LG_UNLOCK(wlWm.surfaceLock); - if (!wlWm.seat) return; @@ -721,210 +597,56 @@ void waylandInputFree(void) void waylandGrabPointer(void) { - uint32_t relativeId = 0; - uint32_t confId = 0; - uint64_t confSeq = 0; - bool haveConf = false; - bool haveLock = false; - bool haveSync = false; - bool havePointer = false; - bool haveConstraints = false; - INTERLOCKED_SECTION(wlWm.surfaceLock, - { - wlWm.confReq = true; - - if (wlWm.pointer && !wlWm.warpSupport && !wlWm.relativePointer && - wlWm.relativePointerManager) - { - wlWm.relativePointer = - zwp_relative_pointer_manager_v1_get_relative_pointer( - wlWm.relativePointerManager, wlWm.pointer); - zwp_relative_pointer_v1_add_listener(wlWm.relativePointer, - &relativePointerListener, NULL); - relativeId = proxyId(wlWm.relativePointer); - } - - if (wlWm.pointer && wlWm.pointerConstraints && - !wlWm.confinedPointer && !wlWm.lockedPointer && !wlWm.confSync) - { - wlWm.confinedPointer = createConfine(NULL); - confId = proxyId(wlWm.confinedPointer); - confSeq = app_mouseSeq(); - } - haveConf = !!wlWm.confinedPointer; - haveLock = !!wlWm.lockedPointer; - haveSync = !!wlWm.confSync; - havePointer = !!wlWm.pointer; - haveConstraints = !!wlWm.pointerConstraints; - }); - - if (relativeId) - MTRACE("rel req id=%u why=grab", relativeId); - - if (confId) - MLOG(confSeq, "conf req id=%u why=grab", confId); - else - MTRACE("conf skip pointer=%d constraints=%d conf=%d lock=%d sync=%d", - havePointer, haveConstraints, haveConf, haveLock, haveSync); -} - -inline static uint32_t destroyConfine(uint64_t * traceSeq) -{ - *traceSeq = 0; - - uint32_t confId = 0; - if (wlWm.confinedPointer) - { - confId = proxyId(wlWm.confinedPointer); - zwp_confined_pointer_v1_destroy(wlWm.confinedPointer); - wlWm.confinedPointer = NULL; - atomic_store_explicit(&wlWm.confActive, false, memory_order_release); - *traceSeq = app_mouseSeq(); - - if (!queueConfSync()) - DEBUG_ERROR("Failed to queue pointer release sync"); - } - - return confId; -} - -static void ungrabBasic(void) -{ - if (wlWm.warpSupport) - return; - - uint32_t relativeId = 0; - LG_LOCK(wlWm.surfaceLock); - if (wlWm.pointer && !wlWm.relativePointer && - wlWm.relativePointerManager) - { - wlWm.relativePointer = - zwp_relative_pointer_manager_v1_get_relative_pointer( - wlWm.relativePointerManager, wlWm.pointer); - zwp_relative_pointer_v1_add_listener(wlWm.relativePointer, - &relativePointerListener, NULL); - relativeId = proxyId(wlWm.relativePointer); - } - LG_UNLOCK(wlWm.surfaceLock); - - if (relativeId) - MTRACE("rel req id=%u why=ungrab", relativeId); - - app_resyncMouseBasic(); - app_handleMouseBasic(); } void waylandUngrabPointer(void) { - bool notify; - uint64_t confSeq; - uint32_t confId; - - LG_LOCK(wlWm.surfaceLock); - wlWm.confReq = false; - confId = destroyConfine(&confSeq); - notify = !wlWm.confSync && wlWm.inputLive; - LG_UNLOCK(wlWm.surfaceLock); - - MLOG(confSeq, "conf destroy id=%u why=ungrab", confId); - ungrabBasic(); - - if (notify) - app_handleGrabEvent(false); } void waylandCapturePointer(void) { - if (!wlWm.warpSupport) - { - MTRACE("capture fallback=confine"); - waylandGrabPointer(); - return; - } - - uint32_t confId = 0; - uint32_t lockId = 0; - uint64_t confSeq = 0; - uint64_t lockSeq = 0; - INTERLOCKED_SECTION(wlWm.surfaceLock, - { - wlWm.confReq = true; - confId = destroyConfine(&confSeq); - - if (wlWm.pointer && !wlWm.lockedPointer) - { - atomic_store_explicit(&wlWm.lockActive, false, - memory_order_release); - wlWm.lockedPointer = createLock(); - lockId = proxyId(wlWm.lockedPointer); - lockSeq = app_mouseSeq(); - } - }); - - MLOG(confSeq, "conf destroy id=%u why=capture", confId); - MLOG(lockSeq, "lock req id=%u why=capture", lockId); + ensureCapturePointer(true); } void waylandUncapturePointer(void) { - uint32_t lockId = 0; - uint32_t confDropId = 0; - uint32_t confReqId = 0; - uint64_t lockSeq = 0; - uint64_t confDropSeq = 0; - uint64_t confReqSeq = 0; + uint32_t lockId = 0; + uint32_t relativeId = 0; + uint64_t lockSeq = 0; INTERLOCKED_SECTION(wlWm.surfaceLock, { + wlWm.captureRequested = false; + atomic_store_explicit(&wlWm.lockActive, false, memory_order_release); + if (wlWm.lockedPointer) { lockId = proxyId(wlWm.lockedPointer); zwp_locked_pointer_v1_destroy(wlWm.lockedPointer); wlWm.lockedPointer = NULL; - atomic_store_explicit(&wlWm.lockActive, false, - memory_order_release); lockSeq = app_mouseSeq(); } - /* we need to ungrab the pointer on the following conditions when exiting capture mode: - * - if warp is not supported, exit via window edge detection will never work - * as the cursor can not be warped out of the window when we release it. - * - if the format is invalid as we do not know where the guest cursor is, - * which also breaks edge detection. - * - if the user has opted to use captureInputOnly mode. - */ - if (!wlWm.warpSupport || !app_isFormatValid() || app_isCaptureOnlyMode()) + if (wlWm.relativePointer) { - wlWm.confReq = false; - confDropId = destroyConfine(&confDropSeq); - } - else - { - wlWm.confReq = true; - if (wlWm.pointer && !wlWm.confSync && !wlWm.confinedPointer) - { - wlWm.confinedPointer = createConfine(NULL); - confReqId = proxyId(wlWm.confinedPointer); - confReqSeq = app_mouseSeq(); - } + relativeId = proxyId(wlWm.relativePointer); + zwp_relative_pointer_v1_destroy(wlWm.relativePointer); + wlWm.relativePointer = NULL; } }); MLOG(lockSeq, "lock destroy id=%u why=uncapture", lockId); - MLOG(confDropSeq, "conf destroy id=%u why=uncapture", confDropId); - MLOG(confReqSeq, "conf req id=%u why=uncapture", confReqId); - ungrabBasic(); + if (relativeId) + MTRACE("rel destroy id=%u why=uncapture", relativeId); } bool waylandIsPointerGrabbed(void) { - return atomic_load_explicit(&wlWm.confActive, memory_order_acquire); + return false; } bool waylandIsPointerCaptured(void) { - const atomic_bool * active = wlWm.warpSupport ? - &wlWm.lockActive : &wlWm.confActive; - return atomic_load_explicit(active, memory_order_acquire); + return atomic_load_explicit(&wlWm.lockActive, memory_order_acquire); } void waylandGrabKeyboard(void) @@ -948,91 +670,22 @@ void waylandUngrabKeyboard(void) void waylandWarpPointer(int x, int y, bool exiting) { - const int reqX = x; - const int reqY = y; - if (!wlWm.pointerInSurface) - { - MTRACE("warp drop=surface target=%d,%d exit=%d", x, y, exiting); - return; - } - - if (wlWm.lockedPointer) - { - MTRACE("warp drop=lock target=%d,%d exit=%d", x, y, exiting); - return; - } - - LG_LOCK(wlWm.surfaceLock); - if (wlWm.lockedPointer) - { - LG_UNLOCK(wlWm.surfaceLock); - MTRACE("warp drop=lock-race target=%d,%d exit=%d", x, y, exiting); - return; - } - - int width, height; - wlWm.desktop->getSize(&width, &height); - - if (x < 0) x = 0; - else if (x >= width) x = width - 1; - if (y < 0) y = 0; - else if (y >= height) y = height - 1; - - struct wl_region * region = wl_compositor_create_region(wlWm.compositor); - wl_region_add(region, x, y, 1, 1); - - const uint32_t confId = proxyId(wlWm.confinedPointer); - uint32_t tempId = 0; - uint64_t warpSeq = 0; - if (wlWm.confinedPointer) - { - zwp_confined_pointer_v1_set_region(wlWm.confinedPointer, region); - wl_surface_commit(wlWm.surface); - zwp_confined_pointer_v1_set_region(wlWm.confinedPointer, NULL); - } - else - { - struct zwp_confined_pointer_v1 * confine = createConfine(region); - tempId = proxyId(confine); - wl_surface_commit(wlWm.surface); - zwp_confined_pointer_v1_destroy(confine); - } - - wl_surface_commit(wlWm.surface); - wl_region_destroy(region); - warpSeq = app_mouseSeq(); - LG_UNLOCK(wlWm.surfaceLock); - - MLOG(warpSeq, "warp req=%d,%d target=%d,%d exit=%d conf=%u temp=%u", - reqX, reqY, x, y, exiting, confId, tempId); + (void)x; + (void)y; + (void)exiting; } void waylandRealignPointer(void) { - if (!wlWm.warpSupport) - app_resyncMouseBasic(); + if (wlWm.pointerInSurface) + app_updateCursorPos(wlWm.motion.x, wlWm.motion.y); } -void waylandGuestPointerUpdated(double x, double y, double localX, double localY) +void waylandGuestPointerUpdated(double x, double y, double localX, + double localY) { - const char * drop = NULL; - if (!wlWm.pointer) - drop = "pointer"; - else if (!wlWm.warpSupport) - drop = "support"; - else if (!wlWm.pointerInSurface) - drop = "surface"; - else if (wlWm.lockedPointer) - drop = "lock"; - - if (drop) - { - MTRACE("guest drop=%s guest=%.3f,%.3f local=%.3f,%.3f", - drop, x, y, localX, localY); - return; - } - - MTRACE("guest warp guest=%.3f,%.3f local=%.3f,%.3f", - x, y, localX, localY); - waylandWarpPointer((int) round(localX), (int) round(localY), false); + (void)x; + (void)y; + (void)localX; + (void)localY; } diff --git a/client/displayservers/Wayland/wayland.c b/client/displayservers/Wayland/wayland.c index 4005f37c..0c53a741 100644 --- a/client/displayservers/Wayland/wayland.c +++ b/client/displayservers/Wayland/wayland.c @@ -34,13 +34,6 @@ static struct Option waylandOptions[] = { - { - .module = "wayland", - .name = "warpSupport", - .description = "Enable cursor warping", - .type = OPTION_TYPE_BOOL, - .value.x_bool = true, - }, { .module = "wayland", .name = "fractionScale", @@ -112,7 +105,6 @@ static bool waylandInit(const LG_DSInitParams params) LG_LOCK_INIT(wlWm.pendingHDRLock); LG_LOCK_INIT(wlWm.hdrLock); wlWm.desktop = WL_Desktops[0]; - atomic_init(&wlWm.confActive, false); atomic_init(&wlWm.lockActive, false); atomic_init(&wlWm.cmFeaturesDone, false); atomic_init(&wlWm.cmCanDoHDR, false); @@ -141,7 +133,6 @@ static bool waylandInit(const LG_DSInitParams params) wl_list_init(&wlWm.surfaceOutputs); - wlWm.warpSupport = option_get_bool("wayland", "warpSupport"); wlWm.useFractionalScale = option_get_bool("wayland", "fractionScale"); if (!waylandPollInit()) @@ -224,7 +215,7 @@ static bool waylandGetProp(LG_DSProperty prop, void * ret) { if (prop == LG_DS_WARP_SUPPORT) { - *(enum LG_DSWarpSupport*)ret = wlWm.warpSupport ? LG_DS_WARP_SURFACE : LG_DS_WARP_NONE; + *(enum LG_DSWarpSupport*)ret = LG_DS_WARP_NONE; return true; } diff --git a/client/displayservers/Wayland/wayland.h b/client/displayservers/Wayland/wayland.h index f088979b..991fe990 100644 --- a/client/displayservers/Wayland/wayland.h +++ b/client/displayservers/Wayland/wayland.h @@ -123,7 +123,6 @@ struct WaylandHDRParameters struct WaylandDSState { - _Atomic(bool) confActive; _Atomic(bool) lockActive; bool keyboardGrabbed; bool pointerInSurface; @@ -143,7 +142,6 @@ struct WaylandDSState bool fractionalScale; bool needsResize; bool configured; - bool warpSupport; struct WlMotion motion; double scrollState; @@ -196,11 +194,8 @@ struct WaylandDSState struct zwp_relative_pointer_manager_v1 * relativePointerManager; struct zwp_pointer_constraints_v1 * pointerConstraints; struct zwp_relative_pointer_v1 * relativePointer; - struct zwp_confined_pointer_v1 * confinedPointer; struct zwp_locked_pointer_v1 * lockedPointer; - struct wl_callback * confSync; - bool confReq; - bool inputLive; + bool captureRequested; bool showPointer; uint32_t pointerEnterSerial; @@ -392,7 +387,8 @@ bool waylandIsPointerGrabbed(void); bool waylandIsPointerCaptured(void); void waylandRealignPointer(void); void waylandWarpPointer(int x, int y, bool exiting); -void waylandGuestPointerUpdated(double x, double y, double localX, double localY); +void waylandGuestPointerUpdated(double x, double y, double localX, + double localY); bool waylandGetKeyLabel(int key, char * label, size_t size); // output module bool waylandOutputInit(void); diff --git a/client/include/app.h b/client/include/app.h index 82506af7..194e1bfa 100644 --- a/client/include/app.h +++ b/client/include/app.h @@ -72,9 +72,6 @@ void app_invalidateWindow(bool full); void app_handleMouseRelative(double normx, double normy, double rawx, double rawy); -void app_handleMouseBasic(void); -void app_resyncMouseBasic(void); - void app_handleButtonPress(int button); void app_handleButtonRelease(int button); void app_handleWheelMotion(double motion); diff --git a/client/src/app.c b/client/src/app.c index ba6c5b13..76236078 100644 --- a/client/src/app.c +++ b/client/src/app.c @@ -269,7 +269,10 @@ void app_handleEnterEvent(bool entered) return; g_cursor.realign = true; - core_handleMouseAbsolute(); + if (g_cursor.grab) + core_setCursorInView(true); + else + core_handleMouseAbsolute(); } else { @@ -652,58 +655,6 @@ void app_handleGrabEvent(bool active) core_handleGrabEvent(active); } -// On some display servers normal cursor logic does not work due to the lack of -// cursor warp support. Instead, we attempt a best-effort emulation which works -// with a 1:1 mouse movement patch applied in the guest. For anything fancy, use -// capture mode. -void app_handleMouseBasic(void) -{ - /* do not pass mouse events to the guest if we do not have focus */ - if (!g_cursor.guest.valid || !g_state.haveSrcSize || !g_state.focused || - app_isOverlayMode()) - return; - - if (!core_inputEnabled()) - return; - - if (lgInput_supports(LG_INPUT_SUPPORT_MOUSE_ABSOLUTE)) - return; - - const bool inView = - g_cursor.pos.x >= g_state.dstRect.x && - g_cursor.pos.x < g_state.dstRect.x + g_state.dstRect.w && - g_cursor.pos.y >= g_state.dstRect.y && - g_cursor.pos.y < g_state.dstRect.y + g_state.dstRect.h; - - core_setCursorInView(inView); - - /* translate the current position to guest coordinate space */ - struct DoublePoint guest; - util_localCurToGuest(&guest); - - int x = (int) round(util_clamp(guest.x, 0, g_state.srcSize.x) - - g_cursor.projected.x); - int y = (int) round(util_clamp(guest.y, 0, g_state.srcSize.y) - - g_cursor.projected.y); - - if (!x && !y) - return; - - g_cursor.projected.x += x; - g_cursor.projected.y += y; - - if (!lgInput_mouseMotion(x, y)) - DEBUG_ERROR("failed to send mouse motion message"); -} - -void app_resyncMouseBasic(void) -{ - if (!g_cursor.guest.valid) - return; - g_cursor.projected.x = g_cursor.guest.x + g_cursor.guest.hx; - g_cursor.projected.y = g_cursor.guest.y + g_cursor.guest.hy; -} - void app_updateWindowPos(int x, int y) { g_state.windowPos.x = x; diff --git a/client/src/core.c b/client/src/core.c index 89b7d5e1..95f48993 100644 --- a/client/src/core.c +++ b/client/src/core.c @@ -327,10 +327,13 @@ void core_setGrabQuiet(bool enable) /* ensure the local mouse is inside the window before we capture, this fixes * odd UI behaviour if the user is using focus follows mouse and the window * was focused without the cursor being in window already */ - struct DoublePoint local; - const bool valid = util_guestCurToLocal(&local); - MTRACE("grab align valid=%d", valid); - core_warpPointer(local.x, local.y, true); + if (warpSupport != LG_DS_WARP_NONE) + { + struct DoublePoint local; + const bool valid = util_guestCurToLocal(&local); + MTRACE("grab align valid=%d", valid); + core_warpPointer(local.x, local.y, true); + } if (g_params.grabKeyboard) g_state.ds->grabKeyboard(); @@ -348,13 +351,18 @@ void core_setGrabQuiet(bool enable) g_state.ds->uncapturePointer(); - if (!g_params.captureInputOnly && warpSupport != LG_DS_WARP_NONE) - applyView(g_state.ds->isPointerGrabbed(), false); + if (warpSupport == LG_DS_WARP_NONE) + core_handleMouseAbsolute(); + else + { + if (!g_params.captureInputOnly) + applyView(g_state.ds->isPointerGrabbed(), false); - /* if exiting capture when input on capture only we need to align the local - * cursor to the guest's location before it is shown. */ - if (g_params.captureInputOnly || !g_params.hideMouse) - core_alignToGuest(); + /* if exiting capture when input on capture only we need to align the + * local cursor to the guest's location before it is shown. */ + if (g_params.captureInputOnly || !g_params.hideMouse) + core_alignToGuest(); + } } } @@ -372,6 +380,14 @@ bool core_warpPointer(int x, int y, bool exiting) return false; } + enum LG_DSWarpSupport warpSupport = LG_DS_WARP_NONE; + app_getProp(LG_DS_WARP_SUPPORT, &warpSupport); + if (warpSupport == LG_DS_WARP_NONE) + { + MTRACE("warp drop=support target=%d,%d exit=%d", x, y, exiting); + return false; + } + if (!exiting && g_cursor.warpState == WARP_STATE_OFF) { MTRACE("warp drop=state target=%d,%d exit=%d", x, y, exiting); diff --git a/client/src/main.c b/client/src/main.c index 4dd960f7..b7e7519f 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -1150,15 +1150,9 @@ int main_cursorThread(void * unused) g_cursor.guest.y = pointer.y; g_cursor.guest.valid = true; if (!wasValid && core_inputEnabled()) - { core_alignToGuest(); - app_resyncMouseBasic(); - } } - if (hotspotChanged) - app_resyncMouseBasic(); - if ((pointer.flags & LG_TRANSPORT_POINTER_POSITION) || hotspotChanged) core_handleGuestMouseUpdate(); diff --git a/client/src/main.h b/client/src/main.h index b56811d3..9b49a858 100644 --- a/client/src/main.h +++ b/client/src/main.h @@ -343,9 +343,6 @@ struct CursorState /* the guest's cursor position */ struct CursorInfo guest; - - /* the projected position after move, for app_handleMouseBasic only */ - struct Point projected; }; // forwards diff --git a/doc/usage.rst b/doc/usage.rst index df6486ff..71f5049f 100644 --- a/doc/usage.rst +++ b/doc/usage.rst @@ -432,8 +432,6 @@ All command line options +-----------------------+-------+-------+-------------------------+ | Long | Short | Value | Description | +=======================+=======+=======+=========================+ - | wayland:warpSupport | | yes | Enable cursor warping | - +-----------------------+-------+-------+-------------------------+ | wayland:fractionScale | | yes | Enable fractional scale | +-----------------------+-------+-------+-------------------------+