浏览代码

Wayland: Implement clipboard paste

Emmanuel Gil Peyrot 7 年之前
父节点
当前提交
8b54e28c4e
共有 3 个文件被更改,包括 92 次插入4 次删除
  1. 11 0
      src/wl_init.c
  2. 2 0
      src/wl_platform.h
  3. 79 4
      src/wl_window.c

+ 11 - 0
src/wl_init.c

@@ -1196,6 +1196,14 @@ int _glfwPlatformInit(void)
             wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager,
             wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager,
                                                    _glfw.wl.seat);
                                                    _glfw.wl.seat);
         wl_data_device_add_listener(_glfw.wl.dataDevice, &dataDeviceListener, NULL);
         wl_data_device_add_listener(_glfw.wl.dataDevice, &dataDeviceListener, NULL);
+        _glfw.wl.clipboardString = malloc(4096);
+        if (!_glfw.wl.clipboardString)
+        {
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "Wayland: Unable to allocate clipboard memory");
+            return GLFW_FALSE;
+        }
+        _glfw.wl.clipboardSize = 4096;
     }
     }
 
 
     return GLFW_TRUE;
     return GLFW_TRUE;
@@ -1285,6 +1293,9 @@ void _glfwPlatformTerminate(void)
         close(_glfw.wl.timerfd);
         close(_glfw.wl.timerfd);
     if (_glfw.wl.cursorTimerfd >= 0)
     if (_glfw.wl.cursorTimerfd >= 0)
         close(_glfw.wl.cursorTimerfd);
         close(_glfw.wl.cursorTimerfd);
+
+    if (_glfw.wl.clipboardString)
+        free(_glfw.wl.clipboardString);
 }
 }
 
 
 const char* _glfwPlatformGetVersionString(void)
 const char* _glfwPlatformGetVersionString(void)

+ 2 - 0
src/wl_platform.h

@@ -256,6 +256,8 @@ typedef struct _GLFWlibraryWayland
     int32_t                     keyboardRepeatDelay;
     int32_t                     keyboardRepeatDelay;
     int                         keyboardLastKey;
     int                         keyboardLastKey;
     int                         keyboardLastScancode;
     int                         keyboardLastScancode;
+    char*                       clipboardString;
+    size_t                      clipboardSize;
     int                         timerfd;
     int                         timerfd;
     short int                   keycodes[256];
     short int                   keycodes[256];
     short int                   scancodes[GLFW_KEY_LAST + 1];
     short int                   scancodes[GLFW_KEY_LAST + 1];

+ 79 - 4
src/wl_window.c

@@ -1576,12 +1576,87 @@ void _glfwPlatformSetClipboardString(const char* string)
                     "Wayland: Clipboard setting not implemented yet");
                     "Wayland: Clipboard setting not implemented yet");
 }
 }
 
 
+static GLFWbool growClipboardString(void)
+{
+    char* clipboard = _glfw.wl.clipboardString;
+
+    clipboard = realloc(clipboard, _glfw.wl.clipboardSize * 2);
+    if (!clipboard)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Wayland: Impossible to grow clipboard string");
+        return GLFW_FALSE;
+    }
+    _glfw.wl.clipboardString = clipboard;
+    _glfw.wl.clipboardSize = _glfw.wl.clipboardSize * 2;
+    return GLFW_TRUE;
+}
+
 const char* _glfwPlatformGetClipboardString(void)
 const char* _glfwPlatformGetClipboardString(void)
 {
 {
-    // TODO
-    _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Wayland: Clipboard getting not implemented yet");
-    return NULL;
+    int fds[2];
+    int ret;
+    size_t len = 0;
+
+    if (!_glfw.wl.dataOffer)
+    {
+        _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
+                        "No clipboard data has been sent yet");
+        return NULL;
+    }
+
+    ret = pipe2(fds, O_CLOEXEC);
+    if (ret < 0)
+    {
+        // TODO: also report errno maybe?
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Wayland: Impossible to create clipboard pipe fds");
+        return NULL;
+    }
+
+    wl_data_offer_receive(_glfw.wl.dataOffer, "text/plain;charset=utf-8", fds[1]);
+    close(fds[1]);
+
+    // XXX: this is a huge hack, this function shouldn’t be synchronous!
+    handleEvents(-1);
+
+    while (1)
+    {
+        // Grow the clipboard if we need to paste something bigger, there is no
+        // shrink operation yet.
+        if (len + 4096 > _glfw.wl.clipboardSize)
+        {
+            if (!growClipboardString())
+            {
+                close(fds[0]);
+                return NULL;
+            }
+        }
+
+        // Then read from the fd to the clipboard, handling all known errors.
+        ret = read(fds[0], _glfw.wl.clipboardString + len, 4096);
+        if (ret == 0)
+            break;
+        if (ret == -1 && errno == EINTR)
+            continue;
+        if (ret == -1)
+        {
+            // TODO: also report errno maybe.
+            _glfwInputError(GLFW_PLATFORM_ERROR,
+                            "Wayland: Impossible to read from clipboard fd");
+            close(fds[0]);
+            return NULL;
+        }
+        len += ret;
+    }
+    close(fds[0]);
+    if (len + 1 > _glfw.wl.clipboardSize)
+    {
+        if (!growClipboardString())
+            return NULL;
+    }
+    _glfw.wl.clipboardString[len] = '\0';
+    return _glfw.wl.clipboardString;
 }
 }
 
 
 void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
 void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)