From: Alexandros Frantzis alexandros.frantzis@collabora.com
Every thread that requires interaction with Wayland maintains its own independent set of Wayland protocols objects. Events from Wayland protocol objects are dispatched into a thread-specific Wayland event queue.
This design simplifies synchronization, since there is no shared Wayland state between threads, and will later make it easier to dispatch events to the proper thread message queue. The downside is that there is some duplication of event handling if multiple GUI threads are present.
Signed-off-by: Alexandros Frantzis alexandros.frantzis@collabora.com --- dlls/winewayland.drv/wayland.c | 132 +++++++++++++++++++++++++ dlls/winewayland.drv/waylanddrv.h | 27 +++++ dlls/winewayland.drv/waylanddrv_main.c | 10 ++ 3 files changed, 169 insertions(+)
diff --git a/dlls/winewayland.drv/wayland.c b/dlls/winewayland.drv/wayland.c index 9b61427c8aa..852226cbb59 100644 --- a/dlls/winewayland.drv/wayland.c +++ b/dlls/winewayland.drv/wayland.c @@ -26,8 +26,140 @@
#include "waylanddrv.h"
+#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv); + struct wl_display *process_wl_display = NULL;
+static struct wayland_mutex thread_wayland_mutex = +{ + PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, 0, 0, __FILE__ ": thread_wayland_mutex" +}; + +static struct wl_list thread_wayland_list = {&thread_wayland_list, &thread_wayland_list}; + +/********************************************************************** + * Registry handling + */ + +static void registry_handle_global(void *data, struct wl_registry *registry, + uint32_t id, const char *interface, + uint32_t version) +{ + struct wayland *wayland = data; + + TRACE("interface=%s version=%d\n id=%u\n", interface, version, id); + + if (strcmp(interface, "wl_compositor") == 0) + { + wayland->wl_compositor = + wl_registry_bind(registry, id, &wl_compositor_interface, 4); + } +} + +static void registry_handle_global_remove(void *data, struct wl_registry *registry, + uint32_t id) +{ + TRACE("id=%d\n", id); +} + +static const struct wl_registry_listener registry_listener = { + registry_handle_global, + registry_handle_global_remove +}; + +/********************************************************************** + * wayland_init + * + * Initialise a wayland instance. + */ +BOOL wayland_init(struct wayland *wayland) +{ + struct wl_display *wl_display_wrapper; + + TRACE("wayland=%p wl_display=%p\n", wayland, process_wl_display); + + wl_list_init(&wayland->thread_link); + + wayland->process_id = GetCurrentProcessId(); + wayland->thread_id = GetCurrentThreadId(); + wayland->wl_display = process_wl_display; + + if (!wayland->wl_display) + { + ERR("Failed to connect to wayland compositor\n"); + return FALSE; + } + + if (!(wayland->wl_event_queue = wl_display_create_queue(wayland->wl_display))) + { + ERR("Failed to create event queue\n"); + return FALSE; + } + + if (!(wl_display_wrapper = wl_proxy_create_wrapper(wayland->wl_display))) + { + ERR("Failed to create proxy wrapper for wl_display\n"); + return FALSE; + } + wl_proxy_set_queue((struct wl_proxy *) wl_display_wrapper, wayland->wl_event_queue); + + wayland->wl_registry = wl_display_get_registry(wl_display_wrapper); + wl_proxy_wrapper_destroy(wl_display_wrapper); + if (!wayland->wl_registry) + { + ERR("Failed to get to wayland registry\n"); + return FALSE; + } + + /* Populate registry */ + wl_registry_add_listener(wayland->wl_registry, ®istry_listener, wayland); + + /* We need three roundtrips. One to get and bind globals, one to handle all + * initial events produced from registering the globals and one more to + * handle potential third-order registrations. */ + wl_display_roundtrip_queue(wayland->wl_display, wayland->wl_event_queue); + wl_display_roundtrip_queue(wayland->wl_display, wayland->wl_event_queue); + wl_display_roundtrip_queue(wayland->wl_display, wayland->wl_event_queue); + + /* Keep a list of all thread wayland instances. */ + wayland_mutex_lock(&thread_wayland_mutex); + wl_list_insert(&thread_wayland_list, &wayland->thread_link); + wayland_mutex_unlock(&thread_wayland_mutex); + + wayland->initialized = TRUE; + + return TRUE; +} + +/********************************************************************** + * wayland_deinit + * + * Deinitialise a wayland instance, releasing all associated resources. + */ +void wayland_deinit(struct wayland *wayland) +{ + TRACE("%p\n", wayland); + + wayland_mutex_lock(&thread_wayland_mutex); + wl_list_remove(&wayland->thread_link); + wayland_mutex_unlock(&thread_wayland_mutex); + + if (wayland->wl_compositor) + wl_compositor_destroy(wayland->wl_compositor); + + if (wayland->wl_registry) + wl_registry_destroy(wayland->wl_registry); + + if (wayland->wl_event_queue) + wl_event_queue_destroy(wayland->wl_event_queue); + + wl_display_flush(wayland->wl_display); + + memset(wayland, 0, sizeof(*wayland)); +} + /********************************************************************** * wayland_process_init * diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 6c1cd770a6d..ee6ee2589a8 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -53,12 +53,25 @@ struct wayland_mutex const char *name; };
+struct wayland +{ + struct wl_list thread_link; + BOOL initialized; + DWORD process_id; + DWORD thread_id; + struct wl_display *wl_display; + struct wl_event_queue *wl_event_queue; + struct wl_registry *wl_registry; + struct wl_compositor *wl_compositor; +}; + /********************************************************************** * Wayland thread data */
struct wayland_thread_data { + struct wayland wayland; };
extern struct wayland_thread_data *wayland_init_thread_data(void) DECLSPEC_HIDDEN; @@ -68,11 +81,25 @@ static inline struct wayland_thread_data *wayland_thread_data(void) return (struct wayland_thread_data *)(UINT_PTR)NtUserGetThreadInfo()->driver_data; }
+static inline struct wayland *thread_init_wayland(void) +{ + return &wayland_init_thread_data()->wayland; +} + +static inline struct wayland *thread_wayland(void) +{ + struct wayland_thread_data *data = wayland_thread_data(); + if (!data) return NULL; + return &data->wayland; +} + /********************************************************************** * Wayland initialization */
BOOL wayland_process_init(void) DECLSPEC_HIDDEN; +BOOL wayland_init(struct wayland *wayland) DECLSPEC_HIDDEN; +void wayland_deinit(struct wayland *wayland) DECLSPEC_HIDDEN;
/********************************************************************** * Wayland mutex diff --git a/dlls/winewayland.drv/waylanddrv_main.c b/dlls/winewayland.drv/waylanddrv_main.c index 10410157709..787d837cc0b 100644 --- a/dlls/winewayland.drv/waylanddrv_main.c +++ b/dlls/winewayland.drv/waylanddrv_main.c @@ -35,6 +35,7 @@ #include <stdlib.h>
WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv); +WINE_DECLARE_DEBUG_CHANNEL(winediag);
/*********************************************************************** * Initialize per thread data @@ -51,6 +52,14 @@ struct wayland_thread_data *wayland_init_thread_data(void) NtTerminateProcess(0, 1); }
+ if (!wayland_init(&data->wayland)) + { + ERR_(winediag)("waylanddrv: Can't open wayland display. Please ensure " + "that your wayland server is running and that " + "$WAYLAND_DISPLAY is set correctly.\n"); + NtTerminateProcess(0, 1); + } + NtUserGetThreadInfo()->driver_data = (UINT_PTR)data;
return data; @@ -65,6 +74,7 @@ static void WAYLAND_ThreadDetach(void)
if (data) { + wayland_deinit(&data->wayland); free(data); /* clear data in case we get re-entered from user32 before the thread is truly dead */ NtUserGetThreadInfo()->driver_data = 0;