From a478436af61c6ce6e786c74344fb5e22f5c23554 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Mon, 12 Jul 2021 12:21:52 +0200 Subject: [PATCH] Make sure the Windows dnd operation terminates I've seen a weird edge case where this doesn't happen once, but i haven't been able to reproduce it. Hopefully this fixes it. --- src/wine-host/xdnd-proxy.cpp | 20 ++++++++++++++++---- src/wine-host/xdnd-proxy.h | 14 +++++++++++--- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/wine-host/xdnd-proxy.cpp b/src/wine-host/xdnd-proxy.cpp index 56672d2f..b60e25dd 100644 --- a/src/wine-host/xdnd-proxy.cpp +++ b/src/wine-host/xdnd-proxy.cpp @@ -194,9 +194,9 @@ WineXdndProxy::Handle WineXdndProxy::get_handle() { return Handle(instance); } -void WineXdndProxy::begin_xdnd( - const boost::container::small_vector_base& - file_paths) { +void WineXdndProxy::begin_xdnd(const boost::container::small_vector_base< + boost::filesystem::path>& file_paths, + HWND tracker_window) { if (file_paths.empty()) { throw std::runtime_error("Cannot drag-and-drop without any files"); } @@ -236,6 +236,7 @@ void WineXdndProxy::begin_xdnd( // the left mouse button gets released. Because Wine is also blocking the // GUI thread, we need to do our XDND polling from another thread. Luckily // the X11 API is thread safe. + this->tracker_window = tracker_window; xdnd_handler = Win32Thread([&]() { run_xdnd_loop(); }); } @@ -479,6 +480,9 @@ void WineXdndProxy::run_xdnd_loop() { // In case that window somehow becomes unresponsive or disappears, we // will set a timeout here to avoid hanging if (std::chrono::steady_clock::now() - wait_start > 5s) { + // Just to make it extra clear that we don't want to interfere with + // Wine's own drag-and-drop if we reach a timeout + drop_finished = false; maybe_leave_last_window(); break; } @@ -535,6 +539,12 @@ void WineXdndProxy::run_xdnd_loop() { } } + // Make sure the Windows drag-and-drop operation doesn't get stuck for + // whatever reason (it shouldn't but who knows) + if (drop_finished) { + PostMessageW(tracker_window, WM_QUIT, 0, 0); + } + end_xdnd(); } @@ -841,8 +851,10 @@ void CALLBACK dnd_winevent_callback(HWINEVENTHOOK /*hWinEventHook*/, return; } + PostMessageW(hwnd, WM_QUIT, 0, 0); + try { - instance->begin_xdnd(dragged_files); + instance->begin_xdnd(dragged_files, hwnd); } catch (const std::exception& error) { std::cerr << "XDND initialization failed:" << std::endl; std::cerr << error.what() << std::endl; diff --git a/src/wine-host/xdnd-proxy.h b/src/wine-host/xdnd-proxy.h index b90396e2..2c501aea 100644 --- a/src/wine-host/xdnd-proxy.h +++ b/src/wine-host/xdnd-proxy.h @@ -136,9 +136,9 @@ class WineXdndProxy { * Initiate the XDDN protocol by taking ownership of the `XdndSelection` * selection and setting up the event listeners. */ - void begin_xdnd( - const boost::container::small_vector_base& - file_paths); + void begin_xdnd(const boost::container::small_vector_base< + boost::filesystem::path>& file_paths, + HWND tracker_window); /** * Release ownership of the selection stop listening for X11 events. @@ -240,6 +240,14 @@ class WineXdndProxy { */ std::string dragged_files_uri_list; + /** + * Wine's tracker window for tracking the drag-and-drop operation. When the + * XDND operation succeeds, we make sure to close this window to avoid the + * potential for weird race conditions where the plugin may still think + * we're doing drag-and-drop. + */ + HWND tracker_window; + /** * We need to poll for mouse position changes from another thread, because * when the drag-and-drop operation starts Wine will be blocking the GUI