src/video/x11/SDL_x11clipboard.c
author Ethan Lee <flibitijibibo@flibitijibibo.com>
Wed, 17 Jul 2019 23:20:57 -0400
changeset 12950 05dddfb66b85
parent 12503 806492103856
permissions -rw-r--r--
Copypaste SDL_NSLog to UIKit backend, document it as such
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 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: */