From b6fd0405fb83d43eed5b0a09b64049d16cefbb7a Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sun, 11 Jul 2021 13:20:36 +0200 Subject: [PATCH] Transform the file list into text/uri-list format --- src/wine-host/xdnd-proxy.cpp | 28 +++++++++++++++++++++++++++- src/wine-host/xdnd-proxy.h | 5 +++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/wine-host/xdnd-proxy.cpp b/src/wine-host/xdnd-proxy.cpp index 495c0414..6ef92ec5 100644 --- a/src/wine-host/xdnd-proxy.cpp +++ b/src/wine-host/xdnd-proxy.cpp @@ -18,6 +18,7 @@ #include #include +#include #include "editor.h" @@ -179,6 +180,10 @@ WineXdndProxy::Handle WineXdndProxy::get_handle() { void WineXdndProxy::begin_xdnd( const boost::container::small_vector_base& file_paths, HWND tracker_window) { + if (file_paths.empty()) { + throw std::runtime_error("Cannot drag-and-drop without any files"); + } + // When XDND starts, we need to start listening for mouse events so we can // react when the mouse cursor hovers over a target that supports XDND. The // actual file contents will be transferred over X11 selections. See the @@ -188,13 +193,34 @@ void WineXdndProxy::begin_xdnd( xcb_xdnd_selection, XCB_CURRENT_TIME); xcb_flush(x11_connection.get()); + // We will transfer the files in `text/uri-list` format, so a string of URIs + // separated by line feeds. When the target window requests the selection to + // be converted, they will ask us to write this to a property on their + // window + // TODO: Like with the desktop notifications, we do not yet perform any + // escaping here + constexpr char file_protocol[] = "file://"; + dragged_files_uri_list.reserve( + std::accumulate(file_paths.begin() + 1, file_paths.end(), + file_paths[0].size() + strlen(file_protocol) - 1, + [file_protocol](size_t size, const auto& path) { + return size + (strlen(file_protocol) - 1) + + path.size() + sizeof('\n'); + })); + dragged_files_uri_list.assign(file_protocol); + dragged_files_uri_list.append(file_paths[0]); + for (size_t i = 1; i < file_paths.size(); i++) { + dragged_files_uri_list.push_back('\n'); + dragged_files_uri_list.append(file_protocol); + dragged_files_uri_list.append(file_paths[i]); + } + // Normally at this point you would grab the mouse pointer and track what // windows it's moving over. Wine is already doing this, so as a hacky // workaround we will instead just periodically poll the pointer position in // `WineXdndProxy::handle_x11_events()`, and we'll consider the // disappearance of `tracker_window` to indicate that the drag-and-drop has // either been cancelled or it has succeeded. - dragged_file_paths.assign(file_paths.begin(), file_paths.end()); this->tracker_window = tracker_window; // Because Wine is blocking the GUI thread, we need to do our XDND polling diff --git a/src/wine-host/xdnd-proxy.h b/src/wine-host/xdnd-proxy.h index bb2deec6..20c869d5 100644 --- a/src/wine-host/xdnd-proxy.h +++ b/src/wine-host/xdnd-proxy.h @@ -221,9 +221,10 @@ class WineXdndProxy { #pragma GCC diagnostic pop /** - * The files that are currently being dragged. + * The files that are currently being dragged, stored as in `text/uri-list` + * format (i.e. a list of URIs, separated by line feeds) */ - boost::container::small_vector dragged_file_paths; + std::string dragged_files_uri_list; /** * Wine's tracker window for tracking the drag-and-drop operation. Normally