diff --git a/client/displayservers/Wayland/wayland.c b/client/displayservers/Wayland/wayland.c index 864886ed..e6951e05 100644 --- a/client/displayservers/Wayland/wayland.c +++ b/client/displayservers/Wayland/wayland.c @@ -1015,7 +1015,7 @@ static bool waylandGetProp(LG_DSProperty prop, void * ret) { if (prop == LG_DS_WARP_SUPPORT) { - *(bool*)ret = false; + *(enum LG_DSWarpSupport*)ret = LG_DS_WARP_NONE; return true; } diff --git a/client/displayservers/X11/x11.c b/client/displayservers/X11/x11.c index 09d5a18a..ab5ca01f 100644 --- a/client/displayservers/X11/x11.c +++ b/client/displayservers/X11/x11.c @@ -449,52 +449,62 @@ static void x11Free(void) static bool x11GetProp(LG_DSProperty prop, void *ret) { - if (prop != LG_DS_MAX_MULTISAMPLE) - return false; - - Display * dpy = XOpenDisplay(NULL); - if (!dpy) - return false; - - XVisualInfo queryTemplate; - queryTemplate.screen = 0; - - int visualCount; - int maxSamples = -1; - XVisualInfo * visuals = XGetVisualInfo(dpy, VisualScreenMask, - &queryTemplate, &visualCount); - - for (int i = 0; i < visualCount; i++) + switch (prop) { - XVisualInfo * visual = &visuals[i]; + case LG_DS_WARP_SUPPORT: + *(enum LG_DSWarpSupport*)ret = LG_DS_WARP_SCREEN; + return true; - int res, supportsGL; - // Some GLX visuals do not use GL, and these must be ignored in our search. - if ((res = glXGetConfig(dpy, visual, GLX_USE_GL, &supportsGL)) != 0 || - !supportsGL) - continue; + case LG_DS_MAX_MULTISAMPLE: + { + Display * dpy = XOpenDisplay(NULL); + if (!dpy) + return false; - int sampleBuffers, samples; - if ((res = glXGetConfig(dpy, visual, GLX_SAMPLE_BUFFERS, &sampleBuffers)) != 0) - continue; + XVisualInfo queryTemplate; + queryTemplate.screen = 0; - // Will be 1 if this visual supports multisampling - if (sampleBuffers != 1) - continue; + int visualCount; + int maxSamples = -1; + XVisualInfo * visuals = XGetVisualInfo(dpy, VisualScreenMask, + &queryTemplate, &visualCount); - if ((res = glXGetConfig(dpy, visual, GLX_SAMPLES, &samples)) != 0) - continue; + for (int i = 0; i < visualCount; i++) + { + XVisualInfo * visual = &visuals[i]; - // Track the largest number of samples supported - if (samples > maxSamples) - maxSamples = samples; + int res, supportsGL; + // Some GLX visuals do not use GL, and these must be ignored in our search. + if ((res = glXGetConfig(dpy, visual, GLX_USE_GL, &supportsGL)) != 0 || + !supportsGL) + continue; + + int sampleBuffers, samples; + if ((res = glXGetConfig(dpy, visual, GLX_SAMPLE_BUFFERS, &sampleBuffers)) != 0) + continue; + + // Will be 1 if this visual supports multisampling + if (sampleBuffers != 1) + continue; + + if ((res = glXGetConfig(dpy, visual, GLX_SAMPLES, &samples)) != 0) + continue; + + // Track the largest number of samples supported + if (samples > maxSamples) + maxSamples = samples; + } + + XFree(visuals); + XCloseDisplay(dpy); + + *(int*)ret = maxSamples; + return true; + } + + default: + return true; } - - XFree(visuals); - XCloseDisplay(dpy); - - *(int*)ret = maxSamples; - return true; } static int x11EventThread(void * unused) diff --git a/client/include/interface/displayserver.h b/client/include/interface/displayserver.h index ad5d5349..d3cf16d4 100644 --- a/client/include/interface/displayserver.h +++ b/client/include/interface/displayserver.h @@ -53,6 +53,13 @@ typedef enum LG_DSProperty } LG_DSProperty; +enum LG_DSWarpSupport +{ + LG_DS_WARP_NONE, + LG_DS_WARP_SURFACE, + LG_DS_WARP_SCREEN, +}; + typedef struct LG_DSInitParams { const char * title; diff --git a/client/src/core.c b/client/src/core.c index f026d163..60918aa3 100644 --- a/client/src/core.c +++ b/client/src/core.c @@ -57,7 +57,7 @@ void core_setCursorInView(bool enable) /* if the display server does not support warp, then we can not operate in * always relative mode and we should not grab the pointer */ - bool warpSupport = true; + enum LG_DSWarpSupport warpSupport = LG_DS_WARP_NONE; app_getProp(LG_DS_WARP_SUPPORT, &warpSupport); g_cursor.warpState = enable ? WARP_STATE_ON : WARP_STATE_OFF; @@ -67,7 +67,7 @@ void core_setCursorInView(bool enable) if (g_params.hideMouse) g_state.ds->showPointer(false); - if (warpSupport && !g_params.captureInputOnly) + if (warpSupport != LG_DS_WARP_NONE && !g_params.captureInputOnly) g_state.ds->grabPointer(); if (g_params.grabKeyboardOnFocus) @@ -78,7 +78,7 @@ void core_setCursorInView(bool enable) if (g_params.hideMouse) g_state.ds->showPointer(true); - if (warpSupport) + if (warpSupport != LG_DS_WARP_NONE) g_state.ds->ungrabPointer(); g_state.ds->ungrabKeyboard(); @@ -112,7 +112,7 @@ void core_setGrabQuiet(bool enable) /* if the display server does not support warp we need to ungrab the pointer * here instead of in the move handler */ - bool warpSupport = true; + enum LG_DSWarpSupport warpSupport = LG_DS_WARP_NONE; app_getProp(LG_DS_WARP_SUPPORT, &warpSupport); if (enable) @@ -134,7 +134,7 @@ void core_setGrabQuiet(bool enable) g_state.ds->ungrabKeyboard(); } - if (!warpSupport || g_params.captureInputOnly || !g_state.formatValid) + if (warpSupport != LG_DS_WARP_NONE || g_params.captureInputOnly || !g_state.formatValid) g_state.ds->ungrabPointer(); // if exiting capture when input on capture only, we want to show the cursor @@ -328,6 +328,15 @@ void core_handleMouseGrabbed(double ex, double ey) DEBUG_ERROR("failed to send mouse motion message"); } +static bool isInView(void) +{ + return + 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; +} + void core_handleMouseNormal(double ex, double ey) { // prevent cursor handling outside of capture if the position is not known @@ -340,19 +349,14 @@ void core_handleMouseNormal(double ex, double ey) /* scale the movement to the guest */ if (g_cursor.useScale && g_params.scaleMouseInput) { - ex *= g_cursor.scale.x / g_cursor.dpiScale; - ey *= g_cursor.scale.y / g_cursor.dpiScale; + ex *= g_cursor.scale.x; + ey *= g_cursor.scale.y; } bool testExit = true; if (!g_cursor.inView) { - 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; - + const bool inView = isInView(); core_setCursorInView(inView); if (inView) g_cursor.realign = true; @@ -398,6 +402,9 @@ void core_handleMouseNormal(double ex, double ey) if (testExit) { + enum LG_DSWarpSupport warpSupport = LG_DS_WARP_NONE; + app_getProp(LG_DS_WARP_SUPPORT, &warpSupport); + /* translate the move to the guests orientation */ struct DoublePoint move = {.x = ex, .y = ey}; util_rotatePoint(&move); @@ -418,22 +425,43 @@ void core_handleMouseNormal(double ex, double ey) const int tx = (local.x <= 0.0) ? floor(local.x) : ceil(local.x); const int ty = (local.y <= 0.0) ? floor(local.y) : ceil(local.y); - if (core_isValidPointerPos( - g_state.windowPos.x + g_state.border.left + tx, - g_state.windowPos.y + g_state.border.top + ty)) + switch (warpSupport) { - core_setCursorInView(false); + case LG_DS_WARP_NONE: + break; - /* preempt the window leave flag if the warp will leave our window */ - if (tx < 0 || ty < 0 || tx > g_state.windowW || ty > g_state.windowH) - g_cursor.inWindow = false; + case LG_DS_WARP_SURFACE: + g_state.ds->ungrabPointer(); + core_warpPointer(tx, ty, true); - /* ungrab the pointer and move the local cursor to the exit point */ - g_state.ds->ungrabPointer(); - core_warpPointer(tx, ty, true); - return; + if (!isInView() && tx >= 0 && tx < g_state.windowW && ty >= 0 && ty < g_state.windowH) + core_setCursorInView(false); + break; + + case LG_DS_WARP_SCREEN: + if (core_isValidPointerPos( + g_state.windowPos.x + g_state.border.left + tx, + g_state.windowPos.y + g_state.border.top + ty)) + { + core_setCursorInView(false); + + /* preempt the window leave flag if the warp will leave our window */ + if (tx < 0 || ty < 0 || tx > g_state.windowW || ty > g_state.windowH) + g_cursor.inWindow = false; + + /* ungrab the pointer and move the local cursor to the exit point */ + g_state.ds->ungrabPointer(); + core_warpPointer(tx, ty, true); + return; + } } } + else if (warpSupport == LG_DS_WARP_SURFACE && isInView()) + { + /* regrab the pointer in case the user did not move off the surface */ + g_state.ds->grabPointer(); + g_cursor.warpState = WARP_STATE_ON; + } } int x, y;