ソースを参照

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
Camilla Löwy 3 年 前
コミット
4cb36872a5
5 ファイル変更62 行追加4 行削除
  1. 1 0
      CONTRIBUTORS.md
  2. 1 0
      README.md
  3. 2 0
      src/wl_init.c
  4. 5 0
      src/wl_platform.h
  5. 53 4
      src/wl_window.c

+ 1 - 0
CONTRIBUTORS.md

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

+ 1 - 0
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

+ 2 - 0
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)

+ 5 - 0
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;
 

+ 53 - 4
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,