diff --git a/client/displayservers/SDL/sdl.c b/client/displayservers/SDL/sdl.c index 1b1434e1..37305773 100644 --- a/client/displayservers/SDL/sdl.c +++ b/client/displayservers/SDL/sdl.c @@ -535,6 +535,8 @@ struct LG_DisplayServerOps LGDS_SDL = .showPointer = sdlShowPointer, .grabPointer = sdlGrabPointer, .ungrabPointer = sdlUngrabPointer, + .capturePointer = sdlGrabPointer, + .uncapturePointer = sdlUngrabPointer, .grabKeyboard = sdlGrabKeyboard, .ungrabKeyboard = sdlUngrabKeyboard, .warpPointer = sdlWarpPointer, diff --git a/client/displayservers/Wayland/input.c b/client/displayservers/Wayland/input.c index bb3993c4..8146f6f0 100644 --- a/client/displayservers/Wayland/input.c +++ b/client/displayservers/Wayland/input.c @@ -357,6 +357,24 @@ void waylandUngrabPointer(void) } } +void waylandCapturePointer(void) +{ + waylandGrabPointer(); +} + +void waylandUncapturePointer(void) +{ + /* 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()) + waylandUngrabPointer(); +} + void waylandGrabKeyboard(void) { if (wlWm.keyboardInhibitManager && !wlWm.keyboardInhibitor) diff --git a/client/displayservers/Wayland/wayland.c b/client/displayservers/Wayland/wayland.c index 00e55329..e4821293 100644 --- a/client/displayservers/Wayland/wayland.c +++ b/client/displayservers/Wayland/wayland.c @@ -164,6 +164,8 @@ struct LG_DisplayServerOps LGDS_Wayland = .showPointer = waylandShowPointer, .grabPointer = waylandGrabPointer, .ungrabPointer = waylandUngrabPointer, + .capturePointer = waylandCapturePointer, + .uncapturePointer = waylandUncapturePointer, .grabKeyboard = waylandGrabKeyboard, .ungrabKeyboard = waylandUngrabKeyboard, .warpPointer = waylandWarpPointer, diff --git a/client/displayservers/Wayland/wayland.h b/client/displayservers/Wayland/wayland.h index fdd9899f..4d149e53 100644 --- a/client/displayservers/Wayland/wayland.h +++ b/client/displayservers/Wayland/wayland.h @@ -225,6 +225,8 @@ void waylandGrabKeyboard(void); void waylandGrabPointer(void); void waylandUngrabKeyboard(void); void waylandUngrabPointer(void); +void waylandCapturePointer(void); +void waylandUncapturePointer(void); void waylandRealignPointer(void); void waylandWarpPointer(int x, int y, bool exiting); void waylandGuestPointerUpdated(double x, double y, int localX, int localY); diff --git a/client/displayservers/X11/x11.c b/client/displayservers/X11/x11.c index 4a82641e..7792c7f2 100644 --- a/client/displayservers/X11/x11.c +++ b/client/displayservers/X11/x11.c @@ -1063,6 +1063,23 @@ static void x11UngrabPointer(void) x11.pointerGrabbed = false; } +static void x11CapturePointer(void) +{ + x11GrabPointer(); +} + +static void x11UncapturePointer(void) +{ + /* we need to ungrab the pointer on the following conditions when exiting capture mode: + * - if the format is invalid as we do not know where the guest cursor is, + * which breaks edge detection as the cursor can not be warped out of the + * window when we release it. + * - if the user has opted to use captureInputOnly mode. + */ + if (!app_isFormatValid() || app_isCaptureOnlyMode()) + x11UngrabPointer(); +} + static void x11GrabKeyboard(void) { if (x11.keyboardGrabbed) @@ -1224,6 +1241,8 @@ struct LG_DisplayServerOps LGDS_X11 = .showPointer = x11ShowPointer, .grabPointer = x11GrabPointer, .ungrabPointer = x11UngrabPointer, + .capturePointer = x11CapturePointer, + .uncapturePointer = x11UncapturePointer, .grabKeyboard = x11GrabKeyboard, .ungrabKeyboard = x11UngrabKeyboard, .warpPointer = x11WarpPointer, diff --git a/client/include/app.h b/client/include/app.h index 4f806003..360382f3 100644 --- a/client/include/app.h +++ b/client/include/app.h @@ -38,6 +38,8 @@ LG_MsgAlert; bool app_isRunning(void); bool app_inputEnabled(void); bool app_isCaptureMode(void); +bool app_isCaptureOnlyMode(void); +bool app_isFormatValid(void); void app_updateCursorPos(double x, double y); void app_updateWindowPos(int x, int y); void app_handleResizeEvent(int w, int h, double scale, const struct Border border); diff --git a/client/include/interface/displayserver.h b/client/include/interface/displayserver.h index 17212b83..bc7b5119 100644 --- a/client/include/interface/displayserver.h +++ b/client/include/interface/displayserver.h @@ -131,10 +131,14 @@ struct LG_DisplayServerOps /* dm specific cursor implementations */ void (*guestPointerUpdated)(double x, double y, int localX, int localY); void (*showPointer)(bool show); - void (*grabPointer)(); - void (*ungrabPointer)(); void (*grabKeyboard)(); void (*ungrabKeyboard)(); + /* (un)grabPointer is used to toggle cursor tracking/confine in normal mode */ + void (*grabPointer)(); + void (*ungrabPointer)(); + /* (un)capturePointer is used do toggle special cursor tracking in capture mode */ + void (*capturePointer)(); + void (*uncapturePointer)(); /* exiting = true if the warp is to leave the window */ void (*warpPointer)(int x, int y, bool exiting); @@ -199,6 +203,8 @@ struct LG_DisplayServerOps assert((x)->showPointer ); \ assert((x)->grabPointer ); \ assert((x)->ungrabPointer ); \ + assert((x)->capturePointer ); \ + assert((x)->uncapturePointer ); \ assert((x)->warpPointer ); \ assert((x)->realignPointer ); \ assert((x)->isValidPointerPos ); \ diff --git a/client/src/app.c b/client/src/app.c index fbf78f48..96e6a14e 100644 --- a/client/src/app.c +++ b/client/src/app.c @@ -46,6 +46,16 @@ bool app_isCaptureMode(void) return g_cursor.grab; } +bool app_isCaptureOnlyMode(void) +{ + return g_params.captureInputOnly; +} + +bool app_isFormatValid(void) +{ + return g_state.formatValid; +} + void app_updateCursorPos(double x, double y) { g_cursor.pos.x = x; diff --git a/client/src/core.c b/client/src/core.c index 8a83a65b..247029d2 100644 --- a/client/src/core.c +++ b/client/src/core.c @@ -123,7 +123,7 @@ void core_setGrabQuiet(bool enable) if (g_params.grabKeyboard) g_state.ds->grabKeyboard(); - g_state.ds->grabPointer(); + g_state.ds->capturePointer(); } else { @@ -134,17 +134,7 @@ void core_setGrabQuiet(bool enable) g_state.ds->ungrabKeyboard(); } - /* we need to ungrab the pointer on the following conditions - * - if the backend does not support warp as 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 (warpSupport == LG_DS_WARP_NONE || !g_state.formatValid || - g_params.captureInputOnly) - g_state.ds->ungrabPointer(); + g_state.ds->uncapturePointer(); /* if exiting capture when input on capture only we need to align the local * cursor to the guest's location before it is shown. */