Module: wine Branch: master Commit: 579d67e17defe047979b4f3e8c156f4cf6924768 URL: https://gitlab.winehq.org/wine/wine/-/commit/579d67e17defe047979b4f3e8c156f4...
Author: Alexandros Frantzis alexandros.frantzis@collabora.com Date: Thu Aug 24 11:27:42 2023 +0300
winewayland.drv: Handle pointer focus events.
Handle wl_pointer enter/leave events and maintain information about the focused HWND. Since pointer information will be accessed by any UI capable thread, ensure proper proper locking is in place.
---
dlls/winewayland.drv/wayland.c | 7 +++--- dlls/winewayland.drv/wayland_pointer.c | 43 ++++++++++++++++++++++++++++++---- dlls/winewayland.drv/wayland_surface.c | 6 +++++ dlls/winewayland.drv/waylanddrv.h | 9 ++++++- 4 files changed, 57 insertions(+), 8 deletions(-)
diff --git a/dlls/winewayland.drv/wayland.c b/dlls/winewayland.drv/wayland.c index 6ea4a94551d..51e36b5ba60 100644 --- a/dlls/winewayland.drv/wayland.c +++ b/dlls/winewayland.drv/wayland.c @@ -34,6 +34,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv);
struct wayland process_wayland = { + .pointer.mutex = PTHREAD_MUTEX_INITIALIZER, .output_list = {&process_wayland.output_list, &process_wayland.output_list}, .output_mutex = PTHREAD_MUTEX_INITIALIZER }; @@ -60,9 +61,9 @@ static const struct xdg_wm_base_listener xdg_wm_base_listener = static void wl_seat_handle_capabilities(void *data, struct wl_seat *seat, enum wl_seat_capability caps) { - if ((caps & WL_SEAT_CAPABILITY_POINTER) && !process_wayland.wl_pointer) + if ((caps & WL_SEAT_CAPABILITY_POINTER) && !process_wayland.pointer.wl_pointer) wayland_pointer_init(wl_seat_get_pointer(seat)); - else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && process_wayland.wl_pointer) + else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && process_wayland.pointer.wl_pointer) wayland_pointer_deinit(); }
@@ -155,7 +156,7 @@ static void registry_handle_global_remove(void *data, struct wl_registry *regist wl_proxy_get_id((struct wl_proxy *)process_wayland.wl_seat) == id) { TRACE("removing seat\n"); - if (process_wayland.wl_pointer) wayland_pointer_deinit(); + if (process_wayland.pointer.wl_pointer) wayland_pointer_deinit(); wl_seat_release(process_wayland.wl_seat); process_wayland.wl_seat = NULL; } diff --git a/dlls/winewayland.drv/wayland_pointer.c b/dlls/winewayland.drv/wayland_pointer.c index 10dacfa03b0..cb9091f0cf2 100644 --- a/dlls/winewayland.drv/wayland_pointer.c +++ b/dlls/winewayland.drv/wayland_pointer.c @@ -25,6 +25,9 @@ #include "config.h"
#include "waylanddrv.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv);
static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy) @@ -35,11 +38,33 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *wl_surface, wl_fixed_t sx, wl_fixed_t sy) { + struct wayland_pointer *pointer = &process_wayland.pointer; + HWND hwnd; + + if (!wl_surface) return; + /* The wl_surface user data remains valid and immutable for the whole + * lifetime of the object, so it's safe to access without locking. */ + hwnd = wl_surface_get_user_data(wl_surface); + + TRACE("hwnd=%p\n", hwnd); + + pthread_mutex_lock(&pointer->mutex); + pointer->focused_hwnd = hwnd; + pthread_mutex_unlock(&pointer->mutex); }
static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *wl_surface) { + struct wayland_pointer *pointer = &process_wayland.pointer; + + if (!wl_surface) return; + + TRACE("hwnd=%p\n", wl_surface_get_user_data(wl_surface)); + + pthread_mutex_lock(&pointer->mutex); + pointer->focused_hwnd = NULL; + pthread_mutex_unlock(&pointer->mutex); }
static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, @@ -87,12 +112,22 @@ static const struct wl_pointer_listener pointer_listener =
void wayland_pointer_init(struct wl_pointer *wl_pointer) { - process_wayland.wl_pointer = wl_pointer; - wl_pointer_add_listener(process_wayland.wl_pointer, &pointer_listener, NULL); + struct wayland_pointer *pointer = &process_wayland.pointer; + + pthread_mutex_lock(&pointer->mutex); + pointer->wl_pointer = wl_pointer; + pointer->focused_hwnd = NULL; + pthread_mutex_unlock(&pointer->mutex); + wl_pointer_add_listener(pointer->wl_pointer, &pointer_listener, NULL); }
void wayland_pointer_deinit(void) { - wl_pointer_release(process_wayland.wl_pointer); - process_wayland.wl_pointer = NULL; + struct wayland_pointer *pointer = &process_wayland.pointer; + + pthread_mutex_lock(&pointer->mutex); + wl_pointer_release(pointer->wl_pointer); + pointer->wl_pointer = NULL; + pointer->focused_hwnd = NULL; + pthread_mutex_unlock(&pointer->mutex); } diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index fbc49191d9e..bc42da72b1e 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -108,6 +108,7 @@ struct wayland_surface *wayland_surface_create(HWND hwnd) ERR("Failed to create wl_surface Wayland surface\n"); goto err; } + wl_surface_set_user_data(surface->wl_surface, hwnd);
return surface;
@@ -123,6 +124,11 @@ err: */ void wayland_surface_destroy(struct wayland_surface *surface) { + pthread_mutex_lock(&process_wayland.pointer.mutex); + if (process_wayland.pointer.focused_hwnd == surface->hwnd) + process_wayland.pointer.focused_hwnd = NULL; + pthread_mutex_unlock(&process_wayland.pointer.mutex); + pthread_mutex_lock(&xdg_data_mutex); pthread_mutex_lock(&surface->mutex);
diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 8932c2c9e8d..e5c456d19e8 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -56,6 +56,13 @@ enum wayland_window_message WM_WAYLAND_INIT_DISPLAY_DEVICES = 0x80001000 };
+struct wayland_pointer +{ + struct wl_pointer *wl_pointer; + HWND focused_hwnd; + pthread_mutex_t mutex; +}; + struct wayland { BOOL initialized; @@ -67,7 +74,7 @@ struct wayland struct xdg_wm_base *xdg_wm_base; struct wl_shm *wl_shm; struct wl_seat *wl_seat; - struct wl_pointer *wl_pointer; + struct wayland_pointer pointer; struct wl_list output_list; /* Protects the output_list and the wayland_output.current states. */ pthread_mutex_t output_mutex;