[client] ds: add surface-only warp variant

This commit converts the output of ds->getProp(LG_DS_WARP_SUPPORT) to
an enum containing three items:

* LG_DS_WARP_NONE: warp is not supported at all
* LG_DS_WARP_SURFACE: warp is possible, but only inside the window
* LG_DS_WARP_SCREEN: warp is possible anywhere on the screen

LG_DS_WARP_NONE corresponds to the old false return value, and
LG_DS_WARP_SCREEN corresponds to the old true return value.

LG_DS_WARP_SURFACE is designed for Wayland, where warping is possible,
but only in our window. In this case, since we cannot warp outside
the window, we can warp the cursor to the edge when we attempt to exit.
If the cursor leaves, the normal leave routine gets called, and the
cursor disappears. If the cursor does not end up leaving, we grab it
again.
This commit is contained in:
Quantum 2021-02-15 19:40:44 -05:00 committed by Geoffrey McRae
parent d86014e5ff
commit 270631f1b9
4 changed files with 109 additions and 64 deletions

View File

@ -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;
}

View File

@ -449,9 +449,14 @@ static void x11Free(void)
static bool x11GetProp(LG_DSProperty prop, void *ret)
{
if (prop != LG_DS_MAX_MULTISAMPLE)
return false;
switch (prop)
{
case LG_DS_WARP_SUPPORT:
*(enum LG_DSWarpSupport*)ret = LG_DS_WARP_SCREEN;
return true;
case LG_DS_MAX_MULTISAMPLE:
{
Display * dpy = XOpenDisplay(NULL);
if (!dpy)
return false;
@ -495,6 +500,11 @@ static bool x11GetProp(LG_DSProperty prop, void *ret)
*(int*)ret = maxSamples;
return true;
}
default:
return true;
}
}
static int x11EventThread(void * unused)

View File

@ -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;

View File

@ -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,6 +425,20 @@ 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);
switch (warpSupport)
{
case LG_DS_WARP_NONE:
break;
case LG_DS_WARP_SURFACE:
g_state.ds->ungrabPointer();
core_warpPointer(tx, ty, true);
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))
@ -435,6 +456,13 @@ void core_handleMouseNormal(double ex, double ey)
}
}
}
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;
util_cursorToInt(ex, ey, &x, &y);