From: Alexandros Frantzis alexandros.frantzis@collabora.com
The data device is initialized once for each process, from within a dedicated thread and window that handles clipboard events. --- dlls/winewayland.drv/Makefile.in | 1 + dlls/winewayland.drv/dllmain.c | 61 ++++++++++++++++++++++ dlls/winewayland.drv/unixlib.h | 1 + dlls/winewayland.drv/wayland.c | 10 +++- dlls/winewayland.drv/wayland_data_device.c | 55 ++++++++++++++----- dlls/winewayland.drv/waylanddrv.h | 17 ++++-- dlls/winewayland.drv/waylanddrv_main.c | 11 ++++ 7 files changed, 140 insertions(+), 16 deletions(-)
diff --git a/dlls/winewayland.drv/Makefile.in b/dlls/winewayland.drv/Makefile.in index 142db22ba9e..4141e36c9a8 100644 --- a/dlls/winewayland.drv/Makefile.in +++ b/dlls/winewayland.drv/Makefile.in @@ -2,6 +2,7 @@ MODULE = winewayland.drv UNIXLIB = winewayland.so UNIX_CFLAGS = $(EGL_CFLAGS) $(WAYLAND_CLIENT_CFLAGS) $(WAYLAND_EGL_CFLAGS) $(XKBCOMMON_CFLAGS) $(XKBREGISTRY_CFLAGS) UNIX_LIBS = -lwin32u $(WAYLAND_CLIENT_LIBS) $(WAYLAND_EGL_LIBS) $(XKBCOMMON_LIBS) $(XKBREGISTRY_LIBS) $(PTHREAD_LIBS) -lm +IMPORTS = user32 win32u
SOURCES = \ display.c \ diff --git a/dlls/winewayland.drv/dllmain.c b/dlls/winewayland.drv/dllmain.c index d040620957b..8055d883ee0 100644 --- a/dlls/winewayland.drv/dllmain.c +++ b/dlls/winewayland.drv/dllmain.c @@ -20,6 +20,9 @@
#include "waylanddrv_dll.h"
+#include "ntuser.h" +#include "winuser.h" + #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv); @@ -35,6 +38,61 @@ static DWORD WINAPI wayland_read_events_thread(void *arg) return 0; }
+static LRESULT CALLBACK clipboard_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + switch (msg) + { + case WM_NCCREATE: + case WM_CLIPBOARDUPDATE: + case WM_RENDERFORMAT: + case WM_TIMER: + case WM_DESTROYCLIPBOARD: + case WM_USER: + return NtUserMessageCall(hwnd, msg, wp, lp, 0, NtUserClipboardWindowProc, FALSE); + } + + return DefWindowProcW(hwnd, msg, wp, lp); +} + +static DWORD WINAPI clipboard_thread(void *arg) +{ + static const WCHAR clipboard_classname[] = L"__winewayland_clipboard_manager"; + WNDCLASSW class; + ATOM atom; + MSG msg; + HWND hwnd; + + memset(&class, 0, sizeof(class)); + class.lpfnWndProc = clipboard_wndproc; + class.lpszClassName = clipboard_classname; + + if (!(atom = RegisterClassW(&class)) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) + { + ERR("could not register clipboard window class err %lu\n", GetLastError()); + return 0; + } + /* The HWND_MESSAGE parent window may not have been created yet. It will be + * created eventually, so keep trying. */ + while (!(hwnd = CreateWindowW(clipboard_classname, NULL, 0, 0, 0, 0, 0, + HWND_MESSAGE, 0, 0, NULL)) && + GetLastError() == ERROR_INVALID_WINDOW_HANDLE) + { + SwitchToThread(); + } + + if (!hwnd) + { + TRACE("failed to create clipboard window err %lu\n", GetLastError()); + UnregisterClassW(MAKEINTRESOURCEW(atom), NULL); + return 0; + } + + TRACE("created per-process clipboard window hwnd=%p\n", hwnd); + + while (GetMessageW(&msg, 0, 0, 0)) DispatchMessageW(&msg); + return 0; +} + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { DWORD tid; @@ -49,6 +107,9 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
/* Read wayland events from a dedicated thread. */ CloseHandle(CreateThread(NULL, 0, wayland_read_events_thread, NULL, 0, &tid)); + /* Handle clipboard events in a dedicated thread, if needed. */ + if (!WAYLANDDRV_UNIX_CALL(init_clipboard, NULL)) + CloseHandle(CreateThread(NULL, 0, clipboard_thread, NULL, 0, &tid));
return TRUE; } diff --git a/dlls/winewayland.drv/unixlib.h b/dlls/winewayland.drv/unixlib.h index dc3bfdf8893..d9378fe8248 100644 --- a/dlls/winewayland.drv/unixlib.h +++ b/dlls/winewayland.drv/unixlib.h @@ -27,6 +27,7 @@ enum waylanddrv_unix_func { waylanddrv_unix_func_init, waylanddrv_unix_func_read_events, + waylanddrv_unix_func_init_clipboard, waylanddrv_unix_func_count, };
diff --git a/dlls/winewayland.drv/wayland.c b/dlls/winewayland.drv/wayland.c index ee162d8fe77..2a51222fd5f 100644 --- a/dlls/winewayland.drv/wayland.c +++ b/dlls/winewayland.drv/wayland.c @@ -147,8 +147,11 @@ static void registry_handle_global(void *data, struct wl_registry *registry, pthread_mutex_unlock(&seat->mutex); if (process_wayland.zwp_text_input_manager_v3) wayland_text_input_init(); /* Recreate the data device for the new seat. */ - if (process_wayland.data_device.zwlr_data_control_device_v1) + if (process_wayland.data_device.zwlr_data_control_device_v1 || + process_wayland.data_device.wl_data_device) + { wayland_data_device_init(); + } } else if (strcmp(interface, "wp_viewporter") == 0) { @@ -181,6 +184,11 @@ static void registry_handle_global(void *data, struct wl_registry *registry, process_wayland.zwlr_data_control_manager_v1 = wl_registry_bind(registry, id, &zwlr_data_control_manager_v1_interface, 1); } + else if (strcmp(interface, "wl_data_device_manager") == 0) + { + process_wayland.wl_data_device_manager = + wl_registry_bind(registry, id, &wl_data_device_manager_interface, 2); + } }
static void registry_handle_global_remove(void *data, struct wl_registry *registry, diff --git a/dlls/winewayland.drv/wayland_data_device.c b/dlls/winewayland.drv/wayland_data_device.c index 04872df4fcb..472df0a2717 100644 --- a/dlls/winewayland.drv/wayland_data_device.c +++ b/dlls/winewayland.drv/wayland_data_device.c @@ -545,17 +545,29 @@ void wayland_data_device_init(void) TRACE("\n");
pthread_mutex_lock(&data_device->mutex); - if (data_device->zwlr_data_control_device_v1) - zwlr_data_control_device_v1_destroy(data_device->zwlr_data_control_device_v1); - data_device->zwlr_data_control_device_v1 = - zwlr_data_control_manager_v1_get_data_device( - process_wayland.zwlr_data_control_manager_v1, - process_wayland.seat.wl_seat); - if (data_device->zwlr_data_control_device_v1) + if (process_wayland.zwlr_data_control_manager_v1) + { + if (data_device->zwlr_data_control_device_v1) + zwlr_data_control_device_v1_destroy(data_device->zwlr_data_control_device_v1); + data_device->zwlr_data_control_device_v1 = + zwlr_data_control_manager_v1_get_data_device( + process_wayland.zwlr_data_control_manager_v1, + process_wayland.seat.wl_seat); + if (data_device->zwlr_data_control_device_v1) + { + zwlr_data_control_device_v1_add_listener( + data_device->zwlr_data_control_device_v1, &data_control_device_listener, + data_device); + } + } + else if (process_wayland.wl_data_device_manager) { - zwlr_data_control_device_v1_add_listener( - data_device->zwlr_data_control_device_v1, &data_control_device_listener, - data_device); + if (data_device->wl_data_device) + wl_data_device_release(data_device->wl_data_device); + data_device->wl_data_device = + wl_data_device_manager_get_data_device( + process_wayland.wl_data_device_manager, + process_wayland.seat.wl_seat); } pthread_mutex_unlock(&data_device->mutex);
@@ -671,16 +683,35 @@ static void destroy_clipboard(void) pthread_mutex_unlock(&data_device->mutex); }
+static BOOL is_winewayland_clipboard_hwnd(HWND hwnd) +{ + static const WCHAR clipboard_classnameW[] = { + '_','_','w','i','n','e','w','a','y','l','a','n','d','_', + 'c','l','i','p','b','o','a','r','d','_','m','a','n','a','g','e','r'}; + WCHAR buffer[64]; + UNICODE_STRING name = {.Buffer = buffer, .MaximumLength = sizeof(buffer)}; + + if (!NtUserGetClassName(hwnd, FALSE, &name)) return FALSE; + return !wcscmp(buffer, clipboard_classnameW); +} + LRESULT WAYLAND_ClipboardWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch (msg) { case WM_NCCREATE: + /* Disable the default clipboard window in the desktop process if we are + * using the core wl_data_device protocol. */ + if (!process_wayland.zwlr_data_control_manager_v1 && + process_wayland.wl_data_device_manager && + !is_winewayland_clipboard_hwnd(hwnd)) + { + return FALSE; + } clipboard_hwnd = hwnd; NtUserAddClipboardFormatListener(hwnd); pthread_mutex_lock(&process_wayland.seat.mutex); - if (process_wayland.seat.wl_seat && process_wayland.zwlr_data_control_manager_v1) - wayland_data_device_init(); + if (process_wayland.seat.wl_seat) wayland_data_device_init(); pthread_mutex_unlock(&process_wayland.seat.mutex); return TRUE; case WM_CLIPBOARDUPDATE: diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index ead2269b72c..c2fb56dc9bf 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -133,9 +133,19 @@ struct wayland_seat
struct wayland_data_device { - struct zwlr_data_control_device_v1 *zwlr_data_control_device_v1; - struct zwlr_data_control_source_v1 *zwlr_data_control_source_v1; - struct zwlr_data_control_offer_v1 *clipboard_zwlr_data_control_offer_v1; + union + { + struct + { + struct zwlr_data_control_device_v1 *zwlr_data_control_device_v1; + struct zwlr_data_control_source_v1 *zwlr_data_control_source_v1; + struct zwlr_data_control_offer_v1 *clipboard_zwlr_data_control_offer_v1; + }; + struct + { + struct wl_data_device *wl_data_device; + }; + }; pthread_mutex_t mutex; };
@@ -155,6 +165,7 @@ struct wayland struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1; struct zwp_text_input_manager_v3 *zwp_text_input_manager_v3; struct zwlr_data_control_manager_v1 *zwlr_data_control_manager_v1; + struct wl_data_device_manager *wl_data_device_manager; struct wayland_seat seat; struct wayland_keyboard keyboard; struct wayland_pointer pointer; diff --git a/dlls/winewayland.drv/waylanddrv_main.c b/dlls/winewayland.drv/waylanddrv_main.c index 1d4ddeb3425..dba519b1df1 100644 --- a/dlls/winewayland.drv/waylanddrv_main.c +++ b/dlls/winewayland.drv/waylanddrv_main.c @@ -110,10 +110,20 @@ static NTSTATUS waylanddrv_unix_read_events(void *arg) return STATUS_UNSUCCESSFUL; }
+static NTSTATUS waylanddrv_unix_init_clipboard(void *arg) +{ + /* If the compositor supports zwlr_data_control_manager_v1, we don't need + * per-process clipboard window and handling, we can use the default clipboard + * window from the desktop process. */ + if (process_wayland.zwlr_data_control_manager_v1) return STATUS_UNSUCCESSFUL; + return STATUS_SUCCESS; +} + const unixlib_entry_t __wine_unix_call_funcs[] = { waylanddrv_unix_init, waylanddrv_unix_read_events, + waylanddrv_unix_init_clipboard, };
C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == waylanddrv_unix_func_count); @@ -124,6 +134,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = { waylanddrv_unix_init, waylanddrv_unix_read_events, + waylanddrv_unix_init_clipboard, };
C_ASSERT(ARRAYSIZE(__wine_unix_call_wow64_funcs) == waylanddrv_unix_func_count);