From 4cb36872a5fe448c205d0b46f0e8c8b57530cfe0 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 --- 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 cc77ff13..c93c187e 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -162,6 +162,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 7b6873f1..334277ed 100644 --- a/README.md +++ b/README.md @@ -287,6 +287,7 @@ information on what to include when reporting a bug. - [X11] Bugfix: Left shift of int constant relied on undefined behavior (#1951) - [Wayland] Added dynamic loading of all Wayland libraries - [Wayland] Added support for key names via xkbcommon + - [Wayland] Added support for file path drop events (#2040) - [Wayland] Removed support for `wl_shell` (#1443) - [Wayland] Bugfix: The `GLFW_HAND_CURSOR` shape used the wrong image (#1432) - [Wayland] Bugfix: `CLOCK_MONOTONIC` was not correctly enabled diff --git a/src/wl_init.c b/src/wl_init.c index 6545c41e..3c0dac47 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -714,6 +714,8 @@ void _glfwTerminateWayland(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 5ad9fa07..d6c8c4da 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -223,6 +223,7 @@ typedef struct _GLFWofferWayland { struct wl_data_offer* offer; GLFWbool text_plain_utf8; + GLFWbool text_uri_list; } _GLFWofferWayland; // Wayland-specific per-window data @@ -300,6 +301,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 3fd4a87b..047b9eb6 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1534,6 +1534,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; } @@ -1572,24 +1574,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, @@ -1603,6 +1634,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++) + _glfw_free(paths[i]); + + _glfw_free(paths); + } + + _glfw_free(string); } static void dataDeviceHandleSelection(void* userData,