Fix dropping files in Wayland

There were two problems dropping files into blender:

- The inputs `focus_pointer` was NULL, causing a crash.
- The wl_data_device_manager version was set to 1, causing the Blender
  window to close (when dropping files in gnome-shell 42).

Resolve by storing the drop surface separately from the pointer surface
and bump the device manager version to 3.
This commit is contained in:
Campbell Barton 2022-06-10 16:32:22 +10:00
parent 178c184825
commit 00aa57594c
1 changed files with 15 additions and 6 deletions

View File

@ -38,6 +38,8 @@
#include <cstring>
static GHOST_IWindow *get_window(struct wl_surface *surface);
/* -------------------------------------------------------------------- */
/** \name Private Types & Defines
* \{ */
@ -131,6 +133,7 @@ struct input_t {
struct wl_surface *focus_pointer = nullptr;
struct wl_surface *focus_keyboard = nullptr;
struct wl_surface *focus_dnd = nullptr;
struct wl_data_device *data_device = nullptr;
/** Drag & Drop. */
@ -508,7 +511,7 @@ static void dnd_events(const input_t *const input, const GHOST_TEventType event)
{
const uint64_t time = input->system->getMilliSeconds();
GHOST_IWindow *const window = static_cast<GHOST_WindowWayland *>(
wl_surface_get_user_data(input->focus_pointer));
wl_surface_get_user_data(input->focus_dnd));
for (const std::string &type : mime_preference_order) {
input->system->pushEvent(new GHOST_EventDragnDrop(time,
event,
@ -670,7 +673,7 @@ static void data_device_data_offer(void * /*data*/,
static void data_device_enter(void *data,
struct wl_data_device * /*wl_data_device*/,
uint32_t serial,
struct wl_surface * /*surface*/,
struct wl_surface *surface,
wl_fixed_t x,
wl_fixed_t y,
struct wl_data_offer *id)
@ -692,6 +695,7 @@ static void data_device_enter(void *data,
wl_data_offer_accept(id, serial, type.c_str());
}
input->focus_dnd = surface;
dnd_events(input, GHOST_kEventDraggingEntered);
}
@ -700,6 +704,7 @@ static void data_device_leave(void *data, struct wl_data_device * /*wl_data_devi
input_t *input = static_cast<input_t *>(data);
dnd_events(input, GHOST_kEventDraggingExited);
input->focus_dnd = nullptr;
if (input->data_offer_dnd && !input->data_offer_dnd->in_use.load()) {
wl_data_offer_destroy(input->data_offer_dnd->id);
@ -732,6 +737,7 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic
auto read_uris = [](input_t *const input,
data_offer_t *data_offer,
wl_surface *surface,
const std::string mime_receive) {
const int x = data_offer->dnd.x;
const int y = data_offer->dnd.y;
@ -750,6 +756,9 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic
static constexpr const char *file_proto = "file://";
static constexpr const char *crlf = "\r\n";
GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(surface));
GHOST_ASSERT(win != nullptr, "Unable to find window for drop event from surface");
std::vector<std::string> uris;
size_t pos = 0;
@ -773,8 +782,6 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic
flist->strings[i] = static_cast<uint8_t *>(malloc((uris[i].size() + 1) * sizeof(uint8_t)));
memcpy(flist->strings[i], uris[i].data(), uris[i].size() + 1);
}
GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
wl_surface_get_user_data(input->focus_pointer));
system->pushEvent(new GHOST_EventDragnDrop(system->getMilliSeconds(),
GHOST_kEventDraggingDropDone,
GHOST_kDragnDropTypeFilenames,
@ -790,7 +797,9 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic
wl_display_roundtrip(system->display());
};
std::thread read_thread(read_uris, input, data_offer, mime_receive);
/* Pass in `input->focus_dnd` instead of accessing it from `input` since the leave callback
* (#data_device_leave) will clear the value once this function starts. */
std::thread read_thread(read_uris, input, data_offer, input->focus_dnd, mime_receive);
read_thread.detach();
}
@ -1480,7 +1489,7 @@ static void global_add(void *data,
}
else if (!strcmp(interface, wl_data_device_manager_interface.name)) {
display->data_device_manager = static_cast<wl_data_device_manager *>(
wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, 1));
wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, 3));
}
else if (!strcmp(interface, zwp_relative_pointer_manager_v1_interface.name)) {
display->relative_pointer_manager = static_cast<zwp_relative_pointer_manager_v1 *>(