mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 00:31:31 +00:00
[client] input: track pointer confinement state
This commit is contained in:
@@ -196,6 +196,9 @@ static void confinedHandler(void * data,
|
||||
atomic_store_explicit(&wlWm.confActive, true, memory_order_release);
|
||||
LG_UNLOCK(wlWm.surfaceLock);
|
||||
MTRACE("conf active=1 id=%u valid=%d", proxyId(pointer), valid);
|
||||
|
||||
if (valid)
|
||||
app_handleGrabEvent(true);
|
||||
}
|
||||
|
||||
static void unconfinedHandler(void * data,
|
||||
@@ -208,6 +211,9 @@ static void unconfinedHandler(void * data,
|
||||
atomic_store_explicit(&wlWm.confActive, false, memory_order_release);
|
||||
LG_UNLOCK(wlWm.surfaceLock);
|
||||
MTRACE("conf active=0 id=%u valid=%d", proxyId(pointer), valid);
|
||||
|
||||
if (valid)
|
||||
app_handleGrabEvent(false);
|
||||
}
|
||||
|
||||
static const struct zwp_confined_pointer_v1_listener confinedListener = {
|
||||
@@ -215,6 +221,65 @@ static const struct zwp_confined_pointer_v1_listener confinedListener = {
|
||||
.unconfined = unconfinedHandler,
|
||||
};
|
||||
|
||||
static struct zwp_confined_pointer_v1 * createConfine(
|
||||
struct wl_region * region);
|
||||
static bool queueConfSync(void);
|
||||
|
||||
static void confSyncHandler(void * data, struct wl_callback * callback,
|
||||
uint32_t serial)
|
||||
{
|
||||
bool notify = false;
|
||||
bool valid = false;
|
||||
const uint32_t id = proxyId(callback);
|
||||
uint32_t confId = 0;
|
||||
uint64_t confSeq = 0;
|
||||
|
||||
LG_LOCK(wlWm.surfaceLock);
|
||||
if (callback == wlWm.confSync)
|
||||
{
|
||||
valid = true;
|
||||
wl_callback_destroy(callback);
|
||||
wlWm.confSync = NULL;
|
||||
atomic_store_explicit(&wlWm.confActive, false,
|
||||
memory_order_release);
|
||||
notify = wlWm.inputLive;
|
||||
|
||||
if (wlWm.inputLive && wlWm.confReq && wlWm.pointer &&
|
||||
wlWm.pointerConstraints && !wlWm.confinedPointer &&
|
||||
!wlWm.lockedPointer)
|
||||
{
|
||||
wlWm.confinedPointer = createConfine(NULL);
|
||||
confId = proxyId(wlWm.confinedPointer);
|
||||
confSeq = app_mouseSeq();
|
||||
}
|
||||
}
|
||||
LG_UNLOCK(wlWm.surfaceLock);
|
||||
|
||||
MTRACE("conf sync id=%u serial=%u valid=%d notify=%d", id, serial,
|
||||
valid, notify);
|
||||
MLOG(confSeq, "conf req id=%u why=sync", confId);
|
||||
|
||||
if (notify)
|
||||
app_handleGrabEvent(false);
|
||||
}
|
||||
|
||||
static const struct wl_callback_listener confSyncListener = {
|
||||
.done = confSyncHandler,
|
||||
};
|
||||
|
||||
static bool queueConfSync(void)
|
||||
{
|
||||
if (wlWm.confSync)
|
||||
return true;
|
||||
|
||||
wlWm.confSync = wl_display_sync(wlWm.display);
|
||||
if (!wlWm.confSync)
|
||||
return false;
|
||||
|
||||
wl_callback_add_listener(wlWm.confSync, &confSyncListener, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void lockedHandler(void * data,
|
||||
struct zwp_locked_pointer_v1 * pointer)
|
||||
{
|
||||
@@ -437,14 +502,21 @@ static const struct wl_keyboard_listener keyboardListener = {
|
||||
.modifiers = keyboardModifiersHandler,
|
||||
};
|
||||
|
||||
static void waylandCleanUpPointer(void)
|
||||
static void waylandCleanUpPointer(bool notify)
|
||||
{
|
||||
bool event = false;
|
||||
uint32_t lockId = 0;
|
||||
uint32_t confId = 0;
|
||||
uint64_t lockSeq = 0;
|
||||
uint64_t confSeq = 0;
|
||||
INTERLOCKED_SECTION(wlWm.surfaceLock,
|
||||
{
|
||||
if (wlWm.confSync)
|
||||
{
|
||||
wl_callback_destroy(wlWm.confSync);
|
||||
wlWm.confSync = NULL;
|
||||
}
|
||||
|
||||
atomic_store_explicit(&wlWm.lockActive, false, memory_order_release);
|
||||
atomic_store_explicit(&wlWm.confActive, false, memory_order_release);
|
||||
|
||||
@@ -463,19 +535,25 @@ static void waylandCleanUpPointer(void)
|
||||
wlWm.confinedPointer = NULL;
|
||||
confSeq = app_mouseSeq();
|
||||
}
|
||||
|
||||
if (wlWm.relativePointer)
|
||||
{
|
||||
zwp_relative_pointer_v1_destroy(wlWm.relativePointer);
|
||||
wlWm.relativePointer = NULL;
|
||||
}
|
||||
|
||||
wl_pointer_destroy(wlWm.pointer);
|
||||
wlWm.pointer = NULL;
|
||||
wlWm.pointerInSurface = false;
|
||||
|
||||
event = notify && wlWm.inputLive;
|
||||
});
|
||||
|
||||
MLOG(lockSeq, "lock destroy id=%u why=pointer", lockId);
|
||||
MLOG(confSeq, "conf destroy id=%u why=pointer", confId);
|
||||
|
||||
if (wlWm.relativePointer)
|
||||
{
|
||||
zwp_relative_pointer_v1_destroy(wlWm.relativePointer);
|
||||
wlWm.relativePointer = NULL;
|
||||
}
|
||||
|
||||
wl_pointer_destroy(wlWm.pointer);
|
||||
wlWm.pointer = NULL;
|
||||
if (event)
|
||||
app_handleGrabEvent(false);
|
||||
}
|
||||
|
||||
// Seat-handling listeners.
|
||||
@@ -484,7 +562,7 @@ static void handlePointerCapability(uint32_t capabilities)
|
||||
{
|
||||
bool hasPointer = capabilities & WL_SEAT_CAPABILITY_POINTER;
|
||||
if (!hasPointer && wlWm.pointer)
|
||||
waylandCleanUpPointer();
|
||||
waylandCleanUpPointer(true);
|
||||
else if (hasPointer && !wlWm.pointer)
|
||||
{
|
||||
wlWm.pointer = wl_seat_get_pointer(wlWm.seat);
|
||||
@@ -502,6 +580,16 @@ static void handlePointerCapability(uint32_t capabilities)
|
||||
|
||||
if (app_isCaptureMode())
|
||||
waylandCapturePointer();
|
||||
else
|
||||
{
|
||||
bool confReq;
|
||||
INTERLOCKED_SECTION(wlWm.surfaceLock,
|
||||
{
|
||||
confReq = wlWm.confReq;
|
||||
});
|
||||
if (confReq)
|
||||
waylandGrabPointer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,6 +666,10 @@ bool waylandInputInit(bool allowNoInput)
|
||||
wlWm.warpSupport, !!wlWm.relativePointerManager,
|
||||
!!wlWm.pointerConstraints);
|
||||
|
||||
LG_LOCK(wlWm.surfaceLock);
|
||||
wlWm.inputLive = true;
|
||||
LG_UNLOCK(wlWm.surfaceLock);
|
||||
|
||||
wlWm.xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
if (!wlWm.xkb)
|
||||
DEBUG_WARN("Failed to initialize xkb, keyboard input will not work");
|
||||
@@ -590,13 +682,15 @@ bool waylandInputInit(bool allowNoInput)
|
||||
|
||||
void waylandInputFree(void)
|
||||
{
|
||||
LG_LOCK(wlWm.surfaceLock);
|
||||
wlWm.inputLive = false;
|
||||
LG_UNLOCK(wlWm.surfaceLock);
|
||||
|
||||
if (!wlWm.seat)
|
||||
return;
|
||||
|
||||
waylandUngrabPointer();
|
||||
|
||||
if (wlWm.pointer)
|
||||
waylandCleanUpPointer();
|
||||
waylandCleanUpPointer(false);
|
||||
|
||||
// The only legal way the keyboard can be null is if it never existed.
|
||||
// When unplugged, the compositor must have an inert object.
|
||||
@@ -617,59 +711,56 @@ void waylandInputFree(void)
|
||||
|
||||
void waylandGrabPointer(void)
|
||||
{
|
||||
if (!wlWm.pointer ||
|
||||
!wlWm.relativePointerManager || !wlWm.pointerConstraints)
|
||||
{
|
||||
MTRACE("grab drop pointer=%d relMgr=%d constraints=%d",
|
||||
!!wlWm.pointer, !!wlWm.relativePointerManager,
|
||||
!!wlWm.pointerConstraints);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wlWm.warpSupport && !wlWm.relativePointer)
|
||||
{
|
||||
struct zwp_relative_pointer_v1 * relative =
|
||||
zwp_relative_pointer_manager_v1_get_relative_pointer(
|
||||
wlWm.relativePointerManager, wlWm.pointer);
|
||||
zwp_relative_pointer_v1_add_listener(relative,
|
||||
&relativePointerListener, NULL);
|
||||
const uint32_t relativeId = proxyId(relative);
|
||||
wlWm.relativePointer = relative;
|
||||
MTRACE("rel req id=%u why=grab", relativeId);
|
||||
}
|
||||
|
||||
uint32_t confId = 0;
|
||||
uint64_t confSeq = 0;
|
||||
bool haveConf = false;
|
||||
bool haveLock = false;
|
||||
uint32_t relativeId = 0;
|
||||
uint32_t confId = 0;
|
||||
uint64_t confSeq = 0;
|
||||
bool haveConf = false;
|
||||
bool haveLock = false;
|
||||
bool haveSync = false;
|
||||
bool havePointer = false;
|
||||
bool haveConstraints = false;
|
||||
INTERLOCKED_SECTION(wlWm.surfaceLock,
|
||||
{
|
||||
if (!wlWm.confinedPointer && !wlWm.lockedPointer)
|
||||
wlWm.confReq = true;
|
||||
|
||||
if (wlWm.pointer && !wlWm.warpSupport && !wlWm.relativePointer &&
|
||||
wlWm.relativePointerManager)
|
||||
{
|
||||
wlWm.relativePointer =
|
||||
zwp_relative_pointer_manager_v1_get_relative_pointer(
|
||||
wlWm.relativePointerManager, wlWm.pointer);
|
||||
zwp_relative_pointer_v1_add_listener(wlWm.relativePointer,
|
||||
&relativePointerListener, NULL);
|
||||
relativeId = proxyId(wlWm.relativePointer);
|
||||
}
|
||||
|
||||
if (wlWm.pointer && wlWm.pointerConstraints &&
|
||||
!wlWm.confinedPointer && !wlWm.lockedPointer && !wlWm.confSync)
|
||||
{
|
||||
atomic_store_explicit(&wlWm.confActive, false,
|
||||
memory_order_release);
|
||||
wlWm.confinedPointer = createConfine(NULL);
|
||||
confId = proxyId(wlWm.confinedPointer);
|
||||
confSeq = app_mouseSeq();
|
||||
}
|
||||
haveConf = !!wlWm.confinedPointer;
|
||||
haveLock = !!wlWm.lockedPointer;
|
||||
haveConf = !!wlWm.confinedPointer;
|
||||
haveLock = !!wlWm.lockedPointer;
|
||||
haveSync = !!wlWm.confSync;
|
||||
havePointer = !!wlWm.pointer;
|
||||
haveConstraints = !!wlWm.pointerConstraints;
|
||||
});
|
||||
|
||||
if (relativeId)
|
||||
MTRACE("rel req id=%u why=grab", relativeId);
|
||||
|
||||
if (confId)
|
||||
MLOG(confSeq, "conf req id=%u why=grab", confId);
|
||||
else
|
||||
MTRACE("conf skip conf=%d lock=%d", haveConf, haveLock);
|
||||
MTRACE("conf skip pointer=%d constraints=%d conf=%d lock=%d sync=%d",
|
||||
havePointer, haveConstraints, haveConf, haveLock, haveSync);
|
||||
}
|
||||
|
||||
inline static uint32_t internalUngrabPointer(bool lock, uint64_t * traceSeq)
|
||||
inline static uint32_t destroyConfine(uint64_t * traceSeq)
|
||||
{
|
||||
*traceSeq = 0;
|
||||
if (!wlWm.pointer)
|
||||
return 0;
|
||||
|
||||
if (lock)
|
||||
LG_LOCK(wlWm.surfaceLock);
|
||||
|
||||
uint32_t confId = 0;
|
||||
if (wlWm.confinedPointer)
|
||||
@@ -679,34 +770,57 @@ inline static uint32_t internalUngrabPointer(bool lock, uint64_t * traceSeq)
|
||||
wlWm.confinedPointer = NULL;
|
||||
atomic_store_explicit(&wlWm.confActive, false, memory_order_release);
|
||||
*traceSeq = app_mouseSeq();
|
||||
}
|
||||
|
||||
if (lock)
|
||||
LG_UNLOCK(wlWm.surfaceLock);
|
||||
|
||||
if (!wlWm.warpSupport)
|
||||
{
|
||||
if (!wlWm.relativePointer)
|
||||
{
|
||||
wlWm.relativePointer =
|
||||
zwp_relative_pointer_manager_v1_get_relative_pointer(
|
||||
wlWm.relativePointerManager, wlWm.pointer);
|
||||
zwp_relative_pointer_v1_add_listener(wlWm.relativePointer,
|
||||
&relativePointerListener, NULL);
|
||||
}
|
||||
|
||||
app_resyncMouseBasic();
|
||||
app_handleMouseBasic();
|
||||
if (!queueConfSync())
|
||||
DEBUG_ERROR("Failed to queue pointer release sync");
|
||||
}
|
||||
|
||||
return confId;
|
||||
}
|
||||
|
||||
static void ungrabBasic(void)
|
||||
{
|
||||
if (wlWm.warpSupport)
|
||||
return;
|
||||
|
||||
uint32_t relativeId = 0;
|
||||
LG_LOCK(wlWm.surfaceLock);
|
||||
if (wlWm.pointer && !wlWm.relativePointer &&
|
||||
wlWm.relativePointerManager)
|
||||
{
|
||||
wlWm.relativePointer =
|
||||
zwp_relative_pointer_manager_v1_get_relative_pointer(
|
||||
wlWm.relativePointerManager, wlWm.pointer);
|
||||
zwp_relative_pointer_v1_add_listener(wlWm.relativePointer,
|
||||
&relativePointerListener, NULL);
|
||||
relativeId = proxyId(wlWm.relativePointer);
|
||||
}
|
||||
LG_UNLOCK(wlWm.surfaceLock);
|
||||
|
||||
if (relativeId)
|
||||
MTRACE("rel req id=%u why=ungrab", relativeId);
|
||||
|
||||
app_resyncMouseBasic();
|
||||
app_handleMouseBasic();
|
||||
}
|
||||
|
||||
void waylandUngrabPointer(void)
|
||||
{
|
||||
bool notify;
|
||||
uint64_t confSeq;
|
||||
const uint32_t confId = internalUngrabPointer(true, &confSeq);
|
||||
uint32_t confId;
|
||||
|
||||
LG_LOCK(wlWm.surfaceLock);
|
||||
wlWm.confReq = false;
|
||||
confId = destroyConfine(&confSeq);
|
||||
notify = !wlWm.confSync && wlWm.inputLive;
|
||||
LG_UNLOCK(wlWm.surfaceLock);
|
||||
|
||||
MLOG(confSeq, "conf destroy id=%u why=ungrab", confId);
|
||||
ungrabBasic();
|
||||
|
||||
if (notify)
|
||||
app_handleGrabEvent(false);
|
||||
}
|
||||
|
||||
void waylandCapturePointer(void)
|
||||
@@ -724,20 +838,17 @@ void waylandCapturePointer(void)
|
||||
uint64_t lockSeq = 0;
|
||||
INTERLOCKED_SECTION(wlWm.surfaceLock,
|
||||
{
|
||||
if (wlWm.confinedPointer)
|
||||
{
|
||||
confId = proxyId(wlWm.confinedPointer);
|
||||
zwp_confined_pointer_v1_destroy(wlWm.confinedPointer);
|
||||
wlWm.confinedPointer = NULL;
|
||||
atomic_store_explicit(&wlWm.confActive, false,
|
||||
memory_order_release);
|
||||
confSeq = app_mouseSeq();
|
||||
}
|
||||
wlWm.confReq = true;
|
||||
confId = destroyConfine(&confSeq);
|
||||
|
||||
atomic_store_explicit(&wlWm.lockActive, false, memory_order_release);
|
||||
wlWm.lockedPointer = createLock();
|
||||
lockId = proxyId(wlWm.lockedPointer);
|
||||
lockSeq = app_mouseSeq();
|
||||
if (wlWm.pointer && !wlWm.lockedPointer)
|
||||
{
|
||||
atomic_store_explicit(&wlWm.lockActive, false,
|
||||
memory_order_release);
|
||||
wlWm.lockedPointer = createLock();
|
||||
lockId = proxyId(wlWm.lockedPointer);
|
||||
lockSeq = app_mouseSeq();
|
||||
}
|
||||
});
|
||||
|
||||
MLOG(confSeq, "conf destroy id=%u why=capture", confId);
|
||||
@@ -772,20 +883,31 @@ void waylandUncapturePointer(void)
|
||||
* - if the user has opted to use captureInputOnly mode.
|
||||
*/
|
||||
if (!wlWm.warpSupport || !app_isFormatValid() || app_isCaptureOnlyMode())
|
||||
confDropId = internalUngrabPointer(false, &confDropSeq);
|
||||
else if (wlWm.pointer)
|
||||
{
|
||||
atomic_store_explicit(&wlWm.confActive, false,
|
||||
memory_order_release);
|
||||
wlWm.confinedPointer = createConfine(NULL);
|
||||
confReqId = proxyId(wlWm.confinedPointer);
|
||||
confReqSeq = app_mouseSeq();
|
||||
wlWm.confReq = false;
|
||||
confDropId = destroyConfine(&confDropSeq);
|
||||
}
|
||||
else
|
||||
{
|
||||
wlWm.confReq = true;
|
||||
if (wlWm.pointer && !wlWm.confSync && !wlWm.confinedPointer)
|
||||
{
|
||||
wlWm.confinedPointer = createConfine(NULL);
|
||||
confReqId = proxyId(wlWm.confinedPointer);
|
||||
confReqSeq = app_mouseSeq();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
MLOG(lockSeq, "lock destroy id=%u why=uncapture", lockId);
|
||||
MLOG(confDropSeq, "conf destroy id=%u why=uncapture", confDropId);
|
||||
MLOG(confReqSeq, "conf req id=%u why=uncapture", confReqId);
|
||||
ungrabBasic();
|
||||
}
|
||||
|
||||
bool waylandIsPointerGrabbed(void)
|
||||
{
|
||||
return atomic_load_explicit(&wlWm.confActive, memory_order_acquire);
|
||||
}
|
||||
|
||||
bool waylandIsPointerCaptured(void)
|
||||
|
||||
@@ -321,6 +321,7 @@ struct LG_DisplayServerOps LGDS_Wayland =
|
||||
.setPointer = waylandSetPointer,
|
||||
.grabPointer = waylandGrabPointer,
|
||||
.ungrabPointer = waylandUngrabPointer,
|
||||
.isPointerGrabbed = waylandIsPointerGrabbed,
|
||||
.capturePointer = waylandCapturePointer,
|
||||
.uncapturePointer = waylandUncapturePointer,
|
||||
.isPointerCaptured = waylandIsPointerCaptured,
|
||||
|
||||
@@ -195,6 +195,9 @@ struct WaylandDSState
|
||||
struct zwp_relative_pointer_v1 * relativePointer;
|
||||
struct zwp_confined_pointer_v1 * confinedPointer;
|
||||
struct zwp_locked_pointer_v1 * lockedPointer;
|
||||
struct wl_callback * confSync;
|
||||
bool confReq;
|
||||
bool inputLive;
|
||||
bool showPointer;
|
||||
uint32_t pointerEnterSerial;
|
||||
|
||||
@@ -379,6 +382,7 @@ void waylandUngrabKeyboard(void);
|
||||
void waylandUngrabPointer(void);
|
||||
void waylandCapturePointer(void);
|
||||
void waylandUncapturePointer(void);
|
||||
bool waylandIsPointerGrabbed(void);
|
||||
bool waylandIsPointerCaptured(void);
|
||||
void waylandRealignPointer(void);
|
||||
void waylandWarpPointer(int x, int y, bool exiting);
|
||||
|
||||
Reference in New Issue
Block a user