diff options
Diffstat (limited to 'source/3rd-party/SDL2/src/video/x11/SDL_x11clipboard.c')
-rw-r--r-- | source/3rd-party/SDL2/src/video/x11/SDL_x11clipboard.c | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/source/3rd-party/SDL2/src/video/x11/SDL_x11clipboard.c b/source/3rd-party/SDL2/src/video/x11/SDL_x11clipboard.c new file mode 100644 index 0000000..fad8c9c --- /dev/null +++ b/source/3rd-party/SDL2/src/video/x11/SDL_x11clipboard.c @@ -0,0 +1,199 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_X11 + +#include <limits.h> /* For INT_MAX */ + +#include "SDL_events.h" +#include "SDL_x11video.h" +#include "SDL_timer.h" + + +/* If you don't support UTF-8, you might use XA_STRING here */ +#ifdef X_HAVE_UTF8_STRING +#define TEXT_FORMAT X11_XInternAtom(display, "UTF8_STRING", False) +#else +#define TEXT_FORMAT XA_STRING +#endif + +/* Get any application owned window handle for clipboard association */ +static Window +GetWindow(_THIS) +{ + SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; + + /* We create an unmapped window that exists just to manage the clipboard, + since X11 selection data is tied to a specific window and dies with it. + We create the window on demand, so apps that don't use the clipboard + don't have to keep an unnecessary resource around. */ + if (data->clipboard_window == None) { + Display *dpy = data->display; + Window parent = RootWindow(dpy, DefaultScreen(dpy)); + XSetWindowAttributes xattr; + data->clipboard_window = X11_XCreateWindow(dpy, parent, -10, -10, 1, 1, 0, + CopyFromParent, InputOnly, + CopyFromParent, 0, &xattr); + X11_XFlush(data->display); + } + + return data->clipboard_window; +} + +/* We use our own cut-buffer for intermediate storage instead of + XA_CUT_BUFFER0 because their use isn't really defined for holding UTF8. */ +Atom +X11_GetSDLCutBufferClipboardType(Display *display) +{ + return X11_XInternAtom(display, "SDL_CUTBUFFER", False); +} + +int +X11_SetClipboardText(_THIS, const char *text) +{ + Display *display = ((SDL_VideoData *) _this->driverdata)->display; + Atom format; + Window window; + Atom XA_CLIPBOARD = X11_XInternAtom(display, "CLIPBOARD", 0); + + /* Get the SDL window that will own the selection */ + window = GetWindow(_this); + if (window == None) { + return SDL_SetError("Couldn't find a window to own the selection"); + } + + /* Save the selection on the root window */ + format = TEXT_FORMAT; + X11_XChangeProperty(display, DefaultRootWindow(display), + X11_GetSDLCutBufferClipboardType(display), format, 8, PropModeReplace, + (const unsigned char *)text, SDL_strlen(text)); + + if (XA_CLIPBOARD != None && + X11_XGetSelectionOwner(display, XA_CLIPBOARD) != window) { + X11_XSetSelectionOwner(display, XA_CLIPBOARD, window, CurrentTime); + } + + if (X11_XGetSelectionOwner(display, XA_PRIMARY) != window) { + X11_XSetSelectionOwner(display, XA_PRIMARY, window, CurrentTime); + } + return 0; +} + +char * +X11_GetClipboardText(_THIS) +{ + SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; + Display *display = videodata->display; + Atom format; + Window window; + Window owner; + Atom selection; + Atom seln_type; + int seln_format; + unsigned long nbytes; + unsigned long overflow; + unsigned char *src; + char *text; + Uint32 waitStart; + Uint32 waitElapsed; + Atom XA_CLIPBOARD = X11_XInternAtom(display, "CLIPBOARD", 0); + if (XA_CLIPBOARD == None) { + SDL_SetError("Couldn't access X clipboard"); + return SDL_strdup(""); + } + + text = NULL; + + /* Get the window that holds the selection */ + window = GetWindow(_this); + format = TEXT_FORMAT; + owner = X11_XGetSelectionOwner(display, XA_CLIPBOARD); + if (owner == None) { + /* Fall back to ancient X10 cut-buffers which do not support UTF8 strings*/ + owner = DefaultRootWindow(display); + selection = XA_CUT_BUFFER0; + format = XA_STRING; + } else if (owner == window) { + owner = DefaultRootWindow(display); + selection = X11_GetSDLCutBufferClipboardType(display); + } else { + /* Request that the selection owner copy the data to our window */ + owner = window; + selection = X11_XInternAtom(display, "SDL_SELECTION", False); + X11_XConvertSelection(display, XA_CLIPBOARD, format, selection, owner, + CurrentTime); + + /* When using synergy on Linux and when data has been put in the clipboard + on the remote (Windows anyway) machine then selection_waiting may never + be set to False. Time out after a while. */ + waitStart = SDL_GetTicks(); + videodata->selection_waiting = SDL_TRUE; + while (videodata->selection_waiting) { + SDL_PumpEvents(); + waitElapsed = SDL_GetTicks() - waitStart; + /* Wait one second for a clipboard response. */ + if (waitElapsed > 1000) { + videodata->selection_waiting = SDL_FALSE; + SDL_SetError("Clipboard timeout"); + /* We need to set the clipboard text so that next time we won't + timeout, otherwise we will hang on every call to this function. */ + X11_SetClipboardText(_this, ""); + return SDL_strdup(""); + } + } + } + + if (X11_XGetWindowProperty(display, owner, selection, 0, INT_MAX/4, False, + format, &seln_type, &seln_format, &nbytes, &overflow, &src) + == Success) { + if (seln_type == format) { + text = (char *)SDL_malloc(nbytes+1); + if (text) { + SDL_memcpy(text, src, nbytes); + text[nbytes] = '\0'; + } + } + X11_XFree(src); + } + + if (!text) { + text = SDL_strdup(""); + } + + return text; +} + +SDL_bool +X11_HasClipboardText(_THIS) +{ + SDL_bool result = SDL_FALSE; + char *text = X11_GetClipboardText(_this); + if (text) { + result = text[0] != '\0' ? SDL_TRUE : SDL_FALSE; + SDL_free(text); + } + return result; +} + +#endif /* SDL_VIDEO_DRIVER_X11 */ + +/* vi: set ts=4 sw=4 expandtab: */ |