From 6f3beca32af75a47255a5c9b37d17bbad50b24c4 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sun, 11 Jul 2021 12:34:04 +0200 Subject: [PATCH] Send XdndPosition messages --- src/wine-host/xdnd-proxy.cpp | 61 +++++++++++++++++++++++++----------- src/wine-host/xdnd-proxy.h | 6 ++++ 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/src/wine-host/xdnd-proxy.cpp b/src/wine-host/xdnd-proxy.cpp index a818ce71..495c0414 100644 --- a/src/wine-host/xdnd-proxy.cpp +++ b/src/wine-host/xdnd-proxy.cpp @@ -44,8 +44,12 @@ constexpr char xdnd_selection_name[] = "XdndSelection"; // xdnd_aware_property_name is defined in `editor.h`` constexpr char xdnd_proxy_property_name[] = "XdndProxy"; constexpr char xdnd_enter_message_name[] = "XdndEnter"; +constexpr char xdnd_position_message_name[] = "XdndPosition"; constexpr char xdnd_leave_message_name[] = "XdndLeave"; +// XDND actions +constexpr char xdnd_copy_action_name[] = "XdndActionCopy"; + // Mime types for use in XDND constexpr char mime_text_uri_list_name[] = "text/uri-list"; constexpr char mime_text_plain_name[] = "text/plain"; @@ -132,9 +136,14 @@ WineXdndProxy::WineXdndProxy() get_atom_by_name(*x11_connection, xdnd_proxy_property_name); xcb_xdnd_enter_message = get_atom_by_name(*x11_connection, xdnd_enter_message_name); + xcb_xdnd_position_message = + get_atom_by_name(*x11_connection, xdnd_position_message_name); xcb_xdnd_leave_message = get_atom_by_name(*x11_connection, xdnd_leave_message_name); + xcb_xdnd_copy_action = + get_atom_by_name(*x11_connection, xdnd_copy_action_name); + xcb_mime_text_uri_list = get_atom_by_name(*x11_connection, mime_text_uri_list_name); xcb_mime_text_plain = @@ -205,13 +214,6 @@ void WineXdndProxy::run_xdnd_loop() { .data->root; const HWND windows_desktop_window = GetDesktopWindow(); - // We cannot just grab the pointer because Wine is already doing that, and - // it's also blocking the GUI thread. So instead we will periodically poll - // the mouse cursor position, and we will consider the disappearance of - // `tracker_window` to mean that the drag-and-drop operation has ended. - std::optional last_pointer_x; - std::optional last_pointer_y; - // FIXME: For some reason you get a -Wmaybe-uninitialized false positive // with GCC 11.1.0 if you just dereference `last_window` here: // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635 @@ -221,13 +223,20 @@ void WineXdndProxy::run_xdnd_loop() { #pragma GCC diagnostic ignored "-Wpragmas" #pragma GCC diagnostic ignored "-Wunknown-warning-option" #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" - std::optional last_window; + + // We cannot just grab the pointer because Wine is already doing that, and + // it's also blocking the GUI thread. So instead we will periodically poll + // the mouse cursor position, and we will consider the disappearance of + // `tracker_window` to mean that the drag-and-drop operation has ended. + std::optional last_pointer_x; + std::optional last_pointer_y; + std::optional last_xdnd_window; auto maybe_leave_last_window = [&]() { - if (last_window) { - send_xdnd_message(*last_window, xcb_xdnd_leave_message, 0, 0, 0, 0); + if (last_xdnd_window) { + send_xdnd_message(*last_xdnd_window, xcb_xdnd_leave_message, 0, 0, + 0, 0); } }; -#pragma GCC diagnostic pop while (IsWindow(tracker_window)) { usleep(1000); @@ -260,7 +269,7 @@ void WineXdndProxy::run_xdnd_loop() { last_pointer_y = xdnd_window_query->root_y; if (!is_xdnd_aware(xdnd_window_query->child)) { maybe_leave_last_window(); - last_window.reset(); + last_xdnd_window.reset(); continue; } @@ -271,13 +280,13 @@ void WineXdndProxy::run_xdnd_loop() { if (HWND windows_window = WindowFromPoint(windows_pointer_pos); windows_window && windows_window != windows_desktop_window) { maybe_leave_last_window(); - last_window.reset(); + last_xdnd_window.reset(); continue; } - // When transitioning between windows we need to announce this to both - // windows - if (last_window != xdnd_window_query->child) { + // When transitioning between windows we need to announce this to + // both windows + if (last_xdnd_window != xdnd_window_query->child) { maybe_leave_last_window(); // We need to announce which file formats we support. There are a @@ -288,15 +297,29 @@ void WineXdndProxy::run_xdnd_loop() { send_xdnd_message(xdnd_window_query->child, xcb_xdnd_enter_message, 5 << 24, xcb_mime_text_uri_list, xcb_mime_text_plain, XCB_NONE); - - xcb_flush(x11_connection.get()); } + // When the pointer is being moved inside of a window, we should + // continuously send `XdndPosition` messages to that window + if (last_xdnd_window) { + // XXX: We'll always stick with the copy action for now because that + // seems safer than allowing the host to move the file + send_xdnd_message( + xdnd_window_query->child, xcb_xdnd_position_message, 0, + (xdnd_window_query->root_x << 16) | xdnd_window_query->root_y, + XCB_CURRENT_TIME, xcb_xdnd_copy_action); + } + + // For efficiency's sake we'll only flush all of the client messages + // we're sending once at the end of every cycle // TODO: Fetch the window under the mouse cursor, send messages to it // according to the XDND protocol - last_window = xdnd_window_query->child; + last_xdnd_window = xdnd_window_query->child; + xcb_flush(x11_connection.get()); } +#pragma GCC diagnostic pop + // TODO: Check if the escape key is pressed to allow cancelling the drop, // and either send the drop or leave message to the window that was // under the pointer diff --git a/src/wine-host/xdnd-proxy.h b/src/wine-host/xdnd-proxy.h index 128e85ba..bb2deec6 100644 --- a/src/wine-host/xdnd-proxy.h +++ b/src/wine-host/xdnd-proxy.h @@ -250,8 +250,14 @@ class WineXdndProxy { xcb_atom_t xcb_xdnd_aware_property; xcb_atom_t xcb_xdnd_proxy_property; xcb_atom_t xcb_xdnd_enter_message; + xcb_atom_t xcb_xdnd_position_message; xcb_atom_t xcb_xdnd_leave_message; + // XDND specifies various actions for drag-and-drop, but since the file is + // technically still owned by the plugin we'll just stick with copies to be + // safe + xcb_atom_t xcb_xdnd_copy_action; + // Mime types for use in XDND, we'll only support dragging links since that // is the foramt the Windows OLE drag-and-drop provides us xcb_atom_t xcb_mime_text_uri_list;