sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_x11clipboard.c (6741B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
      4 
      5   This software is provided 'as-is', without any express or implied
      6   warranty.  In no event will the authors be held liable for any damages
      7   arising from the use of this software.
      8 
      9   Permission is granted to anyone to use this software for any purpose,
     10   including commercial applications, and to alter it and redistribute it
     11   freely, subject to the following restrictions:
     12 
     13   1. The origin of this software must not be misrepresented; you must not
     14      claim that you wrote the original software. If you use this software
     15      in a product, an acknowledgment in the product documentation would be
     16      appreciated but is not required.
     17   2. Altered source versions must be plainly marked as such, and must not be
     18      misrepresented as being the original software.
     19   3. This notice may not be removed or altered from any source distribution.
     20 */
     21 #include "../../SDL_internal.h"
     22 
     23 #if SDL_VIDEO_DRIVER_X11
     24 
     25 #include <limits.h> /* For INT_MAX */
     26 
     27 #include "SDL_events.h"
     28 #include "SDL_x11video.h"
     29 #include "SDL_timer.h"
     30 
     31 
     32 /* If you don't support UTF-8, you might use XA_STRING here */
     33 #ifdef X_HAVE_UTF8_STRING
     34 #define TEXT_FORMAT X11_XInternAtom(display, "UTF8_STRING", False)
     35 #else
     36 #define TEXT_FORMAT XA_STRING
     37 #endif
     38 
     39 /* Get any application owned window handle for clipboard association */
     40 static Window
     41 GetWindow(_THIS)
     42 {
     43     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
     44 
     45     /* We create an unmapped window that exists just to manage the clipboard,
     46        since X11 selection data is tied to a specific window and dies with it.
     47        We create the window on demand, so apps that don't use the clipboard
     48        don't have to keep an unnecessary resource around. */
     49     if (data->clipboard_window == None) {
     50         Display *dpy = data->display;
     51         Window parent = RootWindow(dpy, DefaultScreen(dpy));
     52         XSetWindowAttributes xattr;
     53         data->clipboard_window = X11_XCreateWindow(dpy, parent, -10, -10, 1, 1, 0,
     54                                                    CopyFromParent, InputOnly,
     55                                                    CopyFromParent, 0, &xattr);
     56         X11_XFlush(data->display);
     57     }
     58 
     59     return data->clipboard_window;
     60 }
     61 
     62 /* We use our own cut-buffer for intermediate storage instead of  
     63    XA_CUT_BUFFER0 because their use isn't really defined for holding UTF8. */ 
     64 Atom
     65 X11_GetSDLCutBufferClipboardType(Display *display)
     66 {
     67     return X11_XInternAtom(display, "SDL_CUTBUFFER", False);
     68 }
     69 
     70 int
     71 X11_SetClipboardText(_THIS, const char *text)
     72 {
     73     Display *display = ((SDL_VideoData *) _this->driverdata)->display;
     74     Atom format;
     75     Window window;
     76     Atom XA_CLIPBOARD = X11_XInternAtom(display, "CLIPBOARD", 0);
     77 
     78     /* Get the SDL window that will own the selection */
     79     window = GetWindow(_this);
     80     if (window == None) {
     81         return SDL_SetError("Couldn't find a window to own the selection");
     82     }
     83 
     84     /* Save the selection on the root window */
     85     format = TEXT_FORMAT;
     86     X11_XChangeProperty(display, DefaultRootWindow(display),
     87         X11_GetSDLCutBufferClipboardType(display), format, 8, PropModeReplace,
     88         (const unsigned char *)text, SDL_strlen(text));
     89 
     90     if (XA_CLIPBOARD != None &&
     91         X11_XGetSelectionOwner(display, XA_CLIPBOARD) != window) {
     92         X11_XSetSelectionOwner(display, XA_CLIPBOARD, window, CurrentTime);
     93     }
     94 
     95     if (X11_XGetSelectionOwner(display, XA_PRIMARY) != window) {
     96         X11_XSetSelectionOwner(display, XA_PRIMARY, window, CurrentTime);
     97     }
     98     return 0;
     99 }
    100 
    101 char *
    102 X11_GetClipboardText(_THIS)
    103 {
    104     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    105     Display *display = videodata->display;
    106     Atom format;
    107     Window window;
    108     Window owner;
    109     Atom selection;
    110     Atom seln_type;
    111     int seln_format;
    112     unsigned long nbytes;
    113     unsigned long overflow;
    114     unsigned char *src;
    115     char *text;
    116     Uint32 waitStart;
    117     Uint32 waitElapsed;
    118     Atom XA_CLIPBOARD = X11_XInternAtom(display, "CLIPBOARD", 0);
    119     if (XA_CLIPBOARD == None) {
    120         SDL_SetError("Couldn't access X clipboard");
    121         return SDL_strdup("");
    122     }
    123 
    124     text = NULL;
    125 
    126     /* Get the window that holds the selection */
    127     window = GetWindow(_this);
    128     format = TEXT_FORMAT;
    129     owner = X11_XGetSelectionOwner(display, XA_CLIPBOARD);
    130     if (owner == None) {
    131         /* Fall back to ancient X10 cut-buffers which do not support UTF8 strings*/
    132         owner = DefaultRootWindow(display);
    133         selection = XA_CUT_BUFFER0;
    134         format = XA_STRING;
    135     } else if (owner == window) {
    136         owner = DefaultRootWindow(display);
    137         selection = X11_GetSDLCutBufferClipboardType(display);
    138     } else {
    139         /* Request that the selection owner copy the data to our window */
    140         owner = window;
    141         selection = X11_XInternAtom(display, "SDL_SELECTION", False);
    142         X11_XConvertSelection(display, XA_CLIPBOARD, format, selection, owner,
    143             CurrentTime);
    144 
    145         /* When using synergy on Linux and when data has been put in the clipboard
    146            on the remote (Windows anyway) machine then selection_waiting may never
    147            be set to False. Time out after a while. */
    148         waitStart = SDL_GetTicks();
    149         videodata->selection_waiting = SDL_TRUE;
    150         while (videodata->selection_waiting) {
    151             SDL_PumpEvents();
    152             waitElapsed = SDL_GetTicks() - waitStart;
    153             /* Wait one second for a clipboard response. */
    154             if (waitElapsed > 1000) {
    155                 videodata->selection_waiting = SDL_FALSE;
    156                 SDL_SetError("Clipboard timeout");
    157                 /* We need to set the clipboard text so that next time we won't
    158                    timeout, otherwise we will hang on every call to this function. */
    159                 X11_SetClipboardText(_this, "");
    160                 return SDL_strdup("");
    161             }
    162         }
    163     }
    164 
    165     if (X11_XGetWindowProperty(display, owner, selection, 0, INT_MAX/4, False,
    166             format, &seln_type, &seln_format, &nbytes, &overflow, &src)
    167             == Success) {
    168         if (seln_type == format) {
    169             text = (char *)SDL_malloc(nbytes+1);
    170             if (text) {
    171                 SDL_memcpy(text, src, nbytes);
    172                 text[nbytes] = '\0';
    173             }
    174         }
    175         X11_XFree(src);
    176     }
    177 
    178     if (!text) {
    179         text = SDL_strdup("");
    180     }
    181 
    182     return text;
    183 }
    184 
    185 SDL_bool
    186 X11_HasClipboardText(_THIS)
    187 {
    188     SDL_bool result = SDL_FALSE;
    189     char *text = X11_GetClipboardText(_this);
    190     if (text) {
    191         result = text[0] != '\0' ? SDL_TRUE : SDL_FALSE;
    192         SDL_free(text);
    193     }
    194     return result;
    195 }
    196 
    197 #endif /* SDL_VIDEO_DRIVER_X11 */
    198 
    199 /* vi: set ts=4 sw=4 expandtab: */