From 05422e2824c94358aae6fe1a4becedc0a654a150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 31 Mar 2022 19:56:48 +0200 Subject: [PATCH] Wayland: Add support for file drop events This adds support for file path drop events in text/uri-list format. It is based on work by Pilzschaf in #2040. Closes #2040 (cherry picked from commit 4cb36872a5fe448c205d0b46f0e8c8b57530cfe0) --- CONTRIBUTORS.md | 1 + README.md | 1 + src/wl_init.c | 2 ++ src/wl_platform.h | 5 +++++ src/wl_window.c | 57 +++++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 62 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index f346bffe..5a1b1dcb 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -158,6 +158,7 @@ video tutorials. - Orson Peters - Emmanuel Gil Peyrot - Cyril Pichard + - Pilzschaf - Keith Pitt - Stanislav Podgorskiy - Konstantin Podsvirov diff --git a/README.md b/README.md index d97f71d6..8fea84b8 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,7 @@ information on what to include when reporting a bug. match event scancode (#1993) - [Win32] Bugfix: Instance-local operations used executable instance (#469,#1296,#1395) - [Cocoa] Bugfix: A connected Apple AirPlay would emit a useless error (#1791) + - [Wayland] Added support for file path drop events (#2040) - [Wayland] Bugfix: `glfwSetClipboardString` would fail if set to result of `glfwGetClipboardString` - [Wayland] Bugfix: Data source creation error would cause double free at termination diff --git a/src/wl_init.c b/src/wl_init.c index df760524..ad10aa60 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -537,6 +537,8 @@ void _glfwPlatformTerminate(void) xdg_wm_base_destroy(_glfw.wl.wmBase); if (_glfw.wl.selectionOffer) wl_data_offer_destroy(_glfw.wl.selectionOffer); + if (_glfw.wl.dragOffer) + wl_data_offer_destroy(_glfw.wl.dragOffer); if (_glfw.wl.selectionSource) wl_data_source_destroy(_glfw.wl.selectionSource); if (_glfw.wl.dataDevice) diff --git a/src/wl_platform.h b/src/wl_platform.h index afaf1ee5..824efc72 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -171,6 +171,7 @@ typedef struct _GLFWofferWayland { struct wl_data_offer* offer; GLFWbool text_plain_utf8; + GLFWbool text_uri_list; } _GLFWofferWayland; // Wayland-specific per-window data @@ -250,6 +251,10 @@ typedef struct _GLFWlibraryWayland struct wl_data_offer* selectionOffer; struct wl_data_source* selectionSource; + struct wl_data_offer* dragOffer; + _GLFWwindow* dragFocus; + uint32_t dragSerial; + int compositorVersion; int seatVersion; diff --git a/src/wl_window.c b/src/wl_window.c index ab274996..b15fd16a 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1707,6 +1707,8 @@ static void dataOfferHandleOffer(void* userData, { if (strcmp(mimeType, "text/plain;charset=utf-8") == 0) _glfw.wl.offers[i].text_plain_utf8 = GLFW_TRUE; + else if (strcmp(mimeType, "text/uri-list") == 0) + _glfw.wl.offers[i].text_uri_list = GLFW_TRUE; break; } @@ -1745,24 +1747,53 @@ static void dataDeviceHandleEnter(void* userData, wl_fixed_t y, struct wl_data_offer* offer) { + if (_glfw.wl.dragOffer) + { + wl_data_offer_destroy(_glfw.wl.dragOffer); + _glfw.wl.dragOffer = NULL; + _glfw.wl.dragFocus = NULL; + } + for (unsigned int i = 0; i < _glfw.wl.offerCount; i++) { if (_glfw.wl.offers[i].offer == offer) { + _GLFWwindow* window = NULL; + + if (surface) + window = wl_surface_get_user_data(surface); + + if (window && _glfw.wl.offers[i].text_uri_list) + { + _glfw.wl.dragOffer = offer; + _glfw.wl.dragFocus = window; + _glfw.wl.dragSerial = serial; + } + _glfw.wl.offers[i] = _glfw.wl.offers[_glfw.wl.offerCount - 1]; _glfw.wl.offerCount--; - - // We don't yet handle drag and drop - wl_data_offer_accept(offer, serial, NULL); - wl_data_offer_destroy(offer); break; } } + + if (_glfw.wl.dragOffer) + wl_data_offer_accept(offer, serial, "text/uri-list"); + else + { + wl_data_offer_accept(offer, serial, NULL); + wl_data_offer_destroy(offer); + } } static void dataDeviceHandleLeave(void* userData, struct wl_data_device* device) { + if (_glfw.wl.dragOffer) + { + wl_data_offer_destroy(_glfw.wl.dragOffer); + _glfw.wl.dragOffer = NULL; + _glfw.wl.dragFocus = NULL; + } } static void dataDeviceHandleMotion(void* userData, @@ -1776,6 +1807,24 @@ static void dataDeviceHandleMotion(void* userData, static void dataDeviceHandleDrop(void* userData, struct wl_data_device* device) { + if (!_glfw.wl.dragOffer) + return; + + char* string = readDataOfferAsString(_glfw.wl.dragOffer, "text/uri-list"); + if (string) + { + int count; + char** paths = _glfwParseUriList(string, &count); + if (paths) + _glfwInputDrop(_glfw.wl.dragFocus, count, (const char**) paths); + + for (int i = 0; i < count; i++) + free(paths[i]); + + free(paths); + } + + free(string); } static void dataDeviceHandleSelection(void* userData,