mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-14 21:17:54 +00:00
[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:
parent
d86014e5ff
commit
270631f1b9
4 changed files with 109 additions and 64 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue