From aa600ee842e8501bff0299f54a3d06a79579c295 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 12 Jul 2010 00:36:55 -0700 Subject: [PATCH] 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 | 152 +++++++++++++++++++++++++++++++ src/video/x11/SDL_x11clipboard.h | 33 +++++++ src/video/x11/SDL_x11events.c | 52 +++++++++++ src/video/x11/SDL_x11sym.h | 11 ++- src/video/x11/SDL_x11video.c | 6 ++ src/video/x11/SDL_x11video.h | 2 + 6 files changed, 252 insertions(+), 4 deletions(-) create mode 100644 src/video/x11/SDL_x11clipboard.c create mode 100644 src/video/x11/SDL_x11clipboard.h diff --git a/src/video/x11/SDL_x11clipboard.c b/src/video/x11/SDL_x11clipboard.c new file mode 100644 index 000000000..cbf7a6de7 --- /dev/null +++ b/src/video/x11/SDL_x11clipboard.c @@ -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 /* 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: */ diff --git a/src/video/x11/SDL_x11clipboard.h b/src/video/x11/SDL_x11clipboard.h new file mode 100644 index 000000000..6d9bbb085 --- /dev/null +++ b/src/video/x11/SDL_x11clipboard.h @@ -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: */ diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 147dc626d..e4d51bc6b 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -25,6 +25,7 @@ #include #include #include +#include /* 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 @@ X11_DispatchEvent(_THIS) } 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); diff --git a/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h index 0cdcfe8dc..01dc8f6a0 100644 --- a/src/video/x11/SDL_x11sym.h +++ b/src/video/x11/SDL_x11sym.h @@ -37,6 +37,7 @@ SDL_X11_SYM(int,XChangeWindowAttributes,(Display* a,Window b,unsigned long c,XSe 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(XImage*,XGetImage,(Display* a,Drawable b,int c,int d,unsigned int e, 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(int,XSetForeground,(Display* a,GC b,unsigned long c),(a,b,c),return) 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) diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c index 86a9e7db9..a3a8d2c72 100644 --- a/src/video/x11/SDL_x11video.c +++ b/src/video/x11/SDL_x11video.c @@ -21,6 +21,8 @@ */ #include "SDL_config.h" +#include /* For getpid() and readlink() */ + #include "SDL_video.h" #include "SDL_mouse.h" #include "../SDL_sysvideo.h" @@ -225,6 +227,10 @@ X11_CreateDevice(int devindex) 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; diff --git a/src/video/x11/SDL_x11video.h b/src/video/x11/SDL_x11video.h index a550f8485..34647ca51 100644 --- a/src/video/x11/SDL_x11video.h +++ b/src/video/x11/SDL_x11video.h @@ -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 @@ typedef struct SDL_VideoData int windowlistlength; Atom WM_DELETE_WINDOW; SDL_scancode key_layout[256]; + SDL_bool selection_waiting; } SDL_VideoData; extern SDL_bool X11_UseDirectColorVisuals(void);