diff --git a/client/displayservers/Wayland/cursor.c b/client/displayservers/Wayland/cursor.c index c97b42ae..ca4e8925 100644 --- a/client/displayservers/Wayland/cursor.c +++ b/client/displayservers/Wayland/cursor.c @@ -106,3 +106,7 @@ void waylandShowPointer(bool show) wlWm.showPointer = show; wl_pointer_set_cursor(wlWm.pointer, wlWm.pointerEnterSerial, show ? wlWm.cursor : NULL, 0, 0); } + +void waylandGuestPointerUpdated(double x, double y, int localX, int localY) +{ +} diff --git a/client/displayservers/Wayland/wayland.c b/client/displayservers/Wayland/wayland.c index 3cf968e3..00e55329 100644 --- a/client/displayservers/Wayland/wayland.c +++ b/client/displayservers/Wayland/wayland.c @@ -138,43 +138,43 @@ static bool waylandGetProp(LG_DSProperty prop, void * ret) struct LG_DisplayServerOps LGDS_Wayland = { - .setup = waylandSetup, - .probe = waylandProbe, - .earlyInit = waylandEarlyInit, - .init = waylandInit, - .startup = waylandStartup, - .shutdown = waylandShutdown, - .free = waylandFree, - .getProp = waylandGetProp, + .setup = waylandSetup, + .probe = waylandProbe, + .earlyInit = waylandEarlyInit, + .init = waylandInit, + .startup = waylandStartup, + .shutdown = waylandShutdown, + .free = waylandFree, + .getProp = waylandGetProp, #ifdef ENABLE_EGL - .getEGLDisplay = waylandGetEGLDisplay, - .getEGLNativeWindow = waylandGetEGLNativeWindow, - .eglSwapBuffers = waylandEGLSwapBuffers, + .getEGLDisplay = waylandGetEGLDisplay, + .getEGLNativeWindow = waylandGetEGLNativeWindow, + .eglSwapBuffers = waylandEGLSwapBuffers, #endif #ifdef ENABLE_OPENGL - .glCreateContext = waylandGLCreateContext, - .glDeleteContext = waylandGLDeleteContext, - .glMakeCurrent = waylandGLMakeCurrent, - .glSetSwapInterval = waylandGLSetSwapInterval, - .glSwapBuffers = waylandGLSwapBuffers, + .glCreateContext = waylandGLCreateContext, + .glDeleteContext = waylandGLDeleteContext, + .glMakeCurrent = waylandGLMakeCurrent, + .glSetSwapInterval = waylandGLSetSwapInterval, + .glSwapBuffers = waylandGLSwapBuffers, #endif - - .showPointer = waylandShowPointer, - .grabPointer = waylandGrabPointer, - .ungrabPointer = waylandUngrabPointer, - .grabKeyboard = waylandGrabKeyboard, - .ungrabKeyboard = waylandUngrabKeyboard, - .warpPointer = waylandWarpPointer, - .realignPointer = waylandRealignPointer, - .isValidPointerPos = waylandIsValidPointerPos, - .inhibitIdle = waylandInhibitIdle, - .uninhibitIdle = waylandUninhibitIdle, - .wait = waylandWait, - .setWindowSize = waylandSetWindowSize, - .setFullscreen = waylandSetFullscreen, - .getFullscreen = waylandGetFullscreen, + .guestPointerUpdated = waylandGuestPointerUpdated, + .showPointer = waylandShowPointer, + .grabPointer = waylandGrabPointer, + .ungrabPointer = waylandUngrabPointer, + .grabKeyboard = waylandGrabKeyboard, + .ungrabKeyboard = waylandUngrabKeyboard, + .warpPointer = waylandWarpPointer, + .realignPointer = waylandRealignPointer, + .isValidPointerPos = waylandIsValidPointerPos, + .inhibitIdle = waylandInhibitIdle, + .uninhibitIdle = waylandUninhibitIdle, + .wait = waylandWait, + .setWindowSize = waylandSetWindowSize, + .setFullscreen = waylandSetFullscreen, + .getFullscreen = waylandGetFullscreen, .cbInit = waylandCBInit, .cbNotice = waylandCBNotice, diff --git a/client/displayservers/Wayland/wayland.h b/client/displayservers/Wayland/wayland.h index 19f0817c..b8ee071a 100644 --- a/client/displayservers/Wayland/wayland.h +++ b/client/displayservers/Wayland/wayland.h @@ -190,6 +190,7 @@ void waylandCBRelease(void); // cursor module bool waylandCursorInit(void); void waylandCursorFree(void); +void waylandGuestPointerUpdated(double x, double y, int localX, int localY); void waylandShowPointer(bool show); // gl module diff --git a/client/displayservers/X11/x11.c b/client/displayservers/X11/x11.c index f8f4bf36..642e2a70 100644 --- a/client/displayservers/X11/x11.c +++ b/client/displayservers/X11/x11.c @@ -41,6 +41,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "app.h" #include "common/debug.h" +#include "common/time.h" #define _NET_WM_STATE_REMOVE 0 #define _NET_WM_STATE_ADD 1 @@ -105,7 +106,8 @@ static bool x11Init(const LG_DSInitParams params) .event_mask = StructureNotifyMask | PropertyChangeMask | - ExposureMask + ExposureMask | + PointerMotionMask }; unsigned long swaMask = CWEventMask; @@ -677,6 +679,8 @@ static int x11EventThread(void * unused) static void x11GenericEvent(XGenericEventCookie *cookie) { + static int button_state = 0; + if (cookie->extension != x11.xinputOp) return; @@ -718,10 +722,10 @@ static void x11GenericEvent(XGenericEventCookie *cookie) case XI_Enter: { - if (x11.entered) + XIEnterEvent *xie = cookie->data; + if (x11.entered || xie->event != x11.window) return; - XIEnterEvent *xie = cookie->data; app_updateCursorPos(xie->event_x, xie->event_y); app_handleEnterEvent(true); x11.entered = true; @@ -730,10 +734,11 @@ static void x11GenericEvent(XGenericEventCookie *cookie) case XI_Leave: { - if (!x11.entered) + XILeaveEvent *xie = cookie->data; + if (!x11.entered || xie->event != x11.window || + button_state != 0 || app_isCaptureMode()) return; - XILeaveEvent *xie = cookie->data; app_updateCursorPos(xie->event_x, xie->event_y); app_handleEnterEvent(false); x11.entered = false; @@ -793,8 +798,9 @@ static void x11GenericEvent(XGenericEventCookie *cookie) if (raw->time == prev_time && raw->detail == prev_detail) return; - prev_time = raw->time; - prev_detail = raw->detail; + prev_time = raw->time; + prev_detail = raw->detail; + button_state |= (1 << raw->detail); app_handleButtonPress( raw->detail > 5 ? raw->detail - 2 : raw->detail); @@ -814,8 +820,9 @@ static void x11GenericEvent(XGenericEventCookie *cookie) if (raw->time == prev_time && raw->detail == prev_detail) return; - prev_time = raw->time; - prev_detail = raw->detail; + prev_time = raw->time; + prev_detail = raw->detail; + button_state &= ~(1 << raw->detail); app_handleButtonRelease( raw->detail > 5 ? raw->detail - 2 : raw->detail); @@ -957,6 +964,29 @@ static void x11GLSwapBuffers(void) } #endif +static void x11GuestPointerUpdated(double x, double y, int localX, int localY) +{ + if (app_isCaptureMode() || !x11.entered) + return; + + // avoid running too often + static uint64_t last_warp = 0; + uint64_t now = microtime(); + if (now - last_warp < 10000) + return; + last_warp = now; + + XIWarpPointer( + x11.display, + x11.pointerDev, + None, + x11.window, + 0, 0, 0, 0, + localX, localY); + + XSync(x11.display, False); +} + static void x11ShowPointer(bool show) { if (show) @@ -1000,6 +1030,8 @@ static void x11GrabPointer(void) XISetMask(mask.mask, XI_RawButtonRelease); XISetMask(mask.mask, XI_RawMotion ); XISetMask(mask.mask, XI_Motion ); + XISetMask(mask.mask, XI_Enter ); + XISetMask(mask.mask, XI_Leave ); Status ret = XIGrabDevice( x11.display, @@ -1189,20 +1221,21 @@ struct LG_DisplayServerOps LGDS_X11 = .glSetSwapInterval = x11GLSetSwapInterval, .glSwapBuffers = x11GLSwapBuffers, #endif - .showPointer = x11ShowPointer, - .grabPointer = x11GrabPointer, - .ungrabPointer = x11UngrabPointer, - .grabKeyboard = x11GrabKeyboard, - .ungrabKeyboard = x11UngrabKeyboard, - .warpPointer = x11WarpPointer, - .realignPointer = x11RealignPointer, - .isValidPointerPos = x11IsValidPointerPos, - .inhibitIdle = x11InhibitIdle, - .uninhibitIdle = x11UninhibitIdle, - .wait = x11Wait, - .setWindowSize = x11SetWindowSize, - .setFullscreen = x11SetFullscreen, - .getFullscreen = x11GetFullscreen, + .guestPointerUpdated = x11GuestPointerUpdated, + .showPointer = x11ShowPointer, + .grabPointer = x11GrabPointer, + .ungrabPointer = x11UngrabPointer, + .grabKeyboard = x11GrabKeyboard, + .ungrabKeyboard = x11UngrabKeyboard, + .warpPointer = x11WarpPointer, + .realignPointer = x11RealignPointer, + .isValidPointerPos = x11IsValidPointerPos, + .inhibitIdle = x11InhibitIdle, + .uninhibitIdle = x11UninhibitIdle, + .wait = x11Wait, + .setWindowSize = x11SetWindowSize, + .setFullscreen = x11SetFullscreen, + .getFullscreen = x11GetFullscreen, .cbInit = x11CBInit, .cbNotice = x11CBNotice, diff --git a/client/include/app.h b/client/include/app.h index 18962a16..4f806003 100644 --- a/client/include/app.h +++ b/client/include/app.h @@ -37,6 +37,7 @@ LG_MsgAlert; bool app_isRunning(void); bool app_inputEnabled(void); +bool app_isCaptureMode(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 fb451c29..17212b83 100644 --- a/client/include/interface/displayserver.h +++ b/client/include/interface/displayserver.h @@ -129,6 +129,7 @@ struct LG_DisplayServerOps #endif /* dm specific cursor implementations */ + void (*guestPointerUpdated)(double x, double y, int localX, int localY); void (*showPointer)(bool show); void (*grabPointer)(); void (*ungrabPointer)(); @@ -194,6 +195,7 @@ struct LG_DisplayServerOps ASSERT_OPENGL_FN((x)->glMakeCurrent ); \ ASSERT_OPENGL_FN((x)->glSetSwapInterval); \ ASSERT_OPENGL_FN((x)->glSwapBuffers ); \ + assert((x)->guestPointerUpdated); \ assert((x)->showPointer ); \ assert((x)->grabPointer ); \ assert((x)->ungrabPointer ); \ diff --git a/client/include/util.h b/client/include/util.h index 5296c60f..ed5f4f97 100644 --- a/client/include/util.h +++ b/client/include/util.h @@ -33,4 +33,11 @@ bool util_guestCurToLocal(struct DoublePoint *local); void util_localCurToGuest(struct DoublePoint *guest); void util_rotatePoint(struct DoublePoint *point); +static inline double util_clamp(double x, double min, double max) +{ + if (x < min) return min; + if (x > max) return max; + return x; +} + #endif diff --git a/client/src/app.c b/client/src/app.c index 72929978..fbf78f48 100644 --- a/client/src/app.c +++ b/client/src/app.c @@ -41,6 +41,11 @@ bool app_isRunning(void) g_state.state == APP_STATE_RESTART; } +bool app_isCaptureMode(void) +{ + return g_cursor.grab; +} + 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 8505f65f..8a83a65b 100644 --- a/client/src/core.c +++ b/client/src/core.c @@ -326,6 +326,17 @@ void core_stopFrameThread(void) g_state.frameThread = NULL; } +void core_handleGuestMouseUpdate(void) +{ + int x, y; + struct DoublePoint localPos; + util_guestCurToLocal(&localPos); + localPos.x = util_clamp(localPos.x, 0.0, g_state.dstRect.w); + localPos.y = util_clamp(localPos.y, 0.0, g_state.dstRect.h); + util_cursorToInt(localPos.x, localPos.y, &x, &y); + g_state.ds->guestPointerUpdated(g_cursor.guest.x, g_cursor.guest.y, x, y); +} + void core_handleMouseGrabbed(double ex, double ey) { if (!core_inputEnabled()) diff --git a/client/src/core.h b/client/src/core.h index 47e2d6bc..fe174d39 100644 --- a/client/src/core.h +++ b/client/src/core.h @@ -32,6 +32,7 @@ void core_alignToGuest(void); bool core_isValidPointerPos(int x, int y); bool core_startFrameThread(void); void core_stopFrameThread(void); +void core_handleGuestMouseUpdate(void); void core_handleMouseGrabbed(double ex, double ey); void core_handleMouseNormal(double ex, double ey); diff --git a/client/src/main.c b/client/src/main.c index 425a1156..b0471500 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -306,6 +306,9 @@ static int cursorThread(void * unused) core_alignToGuest(); app_resyncMouseBasic(); } + + // tell the DS there was an update + core_handleGuestMouseUpdate(); } lgmpClientMessageDone(queue);