[client] spice/wayland: improve cursor tracking logic

One of the major issues with the old tracking code is a data race
between the cursor thread updating g_cursor.guest and the
app_handleMouseBasic function. Specifically, the latter may have
sent mouse input via spice that has not been processed by the guest
and updated g_cursor.guest, but the guest may overwrite g_cursor.guest
to a previous state before the input is processed. This causes some
movements to be doubled. Eventually, the cursor positions will
synchronize, but this nevertheless causes a lot of jitter.

In this commit, we introduce a new field g_cursor.projected, which
is unambiguously the position of the cursor after taking into account
all the input already sent via spice. This is synced up to the guest
cursor upon entering the window and when the host restarts. Afterwards,
all mouse movements will be based on this position. This eliminates
all cursor jitter as far as I could tell.

Also, the cursor is now synced to the host position when exiting
capture mode.

A downside of this commit is that if the 1:1 movement patch is not
correctly applied, the cursor position would be wildly off instead
of simply jittering, but that is an unsupported configuration and
should not matter.

Also unsupported is when an application in guest moves the cursor
programmatically and bypassing spice. When using those applications,
capture mode must be on. Before this commit, we try to move the guest
cursor back to where it should be, but it's inherently fragile and
may lead to scenarios such as wild movements in first-person shooters.
This commit is contained in:
Quantum
2021-01-20 21:05:50 -05:00
committed by Geoffrey McRae
parent 543d660ccc
commit b0f9d2f713
5 changed files with 38 additions and 30 deletions

View File

@@ -46,6 +46,7 @@ void app_handleResizeEvent(int w, int h, const struct Border border);
void app_handleMouseGrabbed(double ex, double ey);
void app_handleMouseNormal(double ex, double ey);
void app_handleMouseBasic(void);
void app_resyncMouseBasic(void);
void app_handleButtonPress(int button);
void app_handleButtonRelease(int button);
void app_handleKeyPress(int scancode);