mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-07 03:50:11 +02:00
Store the dragged files so we can use them in XDND
This commit is contained in:
@@ -14,8 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "boost-fix.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
// Generated inside of the build directory
|
||||
|
||||
@@ -17,10 +17,12 @@
|
||||
#include "xdnd-proxy.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
// FIXME: Remove
|
||||
#include <iostream>
|
||||
|
||||
#include "boost-fix.h"
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
/**
|
||||
* The window class name Wine uses for its `DoDragDrop()` tracker window.
|
||||
*
|
||||
@@ -28,6 +30,25 @@
|
||||
*/
|
||||
static constexpr char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";
|
||||
|
||||
/**
|
||||
* We're doing a bit of a hybrid between a COM-style reference counted smart
|
||||
* pointer and a singleton here because we need to ensure that there's only one
|
||||
* proxy per process, but we want to free up the X11 connection when it's not
|
||||
* needed anymore. Because of that this pointer may point to deallocated memory,
|
||||
* so the reference count should be leading here. Oh and explained elsewhere, we
|
||||
* won't even bother making this thread safe because it can only be called from
|
||||
* the GUI thread anyways.
|
||||
*/
|
||||
static WineXdndProxy* instance = nullptr;
|
||||
|
||||
/**
|
||||
* The number of handles to our Wine->X11 drag-and-drop proxy object. To prevent
|
||||
* running out of X11 connections when opening and closing a lot of plugin
|
||||
* editors in a project, we'll free this again after the last editor in this
|
||||
* process gets closed.
|
||||
*/
|
||||
static std::atomic_size_t instance_reference_count = 0;
|
||||
|
||||
/**
|
||||
* Part of the struct Wine uses to keep track of the data during an OLE
|
||||
* drag-and-drop operation. We only really care about the first field that
|
||||
@@ -84,11 +105,19 @@ void CALLBACK dnd_winevent_callback(HWINEVENTHOOK /*hWinEventHook*/,
|
||||
return;
|
||||
}
|
||||
|
||||
std::array<FORMATETC, 16> supported_formats;
|
||||
// The plugin will indicate which formats they support for the
|
||||
// drag-and-drop. In practice this is always going to be a single `HDROP`
|
||||
// (through some `HGLOBAL` global memory) that contains a single file path.
|
||||
// With this information we will set up XDND with those file paths, so we
|
||||
// can drop the files onto native applications.
|
||||
std::array<FORMATETC, 16> supported_formats{};
|
||||
unsigned int num_formats = 0;
|
||||
enumerator->Next(supported_formats.size(), supported_formats.data(),
|
||||
&num_formats);
|
||||
enumerator->Release();
|
||||
|
||||
// This will contain the normal, Unix-style paths to the files
|
||||
boost::container::small_vector<std::string, 4> dragged_files;
|
||||
for (unsigned int format_idx = 0; format_idx < num_formats; format_idx++) {
|
||||
STGMEDIUM storage{};
|
||||
if (HRESULT result = tracker_info->dataObject->GetData(
|
||||
@@ -97,33 +126,31 @@ void CALLBACK dnd_winevent_callback(HWINEVENTHOOK /*hWinEventHook*/,
|
||||
switch (storage.tymed) {
|
||||
case TYMED_HGLOBAL: {
|
||||
auto drop = static_cast<HDROP>(GlobalLock(storage.hGlobal));
|
||||
if (!drop) {
|
||||
std::cerr << "Failed to lock global memory in "
|
||||
"drag-and-drop operation"
|
||||
<< std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::array<WCHAR, 1024> file_name{0};
|
||||
const uint32_t num_files = DragQueryFileW(
|
||||
drop, 0xFFFFFFFF, file_name.data(), file_name.size());
|
||||
|
||||
std::cerr << "Plugin wanted to drag-and-drop " << num_files
|
||||
<< (num_files == 1 ? " file:" : " files:")
|
||||
<< std::endl;
|
||||
for (uint32_t file_idx = 0; file_idx < num_files;
|
||||
file_idx++) {
|
||||
file_name[0] = 0;
|
||||
DragQueryFileW(drop, file_idx, file_name.data(),
|
||||
file_name.size());
|
||||
|
||||
std::cerr << "- "
|
||||
<< wine_get_unix_file_name(file_name.data())
|
||||
<< std::endl;
|
||||
dragged_files.emplace_back(
|
||||
wine_get_unix_file_name(file_name.data()));
|
||||
}
|
||||
|
||||
GlobalUnlock(GlobalLock(storage.hGlobal));
|
||||
GlobalUnlock(storage.hGlobal);
|
||||
} break;
|
||||
case TYMED_FILE: {
|
||||
std::cerr << "Plugin wanted to drag-and-drop 1 file:"
|
||||
<< std::endl;
|
||||
std::cerr << "- "
|
||||
<< wine_get_unix_file_name(storage.lpszFileName)
|
||||
<< std::endl;
|
||||
dragged_files.emplace_back(
|
||||
wine_get_unix_file_name(storage.lpszFileName));
|
||||
} break;
|
||||
default: {
|
||||
std::cerr << "Unknown drag-and-drop format "
|
||||
@@ -136,6 +163,26 @@ void CALLBACK dnd_winevent_callback(HWINEVENTHOOK /*hWinEventHook*/,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dragged_files.empty()) {
|
||||
std::cerr
|
||||
<< "Plugin wanted to drag-and-drop, but didn't specify any files"
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::cerr << "Plugin wanted to drag-and-drop " << dragged_files.size()
|
||||
<< (dragged_files.size() == 1 ? " file:" : " files:")
|
||||
<< std::endl;
|
||||
for (const auto& file : dragged_files) {
|
||||
std::cerr << "- " << file << std::endl;
|
||||
}
|
||||
|
||||
// This shouldn't be possible, but you can never be too sure!
|
||||
if (instance_reference_count <= 0 || !instance) {
|
||||
std::cerr << "Drag-and-drop proxy wasn't initialized yet" << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
WineXdndProxy::WineXdndProxy()
|
||||
@@ -150,14 +197,6 @@ WineXdndProxy::WineXdndProxy()
|
||||
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS),
|
||||
UnhookWinEvent) {}
|
||||
|
||||
/**
|
||||
* The number of handles to our Wine->X11 drag-and-drop proxy object. To prevent
|
||||
* running out of X11 connections when opening and closing a lot of plugin
|
||||
* editors in a project, we'll free this again after the last editor in this
|
||||
* process gets closed.
|
||||
*/
|
||||
static std::atomic_size_t instance_reference_count = 0;
|
||||
|
||||
WineXdndProxy::Handle::Handle(WineXdndProxy* proxy) : proxy(proxy) {}
|
||||
|
||||
WineXdndProxy::Handle::~Handle() noexcept {
|
||||
@@ -175,14 +214,8 @@ WineXdndProxy::Handle::Handle(Handle&& o) noexcept : proxy(o.proxy) {
|
||||
}
|
||||
|
||||
WineXdndProxy::Handle WineXdndProxy::init_proxy() {
|
||||
// We're doing a bit of a hybrid between a COM-style reference counted smart
|
||||
// pointer and a singleton here because we need to ensure that there's only
|
||||
// one proxy per process, but we want to free up the X11 connection when
|
||||
// it's not needed anymore. Because of that this pointer may point to
|
||||
// deallocated memory, so the reference count should be leading here. Oh and
|
||||
// explained elsewhere, we won't even bother making this thread safe because
|
||||
// it can only be called from the GUI thread anyways.
|
||||
static WineXdndProxy* instance = nullptr;
|
||||
// See the `instance` global above for an explanation on what's going on
|
||||
// here.
|
||||
if (instance_reference_count.fetch_add(1) == 0) {
|
||||
instance = new WineXdndProxy{};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user