[client] cursor: ensure cursor is rendered at init and aligned

This commit is contained in:
Geoffrey McRae 2021-01-08 23:12:15 +11:00
parent 86ca1bbbd6
commit 1c016ac0cd

View file

@ -70,7 +70,13 @@ static LGThread *t_cursor = NULL;
static LGThread *t_frame = NULL; static LGThread *t_frame = NULL;
static SDL_Cursor *cursor = NULL; static SDL_Cursor *cursor = NULL;
static int g_XInputOp; // XInput Opcode static int g_XInputOp; // XInput Opcode
static Uint32 e_SDLEvent; // our SDL event
enum
{
LG_EVENT_ALIGN_TO_GUEST
};
struct AppState g_state; struct AppState g_state;
struct CursorState g_cursor; struct CursorState g_cursor;
@ -94,6 +100,20 @@ static void lgInit()
g_cursor.guest.valid = false; g_cursor.guest.valid = false;
} }
static void alignToGuest()
{
if (!params.useSpiceInput || g_cursor.grab ||
SDL_HasEvent(e_SDLEvent))
return;
SDL_Event event;
SDL_memset(&event, 0, sizeof(event));
event.type = e_SDLEvent;
event.user.code = LG_EVENT_ALIGN_TO_GUEST;
SDL_PushEvent(&event);
}
static void updatePositionInfo() static void updatePositionInfo()
{ {
if (g_state.haveSrcSize) if (g_state.haveSrcSize)
@ -365,9 +385,13 @@ static int cursorThread(void * unused)
if (msg.udata & CURSOR_FLAG_POSITION) if (msg.udata & CURSOR_FLAG_POSITION)
{ {
bool valid = g_cursor.guest.valid;
g_cursor.guest.x = cursor->x; g_cursor.guest.x = cursor->x;
g_cursor.guest.y = cursor->y; g_cursor.guest.y = cursor->y;
g_cursor.guest.valid = true; g_cursor.guest.valid = true;
if (valid != true)
alignToGuest();
} }
lgmpClientMessageDone(queue); lgmpClientMessageDone(queue);
@ -869,6 +893,12 @@ static void handleMouseGrabbed(double ex, double ey)
DEBUG_ERROR("failed to send mouse motion message"); DEBUG_ERROR("failed to send mouse motion message");
} }
static void guestCurToLocal(struct DoublePoint *local)
{
local->x = (g_cursor.guest.x + g_cursor.guest.hx) / g_cursor.scale.x;
local->y = (g_cursor.guest.y + g_cursor.guest.hy) / g_cursor.scale.y;
}
static void handleMouseNormal(double ex, double ey) static void handleMouseNormal(double ex, double ey)
{ {
/* if we don't have the current cursor pos just send cursor movements */ /* if we don't have the current cursor pos just send cursor movements */
@ -950,11 +980,8 @@ static void handleMouseNormal(double ex, double ey)
testExit = false; testExit = false;
/* translate the guests position to our coordinate space */ /* translate the guests position to our coordinate space */
struct DoublePoint local = struct DoublePoint local;
{ guestCurToLocal(&local);
.x = (g_cursor.guest.x + g_cursor.guest.hx) / g_cursor.scale.x,
.y = (g_cursor.guest.y + g_cursor.guest.hy) / g_cursor.scale.y
};
/* check if the move would push the cursor outside the guest's viewport */ /* check if the move would push the cursor outside the guest's viewport */
if (testExit && ( if (testExit && (
@ -1042,6 +1069,7 @@ static void handleResizeEvent(unsigned int w, unsigned int h)
g_state.windowCX = w / 2; g_state.windowCX = w / 2;
g_state.windowCY = h / 2; g_state.windowCY = h / 2;
updatePositionInfo(); updatePositionInfo();
alignToGuest();
} }
static void handleWindowLeave() static void handleWindowLeave()
@ -1151,6 +1179,24 @@ static void setGrab(bool enable)
int eventFilter(void * userdata, SDL_Event * event) int eventFilter(void * userdata, SDL_Event * event)
{ {
if (event->type == e_SDLEvent)
{
switch(event->user.code)
{
case LG_EVENT_ALIGN_TO_GUEST:
{
if (!g_cursor.guest.valid || !g_state.focused)
break;
struct DoublePoint local;
guestCurToLocal(&local);
warpMouse(round(local.x), round(local.y), false);
break;
}
}
return 0;
}
switch(event->type) switch(event->type)
{ {
case SDL_QUIT: case SDL_QUIT:
@ -1314,8 +1360,17 @@ int eventFilter(void * userdata, SDL_Event * event)
case EnterNotify: case EnterNotify:
{ {
g_cursor.pos.x = xe.xcrossing.x; int x, y;
g_cursor.pos.y = xe.xcrossing.y; Window child;
XTranslateCoordinates(g_state.wminfo.info.x11.display,
DefaultRootWindow(g_state.wminfo.info.x11.display),
g_state.wminfo.info.x11.window,
xe.xcrossing.x_root, xe.xcrossing.y_root,
&x, &y,
&child);
g_cursor.pos.x = x;
g_cursor.pos.y = y;
handleWindowEnter(); handleWindowEnter();
break; break;
} }
@ -1325,8 +1380,17 @@ int eventFilter(void * userdata, SDL_Event * event)
if (xe.xcrossing.mode != NotifyNormal) if (xe.xcrossing.mode != NotifyNormal)
break; break;
g_cursor.pos.x = xe.xcrossing.x; int x, y;
g_cursor.pos.y = xe.xcrossing.y; Window child;
XTranslateCoordinates(g_state.wminfo.info.x11.display,
DefaultRootWindow(g_state.wminfo.info.x11.display),
g_state.wminfo.info.x11.window,
xe.xcrossing.x_root, xe.xcrossing.y_root,
&x, &y,
&child);
g_cursor.pos.x = x;
g_cursor.pos.y = y;
handleWindowLeave(); handleWindowLeave();
break; break;
} }
@ -1863,6 +1927,9 @@ static int lg_run()
g_state.frameTime = 1000000000ULL / (unsigned long long)params.fpsMin; g_state.frameTime = 1000000000ULL / (unsigned long long)params.fpsMin;
} }
// create our custom event
e_SDLEvent = SDL_RegisterEvents(1);
register_key_binds(); register_key_binds();
// set the compositor hint to bypass for low latency // set the compositor hint to bypass for low latency
@ -1919,13 +1986,6 @@ static int lg_run()
if (params.hideMouse) if (params.hideMouse)
SDL_ShowCursor(SDL_DISABLE); SDL_ShowCursor(SDL_DISABLE);
if (params.captureOnStart)
{
g_cursor.grab = true;
if (g_state.wminfo.subsystem != SDL_SYSWM_X11)
SDL_SetWindowGrab(g_state.window, true);
}
// setup the startup condition // setup the startup condition
if (!(e_startup = lgCreateEvent(false, 0))) if (!(e_startup = lgCreateEvent(false, 0)))
{ {
@ -1970,6 +2030,9 @@ static int lg_run()
* we start checking for a valid session */ * we start checking for a valid session */
SDL_WaitEventTimeout(NULL, 200); SDL_WaitEventTimeout(NULL, 200);
if (params.captureOnStart)
setGrab(true);
uint32_t udataSize; uint32_t udataSize;
KVMFR *udata; KVMFR *udata;
int waitCount = 0; int waitCount = 0;