mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 00:31:31 +00:00
[client] input: add cursor transition diagnostics
Add opt-in sequence-numbered tracing across the core and Wayland mouse paths.
This commit is contained in:
@@ -31,6 +31,16 @@
|
||||
|
||||
#include "common/debug.h"
|
||||
|
||||
#define MTRACE(fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
const uint64_t seq = app_mouseSeq(); \
|
||||
if (seq) \
|
||||
app_mouseTrace(__FILE__, __LINE__, __FUNCTION__, seq, \
|
||||
"wl.cursor." fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
static const uint32_t cursorBitmap[] = {
|
||||
0x000000, 0x000000, 0x000000, 0x000000,
|
||||
0x000000, 0xFFFFFF, 0xFFFFFF, 0x000000,
|
||||
@@ -184,6 +194,9 @@ void waylandCursorFree(void)
|
||||
void waylandCursorScaleChange(void)
|
||||
{
|
||||
int newScale = waylandScaleCeil(wlWm.scale);
|
||||
MTRACE("scale old=%d new=%d ratio=%d/%d pointer=%d",
|
||||
wlWm.cursorScale, newScale, wlWm.scale.num, wlWm.scale.den,
|
||||
wlWm.cursorId);
|
||||
if (newScale == wlWm.cursorScale)
|
||||
return;
|
||||
|
||||
@@ -191,7 +204,10 @@ void waylandCursorScaleChange(void)
|
||||
wlWm.cursorSize * newScale, wlWm.shm);
|
||||
|
||||
if (!new)
|
||||
{
|
||||
MTRACE("scale drop=theme new=%d", newScale);
|
||||
return;
|
||||
}
|
||||
|
||||
struct wl_surface * old[LG_POINTER_COUNT];
|
||||
memcpy(old, wlWm.cursors, sizeof(old));
|
||||
@@ -217,6 +233,9 @@ void waylandSetPointer(LG_DSPointer pointer)
|
||||
wlWm.cursor = wlWm.cursors[pointer];
|
||||
wlWm.cursorHotX = wlWm.cursorHot[pointer].x;
|
||||
wlWm.cursorHotY = wlWm.cursorHot[pointer].y;
|
||||
MTRACE("set id=%d surface=%p hot=%d,%d scale=%d entered=%d",
|
||||
pointer, (void *)wlWm.cursor, wlWm.cursorHotX, wlWm.cursorHotY,
|
||||
wlWm.cursorScale, wlWm.pointerInSurface);
|
||||
if (wlWm.pointer)
|
||||
wl_pointer_set_cursor(wlWm.pointer, wlWm.pointerEnterSerial, wlWm.cursor, wlWm.cursorHotX, wlWm.cursorHotY);
|
||||
}
|
||||
|
||||
@@ -35,13 +35,39 @@
|
||||
const double WL_SCROLL_STEP = 15.0;
|
||||
const double WL_HALF_SCROLL_STEP = WL_SCROLL_STEP / 2.0;
|
||||
|
||||
#define MTRACE(fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
const uint64_t seq = app_mouseSeq(); \
|
||||
if (seq) \
|
||||
app_mouseTrace(__FILE__, __LINE__, __FUNCTION__, seq, \
|
||||
"wl." fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define MLOG(seq, fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (seq) \
|
||||
app_mouseTrace(__FILE__, __LINE__, __FUNCTION__, seq, \
|
||||
"wl." fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
static uint32_t proxyId(void * proxy)
|
||||
{
|
||||
return proxy ? wl_proxy_get_id(proxy) : 0;
|
||||
}
|
||||
|
||||
// Mouse-handling listeners.
|
||||
|
||||
static void pointerMotionHandler(void * data, struct wl_pointer * pointer,
|
||||
uint32_t serial, wl_fixed_t sxW, wl_fixed_t syW)
|
||||
uint32_t time, wl_fixed_t sxW, wl_fixed_t syW)
|
||||
{
|
||||
wlWm.cursorX = wl_fixed_to_double(sxW);
|
||||
wlWm.cursorY = wl_fixed_to_double(syW);
|
||||
MTRACE("abs time=%u pos=%.3f,%.3f", time, wlWm.cursorX,
|
||||
wlWm.cursorY);
|
||||
app_updateCursorPos(wlWm.cursorX, wlWm.cursorY);
|
||||
|
||||
if (!wlWm.warpSupport && !wlWm.relativePointer)
|
||||
@@ -52,6 +78,10 @@ static void pointerEnterHandler(void * data, struct wl_pointer * pointer,
|
||||
uint32_t serial, struct wl_surface * surface, wl_fixed_t sxW,
|
||||
wl_fixed_t syW)
|
||||
{
|
||||
MTRACE("enter main=%d surface=%p serial=%u pos=%.3f,%.3f",
|
||||
surface == wlWm.surface, (void *)surface, serial,
|
||||
wl_fixed_to_double(sxW), wl_fixed_to_double(syW));
|
||||
|
||||
if (surface != wlWm.surface)
|
||||
return;
|
||||
|
||||
@@ -81,6 +111,9 @@ static void pointerEnterHandler(void * data, struct wl_pointer * pointer,
|
||||
static void pointerLeaveHandler(void * data, struct wl_pointer * pointer,
|
||||
uint32_t serial, struct wl_surface * surface)
|
||||
{
|
||||
MTRACE("leave main=%d surface=%p serial=%u",
|
||||
surface == wlWm.surface, (void *)surface, serial);
|
||||
|
||||
if (surface != wlWm.surface)
|
||||
return;
|
||||
|
||||
@@ -153,18 +186,79 @@ static const struct wl_pointer_listener pointerListener = {
|
||||
.axis = pointerAxisHandler,
|
||||
};
|
||||
|
||||
static void confinedHandler(void * data,
|
||||
struct zwp_confined_pointer_v1 * pointer)
|
||||
{
|
||||
MTRACE("conf active=1 id=%u", proxyId(pointer));
|
||||
}
|
||||
|
||||
static void unconfinedHandler(void * data,
|
||||
struct zwp_confined_pointer_v1 * pointer)
|
||||
{
|
||||
MTRACE("conf active=0 id=%u", proxyId(pointer));
|
||||
}
|
||||
|
||||
static const struct zwp_confined_pointer_v1_listener confinedListener = {
|
||||
.confined = confinedHandler,
|
||||
.unconfined = unconfinedHandler,
|
||||
};
|
||||
|
||||
static void lockedHandler(void * data,
|
||||
struct zwp_locked_pointer_v1 * pointer)
|
||||
{
|
||||
MTRACE("lock active=1 id=%u", proxyId(pointer));
|
||||
}
|
||||
|
||||
static void unlockedHandler(void * data,
|
||||
struct zwp_locked_pointer_v1 * pointer)
|
||||
{
|
||||
MTRACE("lock active=0 id=%u", proxyId(pointer));
|
||||
}
|
||||
|
||||
static const struct zwp_locked_pointer_v1_listener lockedListener = {
|
||||
.locked = lockedHandler,
|
||||
.unlocked = unlockedHandler,
|
||||
};
|
||||
|
||||
static struct zwp_confined_pointer_v1 * createConfine(
|
||||
struct wl_region * region)
|
||||
{
|
||||
struct zwp_confined_pointer_v1 * pointer =
|
||||
zwp_pointer_constraints_v1_confine_pointer(
|
||||
wlWm.pointerConstraints, wlWm.surface, wlWm.pointer, region,
|
||||
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
|
||||
zwp_confined_pointer_v1_add_listener(pointer, &confinedListener, NULL);
|
||||
return pointer;
|
||||
}
|
||||
|
||||
static struct zwp_locked_pointer_v1 * createLock(void)
|
||||
{
|
||||
struct zwp_locked_pointer_v1 * pointer =
|
||||
zwp_pointer_constraints_v1_lock_pointer(
|
||||
wlWm.pointerConstraints, wlWm.surface, wlWm.pointer, NULL,
|
||||
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
|
||||
zwp_locked_pointer_v1_add_listener(pointer, &lockedListener, NULL);
|
||||
return pointer;
|
||||
}
|
||||
|
||||
static void relativePointerMotionHandler(void * data,
|
||||
struct zwp_relative_pointer_v1 *pointer, uint32_t timeHi, uint32_t timeLo,
|
||||
wl_fixed_t dxW, wl_fixed_t dyW, wl_fixed_t dxUnaccelW,
|
||||
wl_fixed_t dyUnaccelW)
|
||||
{
|
||||
wlWm.cursorX += wl_fixed_to_double(dxW);
|
||||
wlWm.cursorY += wl_fixed_to_double(dyW);
|
||||
const double dx = wl_fixed_to_double(dxW);
|
||||
const double dy = wl_fixed_to_double(dyW);
|
||||
wlWm.cursorX += dx;
|
||||
wlWm.cursorY += dy;
|
||||
MTRACE("rel time=%u:%u delta=%.3f,%.3f raw=%.3f,%.3f "
|
||||
"pos=%.3f,%.3f", timeHi, timeLo, dx, dy,
|
||||
wl_fixed_to_double(dxUnaccelW), wl_fixed_to_double(dyUnaccelW),
|
||||
wlWm.cursorX, wlWm.cursorY);
|
||||
app_updateCursorPos(wlWm.cursorX, wlWm.cursorY);
|
||||
|
||||
app_handleMouseRelative(
|
||||
wl_fixed_to_double(dxW),
|
||||
wl_fixed_to_double(dyW),
|
||||
dx,
|
||||
dy,
|
||||
wl_fixed_to_double(dxUnaccelW),
|
||||
wl_fixed_to_double(dyUnaccelW));
|
||||
}
|
||||
@@ -322,21 +416,32 @@ static const struct wl_keyboard_listener keyboardListener = {
|
||||
|
||||
static void waylandCleanUpPointer(void)
|
||||
{
|
||||
uint32_t lockId = 0;
|
||||
uint32_t confId = 0;
|
||||
uint64_t lockSeq = 0;
|
||||
uint64_t confSeq = 0;
|
||||
INTERLOCKED_SECTION(wlWm.surfaceLock,
|
||||
{
|
||||
if (wlWm.lockedPointer)
|
||||
{
|
||||
lockId = proxyId(wlWm.lockedPointer);
|
||||
zwp_locked_pointer_v1_destroy(wlWm.lockedPointer);
|
||||
wlWm.lockedPointer = NULL;
|
||||
lockSeq = app_mouseSeq();
|
||||
}
|
||||
|
||||
if (wlWm.confinedPointer)
|
||||
{
|
||||
confId = proxyId(wlWm.confinedPointer);
|
||||
zwp_confined_pointer_v1_destroy(wlWm.confinedPointer);
|
||||
wlWm.confinedPointer = NULL;
|
||||
confSeq = app_mouseSeq();
|
||||
}
|
||||
});
|
||||
|
||||
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);
|
||||
@@ -409,6 +514,7 @@ bool waylandInputInit(bool allowNoInput)
|
||||
{
|
||||
if (!wlWm.seat)
|
||||
{
|
||||
MTRACE("input seat=0 allowNone=%d", allowNoInput);
|
||||
if (allowNoInput)
|
||||
{
|
||||
DEBUG_WARN("Compositor missing wl_seat, input will be disabled");
|
||||
@@ -439,6 +545,10 @@ bool waylandInputInit(bool allowNoInput)
|
||||
DEBUG_WARN("zwp_keyboard_shortcuts_inhibit_manager_v1 not exported by "
|
||||
"compositor, keyboard will not be grabbed");
|
||||
|
||||
MTRACE("input seat=1 warp=%d relMgr=%d constraints=%d",
|
||||
wlWm.warpSupport, !!wlWm.relativePointerManager,
|
||||
!!wlWm.pointerConstraints);
|
||||
|
||||
wlWm.xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
if (!wlWm.xkb)
|
||||
DEBUG_WARN("Failed to initialize xkb, keyboard input will not work");
|
||||
@@ -480,40 +590,63 @@ 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)
|
||||
{
|
||||
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(wlWm.relativePointer,
|
||||
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;
|
||||
INTERLOCKED_SECTION(wlWm.surfaceLock,
|
||||
{
|
||||
if (!wlWm.confinedPointer && !wlWm.lockedPointer)
|
||||
{
|
||||
wlWm.confinedPointer = zwp_pointer_constraints_v1_confine_pointer(
|
||||
wlWm.pointerConstraints, wlWm.surface, wlWm.pointer, NULL,
|
||||
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
|
||||
wlWm.confinedPointer = createConfine(NULL);
|
||||
confId = proxyId(wlWm.confinedPointer);
|
||||
confSeq = app_mouseSeq();
|
||||
}
|
||||
haveConf = !!wlWm.confinedPointer;
|
||||
haveLock = !!wlWm.lockedPointer;
|
||||
});
|
||||
|
||||
if (confId)
|
||||
MLOG(confSeq, "conf req id=%u why=grab", confId);
|
||||
else
|
||||
MTRACE("conf skip conf=%d lock=%d", haveConf, haveLock);
|
||||
}
|
||||
|
||||
inline static void internalUngrabPointer(bool lock)
|
||||
inline static uint32_t internalUngrabPointer(bool lock, uint64_t * traceSeq)
|
||||
{
|
||||
*traceSeq = 0;
|
||||
if (!wlWm.pointer)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (lock)
|
||||
LG_LOCK(wlWm.surfaceLock);
|
||||
|
||||
uint32_t confId = 0;
|
||||
if (wlWm.confinedPointer)
|
||||
{
|
||||
confId = proxyId(wlWm.confinedPointer);
|
||||
zwp_confined_pointer_v1_destroy(wlWm.confinedPointer);
|
||||
wlWm.confinedPointer = NULL;
|
||||
*traceSeq = app_mouseSeq();
|
||||
}
|
||||
|
||||
if (lock)
|
||||
@@ -533,43 +666,65 @@ inline static void internalUngrabPointer(bool lock)
|
||||
app_resyncMouseBasic();
|
||||
app_handleMouseBasic();
|
||||
}
|
||||
|
||||
return confId;
|
||||
}
|
||||
|
||||
void waylandUngrabPointer(void)
|
||||
{
|
||||
internalUngrabPointer(true);
|
||||
uint64_t confSeq;
|
||||
const uint32_t confId = internalUngrabPointer(true, &confSeq);
|
||||
MLOG(confSeq, "conf destroy id=%u why=ungrab", confId);
|
||||
}
|
||||
|
||||
void waylandCapturePointer(void)
|
||||
{
|
||||
if (!wlWm.warpSupport)
|
||||
{
|
||||
MTRACE("capture fallback=confine");
|
||||
waylandGrabPointer();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t confId = 0;
|
||||
uint32_t lockId = 0;
|
||||
uint64_t confSeq = 0;
|
||||
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;
|
||||
confSeq = app_mouseSeq();
|
||||
}
|
||||
|
||||
wlWm.lockedPointer = zwp_pointer_constraints_v1_lock_pointer(
|
||||
wlWm.pointerConstraints, wlWm.surface, wlWm.pointer, NULL,
|
||||
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
|
||||
wlWm.lockedPointer = createLock();
|
||||
lockId = proxyId(wlWm.lockedPointer);
|
||||
lockSeq = app_mouseSeq();
|
||||
});
|
||||
|
||||
MLOG(confSeq, "conf destroy id=%u why=capture", confId);
|
||||
MLOG(lockSeq, "lock req id=%u why=capture", lockId);
|
||||
}
|
||||
|
||||
void waylandUncapturePointer(void)
|
||||
{
|
||||
uint32_t lockId = 0;
|
||||
uint32_t confDropId = 0;
|
||||
uint32_t confReqId = 0;
|
||||
uint64_t lockSeq = 0;
|
||||
uint64_t confDropSeq = 0;
|
||||
uint64_t confReqSeq = 0;
|
||||
INTERLOCKED_SECTION(wlWm.surfaceLock,
|
||||
{
|
||||
if (wlWm.lockedPointer)
|
||||
{
|
||||
lockId = proxyId(wlWm.lockedPointer);
|
||||
zwp_locked_pointer_v1_destroy(wlWm.lockedPointer);
|
||||
wlWm.lockedPointer = NULL;
|
||||
lockSeq = app_mouseSeq();
|
||||
}
|
||||
|
||||
/* we need to ungrab the pointer on the following conditions when exiting capture mode:
|
||||
@@ -580,14 +735,18 @@ void waylandUncapturePointer(void)
|
||||
* - if the user has opted to use captureInputOnly mode.
|
||||
*/
|
||||
if (!wlWm.warpSupport || !app_isFormatValid() || app_isCaptureOnlyMode())
|
||||
internalUngrabPointer(false);
|
||||
confDropId = internalUngrabPointer(false, &confDropSeq);
|
||||
else if (wlWm.pointer)
|
||||
{
|
||||
wlWm.confinedPointer = zwp_pointer_constraints_v1_confine_pointer(
|
||||
wlWm.pointerConstraints, wlWm.surface, wlWm.pointer, NULL,
|
||||
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
|
||||
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);
|
||||
}
|
||||
|
||||
void waylandGrabKeyboard(void)
|
||||
@@ -611,13 +770,25 @@ void waylandUngrabKeyboard(void)
|
||||
|
||||
void waylandWarpPointer(int x, int y, bool exiting)
|
||||
{
|
||||
if (!wlWm.pointerInSurface || wlWm.lockedPointer)
|
||||
const int reqX = x;
|
||||
const int reqY = y;
|
||||
if (!wlWm.pointerInSurface)
|
||||
{
|
||||
MTRACE("warp drop=surface target=%d,%d exit=%d", x, y, exiting);
|
||||
return;
|
||||
}
|
||||
|
||||
if (wlWm.lockedPointer)
|
||||
{
|
||||
MTRACE("warp drop=lock target=%d,%d exit=%d", x, y, exiting);
|
||||
return;
|
||||
}
|
||||
|
||||
LG_LOCK(wlWm.surfaceLock);
|
||||
if (wlWm.lockedPointer)
|
||||
{
|
||||
LG_UNLOCK(wlWm.surfaceLock);
|
||||
MTRACE("warp drop=lock-race target=%d,%d exit=%d", x, y, exiting);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -632,6 +803,9 @@ void waylandWarpPointer(int x, int y, bool exiting)
|
||||
struct wl_region * region = wl_compositor_create_region(wlWm.compositor);
|
||||
wl_region_add(region, x, y, 1, 1);
|
||||
|
||||
const uint32_t confId = proxyId(wlWm.confinedPointer);
|
||||
uint32_t tempId = 0;
|
||||
uint64_t warpSeq = 0;
|
||||
if (wlWm.confinedPointer)
|
||||
{
|
||||
zwp_confined_pointer_v1_set_region(wlWm.confinedPointer, region);
|
||||
@@ -640,17 +814,19 @@ void waylandWarpPointer(int x, int y, bool exiting)
|
||||
}
|
||||
else
|
||||
{
|
||||
struct zwp_confined_pointer_v1 * confine;
|
||||
confine = zwp_pointer_constraints_v1_confine_pointer(
|
||||
wlWm.pointerConstraints, wlWm.surface, wlWm.pointer, region,
|
||||
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
|
||||
struct zwp_confined_pointer_v1 * confine = createConfine(region);
|
||||
tempId = proxyId(confine);
|
||||
wl_surface_commit(wlWm.surface);
|
||||
zwp_confined_pointer_v1_destroy(confine);
|
||||
}
|
||||
|
||||
wl_surface_commit(wlWm.surface);
|
||||
wl_region_destroy(region);
|
||||
warpSeq = app_mouseSeq();
|
||||
LG_UNLOCK(wlWm.surfaceLock);
|
||||
|
||||
MLOG(warpSeq, "warp req=%d,%d target=%d,%d exit=%d conf=%u temp=%u",
|
||||
reqX, reqY, x, y, exiting, confId, tempId);
|
||||
}
|
||||
|
||||
void waylandRealignPointer(void)
|
||||
@@ -661,11 +837,24 @@ void waylandRealignPointer(void)
|
||||
|
||||
void waylandGuestPointerUpdated(double x, double y, double localX, double localY)
|
||||
{
|
||||
if ( !wlWm.pointer ||
|
||||
!wlWm.warpSupport ||
|
||||
!wlWm.pointerInSurface ||
|
||||
wlWm.lockedPointer )
|
||||
return;
|
||||
const char * drop = NULL;
|
||||
if (!wlWm.pointer)
|
||||
drop = "pointer";
|
||||
else if (!wlWm.warpSupport)
|
||||
drop = "support";
|
||||
else if (!wlWm.pointerInSurface)
|
||||
drop = "surface";
|
||||
else if (wlWm.lockedPointer)
|
||||
drop = "lock";
|
||||
|
||||
if (drop)
|
||||
{
|
||||
MTRACE("guest drop=%s guest=%.3f,%.3f local=%.3f,%.3f",
|
||||
drop, x, y, localX, localY);
|
||||
return;
|
||||
}
|
||||
|
||||
MTRACE("guest warp guest=%.3f,%.3f local=%.3f,%.3f",
|
||||
x, y, localX, localY);
|
||||
waylandWarpPointer((int) localX, (int) localY, false);
|
||||
}
|
||||
|
||||
@@ -29,15 +29,30 @@
|
||||
#include "common/debug.h"
|
||||
#include "common/event.h"
|
||||
|
||||
#define MTRACE(fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
const uint64_t seq = app_mouseSeq(); \
|
||||
if (seq) \
|
||||
app_mouseTrace(__FILE__, __LINE__, __FUNCTION__, seq, \
|
||||
"wl.window." fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
// Surface-handling listeners.
|
||||
|
||||
static void setScale(struct WaylandScale newScale)
|
||||
{
|
||||
const struct WaylandScale oldScale = wlWm.scale;
|
||||
wlWm.scale = newScale;
|
||||
wlWm.fractionalScale = waylandScaleIsFractional(newScale);
|
||||
wlWm.needsResize = true;
|
||||
|
||||
if (wlWm.desktop->configured())
|
||||
const bool configured = wlWm.desktop->configured();
|
||||
MTRACE("scale old=%d/%d new=%d/%d configured=%d",
|
||||
oldScale.num, oldScale.den, newScale.num, newScale.den, configured);
|
||||
|
||||
if (configured)
|
||||
{
|
||||
waylandCursorScaleChange();
|
||||
app_invalidateWindow(true);
|
||||
|
||||
@@ -58,6 +58,10 @@ bool app_isCaptureMode(void);
|
||||
bool app_isCaptureOnlyMode(void);
|
||||
bool app_isFormatValid(void);
|
||||
bool app_isOverlayMode(void);
|
||||
uint64_t app_mouseSeq(void);
|
||||
void app_mouseTrace(const char * file, unsigned int line,
|
||||
const char * function, uint64_t seq, const char * format, ...)
|
||||
__attribute__((format (printf, 5, 6)));
|
||||
void app_updateCursorPos(double x, double y);
|
||||
void app_updateMouseState(void);
|
||||
void app_getMouseState(LG_MouseState * state);
|
||||
|
||||
@@ -37,12 +37,25 @@
|
||||
|
||||
#include "cimgui.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SHADER_MOUSE_VALID (UINT32_C(1) << 31)
|
||||
|
||||
#define MTRACE(fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
const uint64_t seq = app_mouseSeq(); \
|
||||
if (seq) \
|
||||
app_mouseTrace(__FILE__, __LINE__, __FUNCTION__, seq, \
|
||||
"app." fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
bool app_isRunning(void)
|
||||
{
|
||||
const enum RunState state = app_getState();
|
||||
@@ -56,6 +69,33 @@ bool app_isCaptureMode(void)
|
||||
return g_cursor.grab;
|
||||
}
|
||||
|
||||
uint64_t app_mouseSeq(void)
|
||||
{
|
||||
static atomic_uint_fast64_t seq;
|
||||
|
||||
if (!g_params.mouseTrace)
|
||||
return 0;
|
||||
|
||||
return atomic_fetch_add_explicit(&seq, 1, memory_order_relaxed) + 1;
|
||||
}
|
||||
|
||||
void app_mouseTrace(const char * file, unsigned int line,
|
||||
const char * function, uint64_t seq, const char * format, ...)
|
||||
{
|
||||
char message[1024];
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
const int result = vsnprintf(message, sizeof(message), format, ap);
|
||||
va_end(ap);
|
||||
if (result < 0)
|
||||
return;
|
||||
|
||||
flockfile(stderr);
|
||||
debug_info(file, line, function, "Mouse %06" PRIu64 ": %s", seq,
|
||||
message);
|
||||
funlockfile(stderr);
|
||||
}
|
||||
|
||||
bool app_isCaptureOnlyMode(void)
|
||||
{
|
||||
return g_params.captureInputOnly;
|
||||
@@ -93,6 +133,9 @@ void app_updateCursorPos(double x, double y)
|
||||
g_cursor.pos.y = y;
|
||||
g_cursor.valid = true;
|
||||
|
||||
MTRACE("pos pos=%.3f,%.3f inWin=%d inView=%d grab=%d",
|
||||
x, y, g_cursor.inWindow, g_cursor.inView, g_cursor.grab);
|
||||
|
||||
if (app_isOverlayMode())
|
||||
g_state.io->MousePos = (ImVec2) { x, y };
|
||||
}
|
||||
@@ -167,6 +210,10 @@ void app_getMouseState(LG_MouseState * state)
|
||||
|
||||
void app_handleFocusEvent(bool focused)
|
||||
{
|
||||
MTRACE("focus set=%d old=%d inWin=%d inView=%d grab=%d",
|
||||
focused, g_state.focused, g_cursor.inWindow, g_cursor.inView,
|
||||
g_cursor.grab);
|
||||
|
||||
if (g_state.focused == focused)
|
||||
return;
|
||||
|
||||
@@ -211,6 +258,9 @@ void app_handleFocusEvent(bool focused)
|
||||
|
||||
void app_handleEnterEvent(bool entered)
|
||||
{
|
||||
MTRACE("enter set=%d inWin=%d inView=%d grab=%d",
|
||||
entered, g_cursor.inWindow, g_cursor.inView, g_cursor.grab);
|
||||
|
||||
if (entered)
|
||||
{
|
||||
g_cursor.inWindow = true;
|
||||
@@ -408,6 +458,9 @@ void app_handleButtonPress(int button)
|
||||
g_cursor.buttons |= (1U << button);
|
||||
app_updateMouseButtons();
|
||||
|
||||
MTRACE("button down=%d buttons=%u inView=%d grab=%d",
|
||||
button, g_cursor.buttons, g_cursor.inView, g_cursor.grab);
|
||||
|
||||
if (app_isOverlayMode())
|
||||
{
|
||||
int igButton = mapSpiceToImGuiButton(button);
|
||||
@@ -428,6 +481,9 @@ void app_handleButtonRelease(int button)
|
||||
g_cursor.buttons &= ~(1U << button);
|
||||
app_updateMouseButtons();
|
||||
|
||||
MTRACE("button up=%d buttons=%u inView=%d grab=%d",
|
||||
button, g_cursor.buttons, g_cursor.inView, g_cursor.grab);
|
||||
|
||||
if (app_isOverlayMode())
|
||||
{
|
||||
int igButton = mapSpiceToImGuiButton(button);
|
||||
@@ -599,6 +655,10 @@ void app_handleKeyboardLEDs(bool numLock, bool capsLock, bool scrollLock)
|
||||
void app_handleMouseRelative(double normx, double normy,
|
||||
double rawx, double rawy)
|
||||
{
|
||||
MTRACE("rel delta=%.3f,%.3f raw=%.3f,%.3f inWin=%d inView=%d "
|
||||
"grab=%d", normx, normy, rawx, rawy, g_cursor.inWindow,
|
||||
g_cursor.inView, g_cursor.grab);
|
||||
|
||||
if (app_isOverlayMode())
|
||||
return;
|
||||
|
||||
@@ -671,6 +731,9 @@ void app_updateWindowPos(int x, int y)
|
||||
|
||||
void app_handleResizeEvent(int w, int h, double scale, const struct Border border)
|
||||
{
|
||||
MTRACE("resize win=%dx%d scale=%.3f border=%d,%d,%d,%d",
|
||||
w, h, scale, border.left, border.top, border.right, border.bottom);
|
||||
|
||||
memcpy(&g_state.border, &border, sizeof(border));
|
||||
|
||||
/* don't do anything else if the window dimensions have not changed */
|
||||
|
||||
@@ -402,6 +402,13 @@ static struct Option options[] =
|
||||
.type = OPTION_TYPE_BOOL,
|
||||
.value.x_bool = true,
|
||||
},
|
||||
{
|
||||
.module = "input",
|
||||
.name = "mouseTrace",
|
||||
.description = "Enable mouse input diagnostics",
|
||||
.type = OPTION_TYPE_BOOL,
|
||||
.value.x_bool = false,
|
||||
},
|
||||
{
|
||||
.module = "input",
|
||||
.name = "autoCapture",
|
||||
@@ -727,6 +734,7 @@ bool config_load(int argc, char * argv[])
|
||||
g_params.mouseSmoothing = option_get_bool("input", "mouseSmoothing" );
|
||||
g_params.rawMouse = option_get_bool("input", "rawMouse" );
|
||||
g_params.mouseRedraw = option_get_bool("input", "mouseRedraw" );
|
||||
g_params.mouseTrace = option_get_bool("input", "mouseTrace" );
|
||||
g_params.autoCapture = option_get_bool("input", "autoCapture" );
|
||||
g_params.captureInputOnly = option_get_bool("input", "captureOnly" );
|
||||
|
||||
|
||||
@@ -36,6 +36,16 @@
|
||||
|
||||
#define RESIZE_TIMEOUT (10 * 1000) // 10ms
|
||||
|
||||
#define MTRACE(fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
const uint64_t seq = app_mouseSeq(); \
|
||||
if (seq) \
|
||||
app_mouseTrace(__FILE__, __LINE__, __FUNCTION__, seq, \
|
||||
"core." fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
static bool isInView(void)
|
||||
{
|
||||
return
|
||||
@@ -58,6 +68,10 @@ void core_invalidatePointer(bool detectInView)
|
||||
enum LG_DSWarpSupport warpSupport = LG_DS_WARP_NONE;
|
||||
app_getProp(LG_DS_WARP_SUPPORT, &warpSupport);
|
||||
|
||||
MTRACE("invalidate detect=%d inWin=%d inView=%d grab=%d warp=%d "
|
||||
"support=%d", detectInView, g_cursor.inWindow, g_cursor.inView,
|
||||
g_cursor.grab, g_cursor.warpState, warpSupport);
|
||||
|
||||
if (detectInView)
|
||||
{
|
||||
bool inView = isInView();
|
||||
@@ -101,12 +115,22 @@ void core_invalidatePointer(bool detectInView)
|
||||
|
||||
void core_setCursorInView(bool enable)
|
||||
{
|
||||
MTRACE("view req=%d old=%d focus=%d inWin=%d grab=%d",
|
||||
enable, g_cursor.inView, g_state.focused, g_cursor.inWindow,
|
||||
g_cursor.grab);
|
||||
|
||||
// if the state has not changed, don't do anything else
|
||||
if (g_cursor.inView == enable)
|
||||
{
|
||||
MTRACE("view skip=same value=%d", enable);
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable && !g_state.focused)
|
||||
{
|
||||
MTRACE("view skip=focus");
|
||||
return;
|
||||
}
|
||||
|
||||
g_cursor.inView = enable;
|
||||
core_invalidatePointer(false);
|
||||
@@ -124,6 +148,10 @@ void core_setGrab(bool enable)
|
||||
|
||||
void core_setGrabQuiet(bool enable)
|
||||
{
|
||||
MTRACE("grab req=%d old=%d inWin=%d inView=%d focus=%d",
|
||||
enable, g_cursor.grab, g_cursor.inWindow, g_cursor.inView,
|
||||
g_state.focused);
|
||||
|
||||
/* we always do this so that at init the cursor is in the right state */
|
||||
if (g_params.captureInputOnly && g_params.hideMouse)
|
||||
g_state.ds->setPointer(enable ? LG_POINTER_NONE : LG_POINTER_SQUARE);
|
||||
@@ -149,7 +177,8 @@ void core_setGrabQuiet(bool enable)
|
||||
* odd UI behaviour if the user is using focus follows mouse and the window
|
||||
* was focused without the cursor being in window already */
|
||||
struct DoublePoint local;
|
||||
util_guestCurToLocal(&local);
|
||||
const bool valid = util_guestCurToLocal(&local);
|
||||
MTRACE("grab align valid=%d", valid);
|
||||
core_warpPointer(local.x, local.y, true);
|
||||
|
||||
if (g_params.grabKeyboard)
|
||||
@@ -177,17 +206,35 @@ void core_setGrabQuiet(bool enable)
|
||||
|
||||
bool core_warpPointer(int x, int y, bool exiting)
|
||||
{
|
||||
if ((!g_cursor.inWindow && !exiting) ||
|
||||
app_isOverlayMode() ||
|
||||
g_cursor.warpState == WARP_STATE_OFF)
|
||||
if (!g_cursor.inWindow && !exiting)
|
||||
{
|
||||
MTRACE("warp drop=window target=%d,%d exit=%d", x, y, exiting);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (app_isOverlayMode())
|
||||
{
|
||||
MTRACE("warp drop=overlay target=%d,%d exit=%d", x, y, exiting);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g_cursor.warpState == WARP_STATE_OFF)
|
||||
{
|
||||
MTRACE("warp drop=state target=%d,%d exit=%d", x, y, exiting);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (exiting)
|
||||
g_cursor.warpState = WARP_STATE_OFF;
|
||||
|
||||
if (g_cursor.pos.x == x && g_cursor.pos.y == y)
|
||||
{
|
||||
MTRACE("warp same target=%d,%d exit=%d", x, y, exiting);
|
||||
return true;
|
||||
}
|
||||
|
||||
MTRACE("warp send target=%d,%d exit=%d pos=%.3f,%.3f",
|
||||
x, y, exiting, g_cursor.pos.x, g_cursor.pos.y);
|
||||
g_state.ds->warpPointer(x, y, exiting);
|
||||
return true;
|
||||
}
|
||||
@@ -366,6 +413,15 @@ void core_updatePositionInfo(void)
|
||||
}
|
||||
|
||||
done:
|
||||
MTRACE("geometry src=%dx%d dst=%d,%d,%d,%d win=%dx%d "
|
||||
"scale=%.4f,%.4f uiScale=%.4f rot=%d/%d border=%d,%d,%d,%d "
|
||||
"valid=%d", g_state.srcSize.x, g_state.srcSize.y,
|
||||
g_state.dstRect.x, g_state.dstRect.y, g_state.dstRect.w,
|
||||
g_state.dstRect.h, g_state.windowW, g_state.windowH,
|
||||
g_cursor.scale.x, g_cursor.scale.y, g_state.windowScale,
|
||||
g_state.rotate, g_params.winRotate, g_state.border.left,
|
||||
g_state.border.top, g_state.border.right, g_state.border.bottom,
|
||||
g_state.posInfoValid);
|
||||
app_updateMouseState();
|
||||
atomic_fetch_add(&g_state.lgrResize, 1);
|
||||
}
|
||||
@@ -438,11 +494,26 @@ void core_handleGuestMouseUpdate(void)
|
||||
{
|
||||
struct DoublePoint localPos;
|
||||
if (!util_guestCurToLocal(&localPos))
|
||||
{
|
||||
MTRACE("guest drop=geometry guest=%d,%d hot=%d,%d valid=%d",
|
||||
g_cursor.guest.x, g_cursor.guest.y, g_cursor.guest.hx,
|
||||
g_cursor.guest.hy, g_cursor.guest.valid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (app_isOverlayMode() || !g_cursor.inView)
|
||||
const bool overlay = app_isOverlayMode();
|
||||
if (overlay || !g_cursor.inView)
|
||||
{
|
||||
MTRACE("guest drop=%s guest=%d,%d local=%.3f,%.3f inWin=%d "
|
||||
"inView=%d", overlay ? "overlay" : "view", g_cursor.guest.x,
|
||||
g_cursor.guest.y, localPos.x, localPos.y, g_cursor.inWindow,
|
||||
g_cursor.inView);
|
||||
return;
|
||||
}
|
||||
|
||||
MTRACE("guest send guest=%d,%d local=%.3f,%.3f inWin=%d inView=%d",
|
||||
g_cursor.guest.x, g_cursor.guest.y, localPos.x, localPos.y,
|
||||
g_cursor.inWindow, g_cursor.inView);
|
||||
g_state.ds->guestPointerUpdated(
|
||||
g_cursor.guest.x, g_cursor.guest.y,
|
||||
util_clamp(localPos.x, g_state.dstRect.x,
|
||||
@@ -454,7 +525,11 @@ void core_handleGuestMouseUpdate(void)
|
||||
|
||||
void core_handleMouseGrabbed(double ex, double ey)
|
||||
{
|
||||
if (!core_inputEnabled())
|
||||
const bool enabled = core_inputEnabled();
|
||||
MTRACE("captured delta=%.3f,%.3f enabled=%d", ex, ey,
|
||||
enabled);
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
int x, y;
|
||||
@@ -481,6 +556,10 @@ void core_handleMouseGrabbed(double ex, double ey)
|
||||
|
||||
void core_handleMouseNormal(double ex, double ey)
|
||||
{
|
||||
MTRACE("normal delta=%.3f,%.3f guest=%d,%d valid=%d inWin=%d "
|
||||
"inView=%d", ex, ey, g_cursor.guest.x, g_cursor.guest.y,
|
||||
g_cursor.guest.valid, g_cursor.inWindow, g_cursor.inView);
|
||||
|
||||
// prevent cursor handling outside of capture if the position is not known
|
||||
if (!g_cursor.guest.valid)
|
||||
{
|
||||
@@ -511,6 +590,7 @@ void core_handleMouseNormal(double ex, double ey)
|
||||
}
|
||||
|
||||
bool testExit = true;
|
||||
bool didExit = false;
|
||||
const bool inView = isInView();
|
||||
if (!g_cursor.inView)
|
||||
{
|
||||
@@ -643,11 +723,18 @@ fallback:
|
||||
local.x + move.x >= g_state.dstRect.x + g_state.dstRect.w ||
|
||||
local.y + move.y >= g_state.dstRect.y + g_state.dstRect.h)
|
||||
{
|
||||
didExit = true;
|
||||
local.x += move.x;
|
||||
local.y += move.y;
|
||||
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);
|
||||
|
||||
MTRACE("exit local=%.3f,%.3f move=%.3f,%.3f target=%d,%d "
|
||||
"dst=%d,%d,%d,%d support=%d", local.x - move.x,
|
||||
local.y - move.y, move.x, move.y, tx, ty, g_state.dstRect.x,
|
||||
g_state.dstRect.y, g_state.dstRect.w, g_state.dstRect.h,
|
||||
warpSupport);
|
||||
|
||||
switch (warpSupport)
|
||||
{
|
||||
case LG_DS_WARP_NONE:
|
||||
@@ -684,6 +771,7 @@ fallback:
|
||||
else if (warpSupport == LG_DS_WARP_SURFACE && isInView())
|
||||
{
|
||||
/* regrab the pointer in case the user did not move off the surface */
|
||||
MTRACE("regrab pos=%.3f,%.3f", g_cursor.pos.x, g_cursor.pos.y);
|
||||
g_state.ds->grabPointer();
|
||||
g_cursor.warpState = WARP_STATE_ON;
|
||||
}
|
||||
@@ -715,6 +803,10 @@ fallback:
|
||||
g_cursor.guest.y += y;
|
||||
}
|
||||
|
||||
MTRACE("motion delta=%d,%d guest=%d,%d exit=%d test=%d warp=%d",
|
||||
x, y, g_cursor.guest.x, g_cursor.guest.y, didExit, testExit,
|
||||
g_cursor.warpState);
|
||||
|
||||
if (!purespice_mouseMotion(x, y))
|
||||
DEBUG_ERROR("failed to send mouse motion message");
|
||||
}
|
||||
|
||||
@@ -227,6 +227,7 @@ struct AppParams
|
||||
const char * windowTitle;
|
||||
const char * appId;
|
||||
bool mouseRedraw;
|
||||
bool mouseTrace;
|
||||
int mouseSens;
|
||||
bool mouseSmoothing;
|
||||
bool rawMouse;
|
||||
|
||||
@@ -326,6 +326,8 @@ All command line options
|
||||
+------------------------------+-------+---------------------+----------------------------------------------------------------------------------------------------------+
|
||||
| input:mouseRedraw | | yes | Mouse movements trigger redraws (ignores FPS minimum) |
|
||||
+------------------------------+-------+---------------------+----------------------------------------------------------------------------------------------------------+
|
||||
| input:mouseTrace | | no | Enable mouse input diagnostics |
|
||||
+------------------------------+-------+---------------------+----------------------------------------------------------------------------------------------------------+
|
||||
| input:autoCapture | | no | Try to keep the mouse captured when needed |
|
||||
+------------------------------+-------+---------------------+----------------------------------------------------------------------------------------------------------+
|
||||
| input:captureOnly | | no | Only enable input via SPICE if in capture mode |
|
||||
|
||||
Reference in New Issue
Block a user