From: Alexandros Frantzis alexandros.frantzis@collabora.com
Also emit a synthetic motion event on pointer entry, to handle cases where the compositor doesn't send an initial motion event itself. --- dlls/winewayland.drv/Makefile.in | 2 +- dlls/winewayland.drv/wayland_pointer.c | 62 ++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-)
diff --git a/dlls/winewayland.drv/Makefile.in b/dlls/winewayland.drv/Makefile.in index 6bc03187d61..e1019ad8348 100644 --- a/dlls/winewayland.drv/Makefile.in +++ b/dlls/winewayland.drv/Makefile.in @@ -1,7 +1,7 @@ MODULE = winewayland.drv UNIXLIB = winewayland.so UNIX_CFLAGS = $(WAYLAND_CLIENT_CFLAGS) -UNIX_LIBS = -lwin32u $(WAYLAND_CLIENT_LIBS) $(PTHREAD_LIBS) +UNIX_LIBS = -lwin32u $(WAYLAND_CLIENT_LIBS) $(PTHREAD_LIBS) -lm
SOURCES = \ display.c \ diff --git a/dlls/winewayland.drv/wayland_pointer.c b/dlls/winewayland.drv/wayland_pointer.c index 1476c2369a9..29121d058cf 100644 --- a/dlls/winewayland.drv/wayland_pointer.c +++ b/dlls/winewayland.drv/wayland_pointer.c @@ -24,14 +24,71 @@
#include "config.h"
+#include <math.h> + #include "waylanddrv.h" #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv);
+static struct wayland_surface *pointer_lock_surface(void) +{ + struct wayland_surface *surface; + + pthread_mutex_lock(&process_wayland.pointer.mutex); + + if ((surface = process_wayland.pointer.surface)) + { + pthread_mutex_lock(&surface->mutex); + /* Return the surface only if it is not under destruction. */ + if (surface->wl_surface) return surface; + pthread_mutex_unlock(&surface->mutex); + } + + pthread_mutex_unlock(&process_wayland.pointer.mutex); + + return NULL; +} + +static void pointer_unlock_surface(void) +{ + pthread_mutex_unlock(&process_wayland.pointer.surface->mutex); + pthread_mutex_unlock(&process_wayland.pointer.mutex); +} + static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy) { + INPUT input = {0}; + RECT window_rect; + struct wayland_surface *surface; + int screen_x, screen_y; + + if (!(surface = pointer_lock_surface())) return; + + NtUserGetWindowRect(surface->hwnd, &window_rect); + + screen_x = round(wl_fixed_to_double(sx)) + window_rect.left; + screen_y = round(wl_fixed_to_double(sy)) + window_rect.top; + /* Sometimes, due to rounding, we may end up with pointer coordinates + * slightly outside the target window, so bring them within bounds. */ + if (screen_x >= window_rect.right) screen_x = window_rect.right - 1; + else if (screen_x < window_rect.left) screen_x = window_rect.left; + if (screen_y >= window_rect.bottom) screen_y = window_rect.bottom - 1; + else if (screen_y < window_rect.top) screen_y = window_rect.top; + + input.type = INPUT_MOUSE; + input.mi.dx = screen_x; + input.mi.dy = screen_y; + input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; + + TRACE("surface=%p hwnd=%p wayland_xy=%.2f,%.2f screen_xy=%d,%d\n", + surface, surface->hwnd, wl_fixed_to_double(sx), wl_fixed_to_double(sy), + screen_x, screen_y); + + __wine_send_input(surface->hwnd, &input, NULL); + + pointer_unlock_surface(); }
static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, @@ -50,6 +107,11 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, pthread_mutex_unlock(&surface->mutex); } pthread_mutex_unlock(&process_wayland.pointer.mutex); + + /* Handle the enter as a motion, to account for cases where the + * window first appears beneath the pointer and won't get a separate + * motion event. */ + pointer_handle_motion(data, wl_pointer, 0, sx, sy); }
static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,