From ec41ec1c81769ef61d84e9cb1966dcedc6aa0480 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sun, 22 Aug 2021 16:43:02 +0200 Subject: [PATCH] Add a warmup phase to the XDND implementation This fixes short drops being ignored. Bitwig does this, and I've also seen some Qt applications do this. --- src/wine-host/xdnd-proxy.cpp | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/wine-host/xdnd-proxy.cpp b/src/wine-host/xdnd-proxy.cpp index 44ffc71e..f205528d 100644 --- a/src/wine-host/xdnd-proxy.cpp +++ b/src/wine-host/xdnd-proxy.cpp @@ -342,6 +342,17 @@ void WineXdndProxy::run_xdnd_loop() { waiting_for_status_message = false; }; + // HACK: Bitwig Studio seems to always deny the drop for the first couple of + // `XdndPosition` messages. To work around this, we'll make sure the + // dragging goes on for at least 200 milliseconds, and we'll allow + // repeat position requests for the same coordinates during that part. + // Normally this wouldn't be necessary, but Samplab's drag-and-drop + // operation lasts only a fraction of a second, so we need to prolong + // this a bit for Bitwig to accept the drop. + const std::chrono::steady_clock::time_point drag_loop_start = + std::chrono::steady_clock::now(); + bool xdnd_warmup_active = true; + // 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 end the drag once the left mouse @@ -350,7 +361,16 @@ void WineXdndProxy::run_xdnd_loop() { bool escape_pressed = false; std::optional last_pointer_x; std::optional last_pointer_y; - while (left_mouse_button_held && !escape_pressed) { + while (xdnd_warmup_active || (left_mouse_button_held && !escape_pressed)) { + // See above for why we need to do this. We'll also stop this warmup + // phase once the host accepts the drop (since at that point it's no + // longer necessary). + if (xdnd_warmup_active) { + xdnd_warmup_active = + !last_window_accepted_status || + std::chrono::steady_clock::now() - drag_loop_start <= 200ms; + } + std::this_thread::sleep_for(1ms); std::unique_ptr generic_event; @@ -408,9 +428,12 @@ void WineXdndProxy::run_xdnd_loop() { // prematurely. This seems to often happen with JUCE plugins. We // will still continue with the dragging operation, although at // that point the mouse pointer isn't grabbed by anything anymore. + // NOTE: During the first couple of milliseconds we'll spam the host, + // see above for why this is necessary left_mouse_button_held = xdnd_window_query->mask & XCB_BUTTON_MASK_1; if (xdnd_window_query->root_x == last_pointer_x && - xdnd_window_query->root_y == last_pointer_y) { + xdnd_window_query->root_y == last_pointer_y && + !xdnd_warmup_active) { continue; }