From 3372f4424ea31d88a888908b1200e9e787a72ee6 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sat, 10 Jul 2021 16:43:23 +0200 Subject: [PATCH] Create a window for the X11 proxy --- src/wine-host/xdnd-proxy.cpp | 46 ++++++++++++++++++++++++++++-------- src/wine-host/xdnd-proxy.h | 43 +++++++++++++++++++++++++++++++-- 2 files changed, 77 insertions(+), 12 deletions(-) diff --git a/src/wine-host/xdnd-proxy.cpp b/src/wine-host/xdnd-proxy.cpp index 6d0277b8..64346be5 100644 --- a/src/wine-host/xdnd-proxy.cpp +++ b/src/wine-host/xdnd-proxy.cpp @@ -57,9 +57,43 @@ void CALLBACK dnd_winevent_callback(HWINEVENTHOOK hWinEventHook, DWORD idEventThread, DWORD dwmsEventTime); +ProxyWindow::ProxyWindow(std::shared_ptr x11_connection) + : x11_connection(x11_connection), + window(xcb_generate_id(x11_connection.get())) { + const xcb_screen_t* screen = + xcb_setup_roots_iterator(xcb_get_setup(x11_connection.get())).data; + + xcb_create_window(x11_connection.get(), XCB_COPY_FROM_PARENT, window, + screen->root, 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY, + XCB_COPY_FROM_PARENT, 0, nullptr); + xcb_flush(x11_connection.get()); +} + +ProxyWindow::~ProxyWindow() noexcept { + if (!is_moved) { + xcb_destroy_window(x11_connection.get(), window); + xcb_flush(x11_connection.get()); + } +} + +ProxyWindow::ProxyWindow(ProxyWindow&& o) noexcept + : x11_connection(std::move(o.x11_connection)), window(std::move(o.window)) { + o.is_moved = true; +} +ProxyWindow& ProxyWindow::operator=(ProxyWindow&& o) noexcept { + if (&o != this) { + x11_connection = std::move(o.x11_connection); + window = std::move(o.window); + + o.is_moved = true; + } + + return *this; +} + WineXdndProxy::WineXdndProxy() : x11_connection(xcb_connect(nullptr, nullptr), xcb_disconnect), - proxy_window(xcb_generate_id(x11_connection.get())), + proxy_window(x11_connection), hook_handle( SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE, @@ -68,15 +102,7 @@ WineXdndProxy::WineXdndProxy() 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS), - UnhookWinEvent) { - // -} - -WineXdndProxy::~WineXdndProxy() noexcept { - // TODO: Move this to a RAII wrapper - xcb_destroy_window(x11_connection.get(), proxy_window); - xcb_flush(x11_connection.get()); -} + UnhookWinEvent) {} WineXdndProxy::Handle::Handle(WineXdndProxy* proxy) : proxy(proxy) {} diff --git a/src/wine-host/xdnd-proxy.h b/src/wine-host/xdnd-proxy.h index 2bd6a41b..1818d8f9 100644 --- a/src/wine-host/xdnd-proxy.h +++ b/src/wine-host/xdnd-proxy.h @@ -26,6 +26,35 @@ #include +/** + * A simple, unmapped 1x1 proxy window we'll use for our Wine->X11 drag-and-drop + * proxy so we can send and receive client messages. + */ +class ProxyWindow { + public: + /** + * Create the proxy window. + */ + ProxyWindow(std::shared_ptr x11_connection); + + /** + * Destroy the window again when this object gets dropped. + */ + ~ProxyWindow() noexcept; + + ProxyWindow(const ProxyWindow&) noexcept = delete; + ProxyWindow& operator=(const ProxyWindow&) noexcept = delete; + + ProxyWindow(ProxyWindow&&) noexcept; + ProxyWindow& operator=(ProxyWindow&&) noexcept; + + private: + std::shared_ptr x11_connection; + xcb_window_t window; + + bool is_moved = false; +}; + /** * A simple wrapper that registers a WinEvents hook to listen for new windows * being created, and handles XDND client messages to achieve the behaviour @@ -33,6 +62,9 @@ */ class WineXdndProxy { protected: + /** + * Initialize the proxy and register all hooks. + */ WineXdndProxy(); public: @@ -106,13 +138,20 @@ class WineXdndProxy { void handle_x11_events() const noexcept; private: - std::unique_ptr x11_connection; + /** + * We need a dedicated X11 connection for our proxy because we can have + * multiple open editors in a single process (e.g. when using VST3 plugins + * or plugin groups), and client messages are sent to the X11 connection + * that created the window. So we cannot just reuse the connection from the + * editor. + */ + std::shared_ptr x11_connection; /** * We need an unmapped proxy window to send and receive client messages for * the XDND protocol. */ - xcb_window_t proxy_window; + ProxyWindow proxy_window; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wignored-attributes"