From 8b54e28c4ea4df8f0f38bb02f8540522b136e826 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Wed, 10 Oct 2018 19:21:26 +0200 Subject: [PATCH] Wayland: Implement clipboard paste --- src/wl_init.c | 11 +++++++ src/wl_platform.h | 2 ++ src/wl_window.c | 83 ++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 92 insertions(+), 4 deletions(-) diff --git a/src/wl_init.c b/src/wl_init.c index 6f7c128b..30d0eca5 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -1196,6 +1196,14 @@ int _glfwPlatformInit(void) wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager, _glfw.wl.seat); 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; @@ -1285,6 +1293,9 @@ void _glfwPlatformTerminate(void) close(_glfw.wl.timerfd); if (_glfw.wl.cursorTimerfd >= 0) close(_glfw.wl.cursorTimerfd); + + if (_glfw.wl.clipboardString) + free(_glfw.wl.clipboardString); } const char* _glfwPlatformGetVersionString(void) diff --git a/src/wl_platform.h b/src/wl_platform.h index 264eae83..11c2f91e 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -256,6 +256,8 @@ typedef struct _GLFWlibraryWayland int32_t keyboardRepeatDelay; int keyboardLastKey; int keyboardLastScancode; + char* clipboardString; + size_t clipboardSize; int timerfd; short int keycodes[256]; short int scancodes[GLFW_KEY_LAST + 1]; diff --git a/src/wl_window.c b/src/wl_window.c index 3cfc9f7f..817e2f0c 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1576,12 +1576,87 @@ void _glfwPlatformSetClipboardString(const char* string) "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) { - // 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)