From 9b688909b0179b9d595720c96a2ac75a9301bb59 Mon Sep 17 00:00:00 2001 From: Quantum Date: Mon, 15 Feb 2021 19:02:29 -0500 Subject: [PATCH] [client] wayland: support LG_DS_WARP_SURFACE This commit implements support for LG_DS_WARP_SURFACE, as well as a warp routine based on cursor confines. This may not necessarily work for all compositors. As such, the old cursor routines are still kept, and used when wm.warpSupport is set to false. --- client/displayservers/Wayland/wayland.c | 135 +++++++++++++++++------- 1 file changed, 98 insertions(+), 37 deletions(-) diff --git a/client/displayservers/Wayland/wayland.c b/client/displayservers/Wayland/wayland.c index e6951e05..9253a35c 100644 --- a/client/displayservers/Wayland/wayland.c +++ b/client/displayservers/Wayland/wayland.c @@ -79,6 +79,8 @@ struct WaylandDSState bool fullscreen; uint32_t resizeSerial; bool configured; + bool warpSupport; + double cursorX, cursorY; #ifdef ENABLE_EGL struct wl_egl_window * eglWindow; @@ -267,10 +269,11 @@ static const struct wl_registry_listener registryListener = { static void pointerMotionHandler(void * data, struct wl_pointer * pointer, uint32_t serial, wl_fixed_t sxW, wl_fixed_t syW) { - int sx = wl_fixed_to_int(sxW); - int sy = wl_fixed_to_int(syW); - app_updateCursorPos(sx, sy); - if (!wm.relativePointer) + wm.cursorX = wl_fixed_to_double(sxW); + wm.cursorY = wl_fixed_to_double(syW); + app_updateCursorPos(wm.cursorX, wm.cursorY); + + if (!wm.warpSupport && !wm.relativePointer) app_handleMouseBasic(); } @@ -283,15 +286,21 @@ static void pointerEnterHandler(void * data, struct wl_pointer * pointer, wl_pointer_set_cursor(pointer, serial, wm.showPointer ? wm.cursor : NULL, 0, 0); wm.pointerEnterSerial = serial; + wm.cursorX = wl_fixed_to_double(sxW); + wm.cursorY = wl_fixed_to_double(syW); + app_updateCursorPos(wm.cursorX, wm.cursorY); + + if (wm.warpSupport) + { + app_handleMouseRelative(0.0, 0.0, 0.0, 0.0); + return; + } + if (wm.relativePointer) return; - int sx = wl_fixed_to_int(sxW); - int sy = wl_fixed_to_int(syW); app_resyncMouseBasic(); - app_updateCursorPos(sx, sy); - if (!wm.relativePointer) - app_handleMouseBasic(); + app_handleMouseBasic(); } static void pointerLeaveHandler(void * data, struct wl_pointer * pointer, @@ -348,6 +357,26 @@ static const struct wl_pointer_listener pointerListener = { .axis = pointerAxisHandler, }; +static void relativePointerMotionHandler(void * data, + struct zwp_relative_pointer_v1 *pointer, uint32_t timeHi, uint32_t timeLo, + wl_fixed_t dxW, wl_fixed_t dyW, wl_fixed_t dxUnaccelW, + wl_fixed_t dyUnaccelW) +{ + wm.cursorX += wl_fixed_to_double(dxW); + wm.cursorY += wl_fixed_to_double(dyW); + app_updateCursorPos(wm.cursorX, wm.cursorY); + + app_handleMouseRelative( + wl_fixed_to_double(dxW), + wl_fixed_to_double(dyW), + wl_fixed_to_double(dxUnaccelW), + wl_fixed_to_double(dyUnaccelW)); +} + +static const struct zwp_relative_pointer_v1_listener relativePointerListener = { + .relative_motion = relativePointerMotionHandler, +}; + static void waylandInhibitIdle(void) { if (wm.idleInhibitManager && !wm.idleInhibitor) @@ -644,6 +673,13 @@ static bool waylandInit(const LG_DSInitParams params) DEBUG_WARN("zwp_idle_inhibit_manager_v1 not exported by compositor, will " "not be able to suppress idle states"); + if (wm.warpSupport && (!wm.relativePointerManager || !wm.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"); + wm.warpSupport = false; + } + wl_seat_add_listener(wm.seat, &seatListener, NULL); xdg_wm_base_add_listener(wm.xdgWmBase, &xdgWmBaseListener, NULL); wl_display_roundtrip(wm.display); @@ -651,6 +687,15 @@ static bool waylandInit(const LG_DSInitParams params) wm.dataDevice = wl_data_device_manager_get_data_device( wm.dataDeviceManager, wm.seat); + if (wm.warpSupport) + { + wm.relativePointer = + zwp_relative_pointer_manager_v1_get_relative_pointer( + wm.relativePointerManager, wm.pointer); + zwp_relative_pointer_v1_add_listener(wm.relativePointer, + &relativePointerListener, NULL); + } + wm.surface = wl_compositor_create_surface(wm.compositor); wm.eglWindow = wl_egl_window_create(wm.surface, params.w, params.h); wm.xdgSurface = xdg_wm_base_get_xdg_surface(wm.xdgWmBase, wm.surface); @@ -905,28 +950,12 @@ static bool waylandGetFullscreen(void) return wm.fullscreen; } -static void relativePointerMotionHandler(void * data, - struct zwp_relative_pointer_v1 *pointer, uint32_t timeHi, uint32_t timeLo, - wl_fixed_t dxW, wl_fixed_t dyW, wl_fixed_t dxUnaccelW, - wl_fixed_t dyUnaccelW) -{ - app_handleMouseRelative( - wl_fixed_to_double(dxW), - wl_fixed_to_double(dyW), - wl_fixed_to_double(dxUnaccelW), - wl_fixed_to_double(dyUnaccelW)); -} - -static const struct zwp_relative_pointer_v1_listener relativePointerListener = { - .relative_motion = relativePointerMotionHandler, -}; - static void waylandGrabPointer(void) { if (!wm.relativePointerManager || !wm.pointerConstraints) return; - if (!wm.relativePointer) + if (!wm.warpSupport && !wm.relativePointer) { wm.relativePointer = zwp_relative_pointer_manager_v1_get_relative_pointer( @@ -945,20 +974,26 @@ static void waylandGrabPointer(void) static void waylandUngrabPointer(void) { - if (wm.relativePointer) - { - zwp_relative_pointer_v1_destroy(wm.relativePointer); - wm.relativePointer = NULL; - } - if (wm.confinedPointer) { zwp_confined_pointer_v1_destroy(wm.confinedPointer); wm.confinedPointer = NULL; } - app_resyncMouseBasic(); - app_handleMouseBasic(); + if (!wm.warpSupport) + { + if (!wm.relativePointer) + { + wm.relativePointer = + zwp_relative_pointer_manager_v1_get_relative_pointer( + wm.relativePointerManager, wm.pointer); + zwp_relative_pointer_v1_add_listener(wm.relativePointer, + &relativePointerListener, NULL); + } + + app_resyncMouseBasic(); + app_handleMouseBasic(); + } } static void waylandGrabKeyboard(void) @@ -981,12 +1016,38 @@ static void waylandUngrabKeyboard(void) static void waylandWarpPointer(int x, int y, bool exiting) { - // This is an unsupported operation on Wayland. + if (x < 0) x = 0; + else if (x >= wm.width) x = wm.width - 1; + if (y < 0) y = 0; + else if (y >= wm.height) y = wm.height - 1; + + struct wl_region * region = wl_compositor_create_region(wm.compositor); + wl_region_add(region, x, y, 1, 1); + + if (wm.confinedPointer) + { + zwp_confined_pointer_v1_set_region(wm.confinedPointer, region); + wl_surface_commit(wm.surface); + zwp_confined_pointer_v1_set_region(wm.confinedPointer, NULL); + } + else + { + struct zwp_confined_pointer_v1 * confine; + confine = zwp_pointer_constraints_v1_confine_pointer( + wm.pointerConstraints, wm.surface, wm.pointer, region, + ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); + wl_surface_commit(wm.surface); + zwp_confined_pointer_v1_destroy(confine); + } + + wl_surface_commit(wm.surface); + wl_region_destroy(region); } static void waylandRealignPointer(void) { - app_resyncMouseBasic(); + if (!wm.warpSupport) + app_resyncMouseBasic(); } static bool waylandIsValidPointerPos(int x, int y) @@ -1015,7 +1076,7 @@ static bool waylandGetProp(LG_DSProperty prop, void * ret) { if (prop == LG_DS_WARP_SUPPORT) { - *(enum LG_DSWarpSupport*)ret = LG_DS_WARP_NONE; + *(enum LG_DSWarpSupport*)ret = wm.warpSupport ? LG_DS_WARP_SURFACE : LG_DS_WARP_NONE; return true; }