Gets rid of the dead mouse issue when you move the mouse slowly
-- v5: winewayland: Implement relative motion accumulator
From: Etaash Mathamsetty etaash.mathamsetty@gmail.com
--- dlls/winewayland.drv/wayland_pointer.c | 53 ++++++++++++++++++++------ dlls/winewayland.drv/waylanddrv.h | 2 + 2 files changed, 43 insertions(+), 12 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_pointer.c b/dlls/winewayland.drv/wayland_pointer.c index 6c852292c1d..2a175b8f3c2 100644 --- a/dlls/winewayland.drv/wayland_pointer.c +++ b/dlls/winewayland.drv/wayland_pointer.c @@ -257,6 +257,19 @@ static const struct wl_pointer_listener pointer_listener = pointer_handle_axis_discrete };
+/********************************************************************** + * wayland_motion_delta_to_window + * + * Converts the surface-local delta to window (logical) coordinate delta. + */ +static void wayland_motion_delta_to_window(struct wayland_surface *surface, + double surface_x, double surface_y, + double *window_x, double *window_y) +{ + *window_x = surface_x * surface->window.scale; + *window_y = surface_y * surface->window.scale; +} + static void relative_pointer_v1_relative_motion(void *private, struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1, uint32_t utime_hi, uint32_t utime_lo, @@ -265,28 +278,41 @@ static void relative_pointer_v1_relative_motion(void *private, { INPUT input = {0}; HWND hwnd; - POINT screen; + struct { + double x; + double y; + } screen = {0.0}; + struct wayland_pointer *pointer = private; struct wayland_win_data *data;
if (!(hwnd = wayland_pointer_get_focused_hwnd())) return; if (!(data = wayland_win_data_get(hwnd))) return; + if (!private) return;
- wayland_surface_coords_to_window(data->wayland_surface, - wl_fixed_to_double(dx), - wl_fixed_to_double(dy), - (int *)&screen.x, (int *)&screen.y); - + wayland_motion_delta_to_window(data->wayland_surface, + wl_fixed_to_double(dx), + wl_fixed_to_double(dy), + &screen.x, &screen.y); wayland_win_data_release(data);
+ pthread_mutex_lock(&pointer->mutex); + + pointer->accum_x += screen.x; + pointer->accum_y += screen.y;
input.type = INPUT_MOUSE; - input.mi.dx = screen.x; - input.mi.dy = screen.y; + input.mi.dx = round(pointer->accum_x); + input.mi.dy = round(pointer->accum_y); input.mi.dwFlags = MOUSEEVENTF_MOVE;
- TRACE("hwnd=%p wayland_dxdy=%.2f,%.2f screen_dxdy=%d,%d\n", - hwnd, wl_fixed_to_double(dx), wl_fixed_to_double(dy), - (int)screen.x, (int)screen.y); + pointer->accum_x -= input.mi.dx; + pointer->accum_y -= input.mi.dy; + + pthread_mutex_unlock(&pointer->mutex); + + TRACE("hwnd=%p wayland_dxdy=%.2f,%.2f accum_dxdy=%d,%d\n", + hwnd, wl_fixed_to_double(dx), wl_fixed_to_double(dy), + input.mi.dx, input.mi.dy);
NtUserSendHardwareInput(hwnd, 0, &input, 0); } @@ -783,11 +809,14 @@ static void wayland_pointer_update_constraint(struct wl_surface *wl_surface, process_wayland.zwp_relative_pointer_manager_v1, pointer->wl_pointer); zwp_relative_pointer_v1_add_listener(pointer->zwp_relative_pointer_v1, - &relative_pointer_v1_listener, NULL); + &relative_pointer_v1_listener, pointer); TRACE("Enabling relative motion\n"); } else if (!needs_relative && pointer->zwp_relative_pointer_v1) { + pthread_mutex_lock(&pointer->mutex); + pointer->accum_x = pointer->accum_y = 0; + pthread_mutex_unlock(&pointer->mutex); zwp_relative_pointer_v1_destroy(pointer->zwp_relative_pointer_v1); pointer->zwp_relative_pointer_v1 = NULL; TRACE("Disabling relative motion\n"); diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 50d5fc44079..30fc65d949a 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -112,6 +112,8 @@ struct wayland_pointer uint32_t enter_serial; uint32_t button_serial; struct wayland_cursor cursor; + double accum_x; + double accum_y; pthread_mutex_t mutex; };
v2: applied suggestions
Alexandros Frantzis (@afrantzis) commented about dlls/winewayland.drv/wayland_pointer.c:
process_wayland.zwp_relative_pointer_manager_v1, pointer->wl_pointer); zwp_relative_pointer_v1_add_listener(pointer->zwp_relative_pointer_v1,
&relative_pointer_v1_listener, NULL);
&relative_pointer_v1_listener, pointer);
Although passing `pointer` as user data is fine, we can also just have `struct wayland_pointer *pointer = &process_wayland.pointer;` in the relative motion handler, like we do in the other pointer handlers (since we only have one pointer at the moment).
Alexandros Frantzis (@afrantzis) commented about dlls/winewayland.drv/wayland_pointer.c:
process_wayland.zwp_relative_pointer_manager_v1, pointer->wl_pointer); zwp_relative_pointer_v1_add_listener(pointer->zwp_relative_pointer_v1,
&relative_pointer_v1_listener, NULL);
} else if (!needs_relative && pointer->zwp_relative_pointer_v1) {&relative_pointer_v1_listener, pointer); TRACE("Enabling relative motion\n");
pthread_mutex_lock(&pointer->mutex);
The whole `wayland_pointer_update_constraint` function is always called with the pointer mutex locked, so this lock is not necessary. In fact this second lock attempt causes a deadlock since we are not using a reentrant mutex.
Alexandros Frantzis (@afrantzis) commented about dlls/winewayland.drv/wayland_pointer.c:
- input.mi.dx = screen.x;
- input.mi.dy = screen.y;
- input.mi.dx = round(pointer->accum_x);
- input.mi.dy = round(pointer->accum_y); input.mi.dwFlags = MOUSEEVENTF_MOVE;
- TRACE("hwnd=%p wayland_dxdy=%.2f,%.2f screen_dxdy=%d,%d\n",
hwnd, wl_fixed_to_double(dx), wl_fixed_to_double(dy),
(int)screen.x, (int)screen.y);
- pointer->accum_x -= input.mi.dx;
- pointer->accum_y -= input.mi.dy;
- pthread_mutex_unlock(&pointer->mutex);
- TRACE("hwnd=%p wayland_dxdy=%.2f,%.2f accum_dxdy=%d,%d\n",
hwnd, wl_fixed_to_double(dx), wl_fixed_to_double(dy),
Nit: alignment
Alexandros Frantzis (@afrantzis) commented about dlls/winewayland.drv/wayland_pointer.c:
{ INPUT input = {0}; HWND hwnd;
- POINT screen;
- struct {
double x;
double y;
- } screen = {0.0};
How about just using `double screen_x = 0.0, screen_y = 0.0;`? We don't really need to match the previous use of a `POINT`-like type here. I only used that before because we had that type readily available.