Added X11 clipboard support.
authorSam Lantinga <slouken@libsdl.org>
Mon, 12 Jul 2010 00:36:55 -0700
changeset 4508 15d2c6f40c48
parent 4507 dbf3fa541096
child 4509 8e91c3947210
Added X11 clipboard support. As far as I know there isn't any real way to tell when the clipboard contents have changed without polling them, so I didn't implement the clipboard update event on X11.
src/video/x11/SDL_x11clipboard.c
src/video/x11/SDL_x11clipboard.h
src/video/x11/SDL_x11events.c
src/video/x11/SDL_x11sym.h
src/video/x11/SDL_x11video.c
src/video/x11/SDL_x11video.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/x11/SDL_x11clipboard.c	Mon Jul 12 00:36:55 2010 -0700
@@ -0,0 +1,152 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2010 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#include <limits.h> /* For INT_MAX */
+
+#include "SDL_events.h"
+#include "SDL_x11video.h"
+
+
+/* Get any application owned window handle for clipboard association */
+static Window
+GetWindow(_THIS)
+{
+    SDL_VideoDisplay *display;
+    SDL_Window *window;
+
+    display = _this->displays;
+    if (display) {
+        window = display->windows;
+        if (window) {
+            return ((SDL_WindowData *) window->driverdata)->xwindow;
+        }
+    }
+    return None;
+}
+
+int
+X11_SetClipboardText(_THIS, const char *text)
+{
+    Display *display = ((SDL_VideoData *) _this->driverdata)->display;
+    Atom format;
+    Window window;
+
+    /* Get the SDL window that will own the selection */
+    window = GetWindow(_this);
+    if (window == None) {
+        SDL_SetError("Couldn't find a window to own the selection");
+        return -1;
+    }
+
+    /* If you don't support UTF-8, you might use XA_STRING here */
+    format = XInternAtom(display, "UTF8_STRING", False);
+    XChangeProperty(display, DefaultRootWindow(display),
+        XA_CUT_BUFFER0, format, 8, PropModeReplace,
+        (const unsigned char *)text, SDL_strlen(text));
+
+    if (XGetSelectionOwner(display, XA_PRIMARY) != window) {
+        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;
+
+    text = NULL;
+
+    /* Get the SDL window that will own the selection */
+    window = GetWindow(_this);
+
+    /* If you don't support UTF-8, you might use XA_STRING here */
+    format = XInternAtom(display, "UTF8_STRING", False);
+
+    owner = XGetSelectionOwner(display, XA_PRIMARY);
+    if ((owner == None) || (owner == window)) {
+        owner = DefaultRootWindow(display);
+        selection = XA_CUT_BUFFER0;
+    } else {
+        /* Request that the selection owner copy the data to our window */
+        owner = window;
+        selection = XInternAtom(display, "SDL_SELECTION", False);
+        XConvertSelection(display, XA_PRIMARY, format, selection, owner,
+            CurrentTime);
+
+        /* FIXME: Should we have a timeout here? */
+        videodata->selection_waiting = SDL_TRUE;
+        while (videodata->selection_waiting) {
+            SDL_PumpEvents();
+        }
+    }
+
+    if (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';
+            }
+        }
+        XFree(src);
+    }
+
+    if (!text) {
+        text = SDL_strdup("");
+    }
+    return text;
+}
+
+SDL_bool
+X11_HasClipboardText(_THIS)
+{
+    /* Not an easy way to tell with X11, as far as I know... */
+    char *text;
+    SDL_bool retval;
+
+    text = X11_GetClipboardText(_this);
+    if (*text) {
+        retval = SDL_TRUE;
+    } else {
+        retval = SDL_FALSE;
+    }
+    SDL_free(text);
+
+    return retval;
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/x11/SDL_x11clipboard.h	Mon Jul 12 00:36:55 2010 -0700
@@ -0,0 +1,33 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2010 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_x11clipboard_h
+#define _SDL_x11clipboard_h
+
+extern int X11_SetClipboardText(_THIS, const char *text);
+extern char *X11_GetClipboardText(_THIS);
+extern SDL_bool X11_HasClipboardText(_THIS);
+
+#endif /* _SDL_x11clipboard_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/x11/SDL_x11events.c	Mon Jul 12 00:35:24 2010 -0700
+++ b/src/video/x11/SDL_x11events.c	Mon Jul 12 00:36:55 2010 -0700
@@ -25,6 +25,7 @@
 #include <sys/time.h>
 #include <signal.h>
 #include <unistd.h>
+#include <limits.h>	/* For INT_MAX */
 
 #include "SDL_x11video.h"
 #include "../../events/SDL_events_c.h"
@@ -33,6 +34,8 @@
 #include "SDL_timer.h"
 #include "SDL_syswm.h"
 
+/*#define DEBUG_XEVENTS*/
+
 static void
 X11_DispatchEvent(_THIS)
 {
@@ -286,6 +289,55 @@
         }
         break;
 
+    /* Copy the selection from XA_CUT_BUFFER0 to the requested property */
+    case SelectionRequest: {
+            Display *display = videodata->display;
+            XSelectionRequestEvent *req;
+            XEvent sevent;
+            int seln_format;
+            unsigned long nbytes;
+            unsigned long overflow;
+            unsigned char *seln_data;
+
+            req = &xevent.xselectionrequest;
+#ifdef DEBUG_XEVENTS
+            printf("SelectionRequest (requestor = %ld, target = %ld)\n",
+                req->requestor, req->target);
+#endif
+
+            sevent.xselection.type = SelectionNotify;
+            sevent.xselection.display = req->display;
+            sevent.xselection.selection = req->selection;
+            sevent.xselection.target = None;
+            sevent.xselection.property = None;
+            sevent.xselection.requestor = req->requestor;
+            sevent.xselection.time = req->time;
+            if (XGetWindowProperty(display, DefaultRootWindow(display),
+                    XA_CUT_BUFFER0, 0, INT_MAX/4, False, req->target,
+                    &sevent.xselection.target, &seln_format, &nbytes,
+                    &overflow, &seln_data) == Success) {
+                if (sevent.xselection.target == req->target) {
+                    XChangeProperty(display, req->requestor, req->property,
+                        sevent.xselection.target, seln_format, PropModeReplace,
+                        seln_data, nbytes);
+                    sevent.xselection.property = req->property;
+                }
+                XFree(seln_data);
+            }
+            XSendEvent(display, req->requestor, False, 0, &sevent);
+            XSync(display, False);
+        }
+        break;
+
+    case SelectionNotify: {
+#ifdef DEBUG_XEVENTS
+            printf("SelectionNotify (requestor = %ld, target = %ld)\n",
+                xevent.xselection.requestor, xevent.xselection.target);
+#endif
+            videodata->selection_waiting = SDL_FALSE;
+        }
+        break;
+
     default:{
 #ifdef DEBUG_XEVENTS
             printf("Unhandled event %d\n", xevent.type);
--- a/src/video/x11/SDL_x11sym.h	Mon Jul 12 00:35:24 2010 -0700
+++ b/src/video/x11/SDL_x11sym.h	Mon Jul 12 00:36:55 2010 -0700
@@ -37,6 +37,7 @@
 SDL_X11_SYM(Bool,XCheckWindowEvent,(Display* a,Window b,long c,XEvent* d),(a,b,c,d),return)
 SDL_X11_SYM(int,XClearWindow,(Display* a,Window b),(a,b),return)
 SDL_X11_SYM(int,XCloseDisplay,(Display* a),(a),return)
+SDL_X11_SYM(int,XConvertSelection,(Display* a,Atom b,Atom c,Atom d,Window e,Time f),(a,b,c,d,e,f),return)
 SDL_X11_SYM(int,XCopyArea,(Display* a,Drawable b,Drawable c,GC d,int e,int f,unsigned int g,unsigned int h,int i,int j),(a,b,c,d,e,f,g,h,i,j),return)
 SDL_X11_SYM(Colormap,XCreateColormap,(Display* a,Window b,Visual* c,int d),(a,b,c,d),return)
 SDL_X11_SYM(Cursor,XCreatePixmapCursor,(Display* a,Pixmap b,Pixmap c,XColor* d,XColor* e,unsigned int f,unsigned int g),(a,b,c,d,e,f,g),return)
@@ -71,10 +72,11 @@
 SDL_X11_SYM(XModifierKeymap*,XGetModifierMapping,(Display* a),(a),return)
 SDL_X11_SYM(int,XGetPointerControl,(Display* a,int* b,int* c,int* d),(a,b,c,d),return)
 SDL_X11_SYM(int,XGetRGBColormaps,(Display* a,Window b,XStandardColormap **c,int *d,Atom e),(a,b,c,d,e),return)
+SDL_X11_SYM(Window,XGetSelectionOwner,(Display* a,Atom b),(a,b),return)
 SDL_X11_SYM(XVisualInfo*,XGetVisualInfo,(Display* a,long b,XVisualInfo* c,int* d),(a,b,c,d),return)
-SDL_X11_SYM(XWMHints*,XGetWMHints,(Display* a,Window b),(a,b),return)
 SDL_X11_SYM(Status,XGetWindowAttributes,(Display* a,Window b,XWindowAttributes* c),(a,b,c),return)
 SDL_X11_SYM(int,XGetWindowProperty,(Display* a,Window b,Atom c,long d,long e,Bool f,Atom g,Atom* h,int* i,unsigned long* j,unsigned long *k,unsigned char **l),(a,b,c,d,e,f,g,h,i,j,k,l),return)
+SDL_X11_SYM(XWMHints*,XGetWMHints,(Display* a,Window b),(a,b),return)
 SDL_X11_SYM(int,XGrabKeyboard,(Display* a,Window b,Bool c,int d,int e,Time f),(a,b,c,d,e,f),return)
 SDL_X11_SYM(int,XGrabPointer,(Display* a,Window b,Bool c,unsigned int d,int e,int f,Window g,Cursor h,Time i),(a,b,c,d,e,f,g,h,i),return)
 SDL_X11_SYM(int,XGrabServer,(Display* a),(a),return)
@@ -114,14 +116,15 @@
 SDL_X11_SYM(XErrorHandler,XSetErrorHandler,(XErrorHandler a),(a),return)
 SDL_X11_SYM(XIOErrorHandler,XSetIOErrorHandler,(XIOErrorHandler a),(a),return)
 SDL_X11_SYM(void,XSetRGBColormaps,( Display *a,Window b,XStandardColormap *c,int d,Atom e),(a,b,c,d,e),return)
+SDL_X11_SYM(int,XSetSelectionOwner,(Display* a,Atom b,Window c,Time d),(a,b,c,d),return)
 SDL_X11_SYM(int,XSetTransientForHint,(Display* a,Window b,Window c),(a,b,c),return)
-SDL_X11_SYM(int,XSetWMHints,(Display* a,Window b,XWMHints* c),(a,b,c),return)
 SDL_X11_SYM(void,XSetTextProperty,(Display* a,Window b,XTextProperty* c,Atom d),(a,b,c,d),)
-SDL_X11_SYM(void,XSetWMNormalHints,(Display* a,Window b,XSizeHints* c),(a,b,c),)
-SDL_X11_SYM(Status,XSetWMProtocols,(Display* a,Window b,Atom* c,int d),(a,b,c,d),return)
 SDL_X11_SYM(int,XSetWindowBackground,(Display* a,Window b,unsigned long c),(a,b,c),return)
 SDL_X11_SYM(int,XSetWindowBackgroundPixmap,(Display* a,Window b,Pixmap c),(a,b,c),return)
 SDL_X11_SYM(int,XSetWindowColormap,(Display* a,Window b,Colormap c),(a,b,c),return)
+SDL_X11_SYM(int,XSetWMHints,(Display* a,Window b,XWMHints* c),(a,b,c),return)
+SDL_X11_SYM(void,XSetWMNormalHints,(Display* a,Window b,XSizeHints* c),(a,b,c),)
+SDL_X11_SYM(Status,XSetWMProtocols,(Display* a,Window b,Atom* c,int d),(a,b,c,d),return)
 SDL_X11_SYM(int,XStoreColors,(Display* a,Colormap b,XColor* c,int d),(a,b,c,d),return)
 SDL_X11_SYM(Status,XStringListToTextProperty,(char** a,int b,XTextProperty* c),(a,b,c),return)
 SDL_X11_SYM(int,XSync,(Display* a,Bool b),(a,b),return)
--- a/src/video/x11/SDL_x11video.c	Mon Jul 12 00:35:24 2010 -0700
+++ b/src/video/x11/SDL_x11video.c	Mon Jul 12 00:36:55 2010 -0700
@@ -21,6 +21,8 @@
 */
 #include "SDL_config.h"
 
+#include <unistd.h> /* For getpid() and readlink() */
+
 #include "SDL_video.h"
 #include "SDL_mouse.h"
 #include "../SDL_sysvideo.h"
@@ -225,6 +227,10 @@
     device->GL_DeleteContext = X11_GLES_DeleteContext;
 #endif
 
+    device->SetClipboardText = X11_SetClipboardText;
+    device->GetClipboardText = X11_GetClipboardText;
+    device->HasClipboardText = X11_HasClipboardText;
+
     device->free = X11_DeleteDevice;
 
     return device;
--- a/src/video/x11/SDL_x11video.h	Mon Jul 12 00:35:24 2010 -0700
+++ b/src/video/x11/SDL_x11video.h	Mon Jul 12 00:36:55 2010 -0700
@@ -48,6 +48,7 @@
 
 #include "SDL_x11dyn.h"
 
+#include "SDL_x11clipboard.h"
 #include "SDL_x11events.h"
 #include "SDL_x11gamma.h"
 #include "SDL_x11keyboard.h"
@@ -69,6 +70,7 @@
     int windowlistlength;
     Atom WM_DELETE_WINDOW;
     SDL_scancode key_layout[256];
+    SDL_bool selection_waiting;
 } SDL_VideoData;
 
 extern SDL_bool X11_UseDirectColorVisuals(void);