From 00aa57594c74c69d53ba326e48d2d1339ab99b75 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 10 Jun 2022 16:32:22 +1000 Subject: 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. --- intern/ghost/intern/GHOST_SystemWayland.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp index c446963c082..b9696ab6354 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cpp +++ b/intern/ghost/intern/GHOST_SystemWayland.cpp @@ -38,6 +38,8 @@ #include +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( - 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(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(get_window(surface)); + GHOST_ASSERT(win != nullptr, "Unable to find window for drop event from surface"); + std::vector 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(malloc((uris[i].size() + 1) * sizeof(uint8_t))); memcpy(flist->strings[i], uris[i].data(), uris[i].size() + 1); } - GHOST_IWindow *win = static_cast( - 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_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( -- cgit v1.2.3