diff --git a/src/video/x11/SDL_x11clipboard.c b/src/video/x11/SDL_x11clipboard.c index ad34b3a56..7a50ce2de 100644 --- a/src/video/x11/SDL_x11clipboard.c +++ b/src/video/x11/SDL_x11clipboard.c @@ -27,14 +27,7 @@ #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 +#include "SDL_x11clipboard.h" /* Get any application owned window handle for clipboard association */ static Window @@ -59,19 +52,77 @@ GetWindow(_THIS) 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) +X11_GetSDLCutBufferClipboardType(Display *display, enum ESDLX11ClipboardMimeType mime_type) { - return X11_XInternAtom(display, "SDL_CUTBUFFER", False); + switch (mime_type) { + case SDL_X11_CLIPBOARD_MIME_TYPE_STRING: + case SDL_X11_CLIPBOARD_MIME_TYPE_TEXT_PLAIN: + #ifdef X_HAVE_UTF8_STRING + case SDL_X11_CLIPBOARD_MIME_TYPE_TEXT_PLAIN_UTF8: + #endif + case SDL_X11_CLIPBOARD_MIME_TYPE_TEXT: + return X11_XInternAtom(display, "SDL_CUTBUFFER", False); + default: + SDL_SetError("Can't find mime_type."); + return XA_STRING; + } } +Atom +X11_GetSDLCutBufferClipboardExternalFormat(Display *display, enum ESDLX11ClipboardMimeType mime_type) +{ + switch (mime_type) { + case SDL_X11_CLIPBOARD_MIME_TYPE_STRING: + /* If you don't support UTF-8, you might use XA_STRING here */ + #ifdef X_HAVE_UTF8_STRING + return X11_XInternAtom(display, "UTF8_STRING", False); + #else + return XA_STRING; + #endif + case SDL_X11_CLIPBOARD_MIME_TYPE_TEXT_PLAIN: + return X11_XInternAtom(display, "text/plain", False); + #ifdef X_HAVE_UTF8_STRING + case SDL_X11_CLIPBOARD_MIME_TYPE_TEXT_PLAIN_UTF8: + return X11_XInternAtom(display, "text/plain;charset=utf-8", False); + #endif + case SDL_X11_CLIPBOARD_MIME_TYPE_TEXT: + return X11_XInternAtom(display, "TEXT", False); + default: + SDL_SetError("Can't find mime_type."); + return XA_STRING; + } +} +Atom +X11_GetSDLCutBufferClipboardInternalFormat(Display *display, enum ESDLX11ClipboardMimeType mime_type) +{ + switch (mime_type) { + case SDL_X11_CLIPBOARD_MIME_TYPE_STRING: + case SDL_X11_CLIPBOARD_MIME_TYPE_TEXT_PLAIN: + #ifdef X_HAVE_UTF8_STRING + case SDL_X11_CLIPBOARD_MIME_TYPE_TEXT_PLAIN_UTF8: + #endif + case SDL_X11_CLIPBOARD_MIME_TYPE_TEXT: + /* If you don't support UTF-8, you might use XA_STRING here */ + #ifdef X_HAVE_UTF8_STRING + return X11_XInternAtom(display, "UTF8_STRING", False); + #else + return XA_STRING; + #endif + default: + SDL_SetError("Can't find mime_type."); + return XA_STRING; + } +} + + 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); @@ -82,9 +133,8 @@ X11_SetClipboardText(_THIS, const char *text) } /* Save the selection on the root window */ - format = TEXT_FORMAT; X11_XChangeProperty(display, DefaultRootWindow(display), - X11_GetSDLCutBufferClipboardType(display), format, 8, PropModeReplace, + X11_GetSDLCutBufferClipboardType(display, SDL_X11_CLIPBOARD_MIME_TYPE_STRING), X11_GetSDLCutBufferClipboardInternalFormat(display, SDL_X11_CLIPBOARD_MIME_TYPE_STRING), 8, PropModeReplace, (const unsigned char *)text, SDL_strlen(text)); if (XA_CLIPBOARD != None && @@ -125,7 +175,7 @@ X11_GetClipboardText(_THIS) /* Get the window that holds the selection */ window = GetWindow(_this); - format = TEXT_FORMAT; + format = X11_GetSDLCutBufferClipboardInternalFormat(display, SDL_X11_CLIPBOARD_MIME_TYPE_STRING); owner = X11_XGetSelectionOwner(display, XA_CLIPBOARD); if (owner == None) { /* Fall back to ancient X10 cut-buffers which do not support UTF8 strings*/ @@ -134,7 +184,7 @@ X11_GetClipboardText(_THIS) format = XA_STRING; } else if (owner == window) { owner = DefaultRootWindow(display); - selection = X11_GetSDLCutBufferClipboardType(display); + selection = X11_GetSDLCutBufferClipboardType(display, SDL_X11_CLIPBOARD_MIME_TYPE_STRING); } else { /* Request that the selection owner copy the data to our window */ owner = window; diff --git a/src/video/x11/SDL_x11clipboard.h b/src/video/x11/SDL_x11clipboard.h index 09b7f515e..9a61f5a07 100644 --- a/src/video/x11/SDL_x11clipboard.h +++ b/src/video/x11/SDL_x11clipboard.h @@ -23,10 +23,22 @@ #ifndef SDL_x11clipboard_h_ #define SDL_x11clipboard_h_ +enum ESDLX11ClipboardMimeType { + SDL_X11_CLIPBOARD_MIME_TYPE_STRING, + SDL_X11_CLIPBOARD_MIME_TYPE_TEXT_PLAIN, + #ifdef X_HAVE_UTF8_STRING + SDL_X11_CLIPBOARD_MIME_TYPE_TEXT_PLAIN_UTF8, + #endif + SDL_X11_CLIPBOARD_MIME_TYPE_TEXT, + SDL_X11_CLIPBOARD_MIME_TYPE_MAX +}; + extern int X11_SetClipboardText(_THIS, const char *text); extern char *X11_GetClipboardText(_THIS); extern SDL_bool X11_HasClipboardText(_THIS); -extern Atom X11_GetSDLCutBufferClipboardType(Display *display); +extern Atom X11_GetSDLCutBufferClipboardType(Display *display, enum ESDLX11ClipboardMimeType mime_type); +extern Atom X11_GetSDLCutBufferClipboardExternalFormat(Display *display, enum ESDLX11ClipboardMimeType mime_type); +extern Atom X11_GetSDLCutBufferClipboardInternalFormat(Display *display, enum ESDLX11ClipboardMimeType mime_type); #endif /* SDL_x11clipboard_h_ */ diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 8d19a2e6d..d3b02f568 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -562,6 +562,7 @@ X11_UpdateUserTime(SDL_WindowData *data, const unsigned long latest) static void X11_HandleClipboardEvent(_THIS, const XEvent *xevent) { + int i; SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; Display *display = videodata->display; @@ -573,10 +574,12 @@ X11_HandleClipboardEvent(_THIS, const XEvent *xevent) case SelectionRequest: { const XSelectionRequestEvent *req = &xevent->xselectionrequest; XEvent sevent; - int seln_format; + int seln_format, mime_formats; unsigned long nbytes; unsigned long overflow; - unsigned char *seln_data; + unsigned char *seln_data; + Atom supportedFormats[SDL_X11_CLIPBOARD_MIME_TYPE_MAX+1]; + Atom XA_TARGETS = X11_XInternAtom(display, "TARGETS", 0); #ifdef DEBUG_XEVENTS printf("window CLIPBOARD: SelectionRequest (requestor = %ld, target = %ld)\n", @@ -594,27 +597,38 @@ X11_HandleClipboardEvent(_THIS, const XEvent *xevent) /* !!! FIXME: We were probably storing this on the root window because an SDL window might go away...? but we don't have to do this now (or ever, really). */ - if (X11_XGetWindowProperty(display, DefaultRootWindow(display), - X11_GetSDLCutBufferClipboardType(display), 0, INT_MAX/4, False, req->target, - &sevent.xselection.target, &seln_format, &nbytes, - &overflow, &seln_data) == Success) { - /* !!! FIXME: cache atoms */ - Atom XA_TARGETS = X11_XInternAtom(display, "TARGETS", 0); - if (sevent.xselection.target == req->target) { - X11_XChangeProperty(display, req->requestor, req->property, - sevent.xselection.target, seln_format, PropModeReplace, - seln_data, nbytes); - sevent.xselection.property = req->property; - } else if (XA_TARGETS == req->target) { - Atom SupportedFormats[] = { XA_TARGETS, sevent.xselection.target }; - X11_XChangeProperty(display, req->requestor, req->property, - XA_ATOM, 32, PropModeReplace, - (unsigned char*)SupportedFormats, - SDL_arraysize(SupportedFormats)); - sevent.xselection.property = req->property; - sevent.xselection.target = XA_TARGETS; + + if (req->target == XA_TARGETS) { + supportedFormats[0] = XA_TARGETS; + mime_formats = 1; + for (i = 0; i < SDL_X11_CLIPBOARD_MIME_TYPE_MAX; ++i) + supportedFormats[mime_formats++] = X11_GetSDLCutBufferClipboardExternalFormat(display, i); + X11_XChangeProperty(display, req->requestor, req->property, + XA_ATOM, 32, PropModeReplace, + (unsigned char*)supportedFormats, + mime_formats); + sevent.xselection.property = req->property; + sevent.xselection.target = XA_TARGETS; + } else { + for (i = 0; i < SDL_X11_CLIPBOARD_MIME_TYPE_MAX; ++i) { + if (X11_GetSDLCutBufferClipboardExternalFormat(display, i) != req->target) + continue; + if (X11_XGetWindowProperty(display, DefaultRootWindow(display), + X11_GetSDLCutBufferClipboardType(display, i), 0, INT_MAX/4, False, X11_GetSDLCutBufferClipboardInternalFormat(display, i), + &sevent.xselection.target, &seln_format, &nbytes, + &overflow, &seln_data) == Success) { + if (seln_format != None) { + X11_XChangeProperty(display, req->requestor, req->property, + sevent.xselection.target, seln_format, PropModeReplace, + seln_data, nbytes); + sevent.xselection.property = req->property; + X11_XFree(seln_data); + break; + } else { + X11_XFree(seln_data); + } + } } - X11_XFree(seln_data); } X11_XSendEvent(display, req->requestor, False, 0, &sevent); X11_XSync(display, False);