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 4cb36872a5)
This commit is contained in:
Camilla Löwy 2022-03-31 19:56:48 +02:00
parent 2b504e41d5
commit 05422e2824
5 changed files with 62 additions and 4 deletions

View File

@ -158,6 +158,7 @@ video tutorials.
- Orson Peters - Orson Peters
- Emmanuel Gil Peyrot - Emmanuel Gil Peyrot
- Cyril Pichard - Cyril Pichard
- Pilzschaf
- Keith Pitt - Keith Pitt
- Stanislav Podgorskiy - Stanislav Podgorskiy
- Konstantin Podsvirov - Konstantin Podsvirov

View File

@ -129,6 +129,7 @@ information on what to include when reporting a bug.
match event scancode (#1993) match event scancode (#1993)
- [Win32] Bugfix: Instance-local operations used executable instance (#469,#1296,#1395) - [Win32] Bugfix: Instance-local operations used executable instance (#469,#1296,#1395)
- [Cocoa] Bugfix: A connected Apple AirPlay would emit a useless error (#1791) - [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 - [Wayland] Bugfix: `glfwSetClipboardString` would fail if set to result of
`glfwGetClipboardString` `glfwGetClipboardString`
- [Wayland] Bugfix: Data source creation error would cause double free at termination - [Wayland] Bugfix: Data source creation error would cause double free at termination

View File

@ -537,6 +537,8 @@ void _glfwPlatformTerminate(void)
xdg_wm_base_destroy(_glfw.wl.wmBase); xdg_wm_base_destroy(_glfw.wl.wmBase);
if (_glfw.wl.selectionOffer) if (_glfw.wl.selectionOffer)
wl_data_offer_destroy(_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) if (_glfw.wl.selectionSource)
wl_data_source_destroy(_glfw.wl.selectionSource); wl_data_source_destroy(_glfw.wl.selectionSource);
if (_glfw.wl.dataDevice) if (_glfw.wl.dataDevice)

View File

@ -171,6 +171,7 @@ typedef struct _GLFWofferWayland
{ {
struct wl_data_offer* offer; struct wl_data_offer* offer;
GLFWbool text_plain_utf8; GLFWbool text_plain_utf8;
GLFWbool text_uri_list;
} _GLFWofferWayland; } _GLFWofferWayland;
// Wayland-specific per-window data // Wayland-specific per-window data
@ -250,6 +251,10 @@ typedef struct _GLFWlibraryWayland
struct wl_data_offer* selectionOffer; struct wl_data_offer* selectionOffer;
struct wl_data_source* selectionSource; struct wl_data_source* selectionSource;
struct wl_data_offer* dragOffer;
_GLFWwindow* dragFocus;
uint32_t dragSerial;
int compositorVersion; int compositorVersion;
int seatVersion; int seatVersion;

View File

@ -1707,6 +1707,8 @@ static void dataOfferHandleOffer(void* userData,
{ {
if (strcmp(mimeType, "text/plain;charset=utf-8") == 0) if (strcmp(mimeType, "text/plain;charset=utf-8") == 0)
_glfw.wl.offers[i].text_plain_utf8 = GLFW_TRUE; _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; break;
} }
@ -1745,24 +1747,53 @@ static void dataDeviceHandleEnter(void* userData,
wl_fixed_t y, wl_fixed_t y,
struct wl_data_offer* offer) 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++) for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
{ {
if (_glfw.wl.offers[i].offer == offer) 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.offers[i] = _glfw.wl.offers[_glfw.wl.offerCount - 1];
_glfw.wl.offerCount--; _glfw.wl.offerCount--;
// We don't yet handle drag and drop
wl_data_offer_accept(offer, serial, NULL);
wl_data_offer_destroy(offer);
break; 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, static void dataDeviceHandleLeave(void* userData,
struct wl_data_device* device) 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, static void dataDeviceHandleMotion(void* userData,
@ -1776,6 +1807,24 @@ static void dataDeviceHandleMotion(void* userData,
static void dataDeviceHandleDrop(void* userData, static void dataDeviceHandleDrop(void* userData,
struct wl_data_device* device) 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, static void dataDeviceHandleSelection(void* userData,