mirror of
https://github.com/shadps4-emu/ext-SDL.git
synced 2025-01-09 12:20:19 +00:00
x11: Adds support for generic clipboard data in X11
Re-writes clipboard data handling in X11 to an on demand approach where data can be produced on request instead of storing it in X11 properties on the window. Primary selection has been changed to mimic this behavior even though it's only possible to use it for text as of now.
This commit is contained in:
parent
b48b1ce500
commit
da3fefc65c
@ -26,6 +26,42 @@
|
||||
|
||||
#include "SDL_x11video.h"
|
||||
#include "SDL_x11clipboard.h"
|
||||
#include "../../events/SDL_events_c.h"
|
||||
|
||||
#define TEXT_MIME_TYPES_LEN 5
|
||||
static const char *text_mime_types[TEXT_MIME_TYPES_LEN] = {
|
||||
"text/plain;charset=utf-8",
|
||||
"text/plain",
|
||||
"TEXT",
|
||||
"UTF8_STRING",
|
||||
"STRING",
|
||||
};
|
||||
|
||||
static void *X11_ClipboardTextCallback(size_t *length, const char *mime_type, void *userdata)
|
||||
{
|
||||
void *data = NULL;
|
||||
SDL_bool valid_mime_type = SDL_FALSE;
|
||||
*length = 0;
|
||||
|
||||
if (userdata == NULL) {
|
||||
return data;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < TEXT_MIME_TYPES_LEN; ++i) {
|
||||
if (SDL_strcmp(mime_type, text_mime_types[i]) == 0) {
|
||||
valid_mime_type = SDL_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_mime_type) {
|
||||
char *text = userdata;
|
||||
*length = SDL_strlen(text);
|
||||
data = userdata;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/* Get any application owned window handle for clipboard association */
|
||||
static Window GetWindow(SDL_VideoDevice *_this)
|
||||
@ -49,130 +85,113 @@ static Window GetWindow(SDL_VideoDevice *_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, enum ESDLX11ClipboardMimeType mime_type,
|
||||
Atom selection_type)
|
||||
static int SetSelectionData(SDL_VideoDevice *_this, Atom selection, SDL_ClipboardDataCallback callback,
|
||||
size_t mime_count, const char **mime_types, void *userdata, SDL_bool internal)
|
||||
{
|
||||
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, selection_type == XA_PRIMARY ? "SDL_CUTBUFFER_PRIMARY_SELECTION" : "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;
|
||||
}
|
||||
}
|
||||
|
||||
static int SetSelectionText(SDL_VideoDevice *_this, const char *text, Atom selection_type)
|
||||
{
|
||||
Display *display = _this->driverdata->display;
|
||||
SDL_VideoData *videodata = _this->driverdata;
|
||||
Display *display = videodata->display;
|
||||
Window window;
|
||||
SDLX11_ClipboardData *clipboard;
|
||||
SDL_bool clipboard_owner = SDL_FALSE;
|
||||
|
||||
/* Get the SDL window that will own the selection */
|
||||
window = GetWindow(_this);
|
||||
if (window == None) {
|
||||
return SDL_SetError("Couldn't find a window to own the selection");
|
||||
}
|
||||
|
||||
/* Save the selection on the root window */
|
||||
X11_XChangeProperty(display, DefaultRootWindow(display),
|
||||
X11_GetSDLCutBufferClipboardType(display, SDL_X11_CLIPBOARD_MIME_TYPE_STRING, selection_type),
|
||||
X11_GetSDLCutBufferClipboardInternalFormat(display, SDL_X11_CLIPBOARD_MIME_TYPE_STRING), 8, PropModeReplace,
|
||||
(const unsigned char *)text, SDL_strlen(text));
|
||||
|
||||
if (X11_XGetSelectionOwner(display, selection_type) != window) {
|
||||
X11_XSetSelectionOwner(display, selection_type, window, CurrentTime);
|
||||
if (selection == XA_PRIMARY) {
|
||||
clipboard = &videodata->primary_selection;
|
||||
} else {
|
||||
clipboard = &videodata->clipboard;
|
||||
}
|
||||
|
||||
clipboard_owner = X11_XGetSelectionOwner(display, selection) == window;
|
||||
|
||||
/* If we are cancelling our own data we need to clean it up */
|
||||
if (clipboard_owner) {
|
||||
if (clipboard->internal == SDL_TRUE) {
|
||||
SDL_free(clipboard->userdata);
|
||||
} else {
|
||||
SDL_SendClipboardCancelled(clipboard->userdata);
|
||||
}
|
||||
}
|
||||
|
||||
clipboard->callback = callback;
|
||||
clipboard->userdata = userdata;
|
||||
clipboard->mime_types = mime_types;
|
||||
clipboard->mime_count = mime_count;
|
||||
clipboard->internal = internal;
|
||||
|
||||
if (!clipboard_owner) {
|
||||
X11_XSetSelectionOwner(display, selection, window, CurrentTime);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *GetSelectionText(SDL_VideoDevice *_this, Atom selection_type)
|
||||
static void *CloneDataBuffer(void *buffer, size_t *len, SDL_bool nullterminate)
|
||||
{
|
||||
void *clone = NULL;
|
||||
if (*len > 0 && buffer != NULL) {
|
||||
if (nullterminate == SDL_TRUE) {
|
||||
clone = SDL_malloc((*len)+1);
|
||||
if (clone == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
} else {
|
||||
SDL_memcpy(clone, buffer, *len);
|
||||
((char *) clone)[*len] = '\0';
|
||||
*len += 1;
|
||||
}
|
||||
} else {
|
||||
clone = SDL_malloc(*len);
|
||||
if (clone == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
} else {
|
||||
SDL_memcpy(clone, buffer, *len);
|
||||
}
|
||||
}
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
static void *GetSelectionData(SDL_VideoDevice *_this, Atom selection_type, size_t *length,
|
||||
const char *mime_type, SDL_bool nullterminate)
|
||||
{
|
||||
SDL_VideoData *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;
|
||||
Uint64 waitStart;
|
||||
Uint64 waitElapsed;
|
||||
|
||||
text = NULL;
|
||||
void *data = NULL;
|
||||
unsigned char *src = NULL;
|
||||
Atom XA_MIME = X11_XInternAtom(display, mime_type, False);
|
||||
*length = 0;
|
||||
|
||||
/* Get the window that holds the selection */
|
||||
window = GetWindow(_this);
|
||||
format = X11_GetSDLCutBufferClipboardInternalFormat(display, SDL_X11_CLIPBOARD_MIME_TYPE_STRING);
|
||||
owner = X11_XGetSelectionOwner(display, selection_type);
|
||||
if (owner == None) {
|
||||
/* Fall back to ancient X10 cut-buffers which do not support UTF8 strings*/
|
||||
owner = DefaultRootWindow(display);
|
||||
selection = XA_CUT_BUFFER0;
|
||||
format = XA_STRING;
|
||||
/* This requires a fallback to ancient X10 cut-buffers. We will just skip those for now */
|
||||
return NULL;
|
||||
} else if (owner == window) {
|
||||
owner = DefaultRootWindow(display);
|
||||
selection = X11_GetSDLCutBufferClipboardType(display, SDL_X11_CLIPBOARD_MIME_TYPE_STRING, selection_type);
|
||||
if (selection_type == XA_PRIMARY) {
|
||||
src = videodata->primary_selection.callback(length, mime_type, videodata->primary_selection.userdata);
|
||||
} else {
|
||||
src = videodata->clipboard.callback(length, mime_type, videodata->clipboard.userdata);
|
||||
}
|
||||
|
||||
data = CloneDataBuffer(src, length, nullterminate);
|
||||
} else {
|
||||
/* Request that the selection owner copy the data to our window */
|
||||
owner = window;
|
||||
selection = X11_XInternAtom(display, "SDL_SELECTION", False);
|
||||
X11_XConvertSelection(display, selection_type, format, selection, owner,
|
||||
X11_XConvertSelection(display, selection_type, XA_MIME, selection, owner,
|
||||
CurrentTime);
|
||||
|
||||
/* When using synergy on Linux and when data has been put in the clipboard
|
||||
@ -189,29 +208,63 @@ static char *GetSelectionText(SDL_VideoDevice *_this, Atom selection_type)
|
||||
SDL_SetError("Selection timeout");
|
||||
/* We need to set the selection text so that next time we won't
|
||||
timeout, otherwise we will hang on every call to this function. */
|
||||
SetSelectionText(_this, "", selection_type);
|
||||
return SDL_strdup("");
|
||||
SetSelectionData(_this, selection_type, X11_ClipboardTextCallback, TEXT_MIME_TYPES_LEN,
|
||||
text_mime_types, NULL, SDL_TRUE);
|
||||
data = NULL;
|
||||
*length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (X11_XGetWindowProperty(display, owner, selection, 0, INT_MAX / 4, False,
|
||||
XA_MIME, &seln_type, &seln_format, length, &overflow, &src) == Success) {
|
||||
if (seln_type == XA_MIME) {
|
||||
data = CloneDataBuffer(src, length, nullterminate);
|
||||
}
|
||||
X11_XFree(src);
|
||||
}
|
||||
}
|
||||
|
||||
if (X11_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';
|
||||
}
|
||||
}
|
||||
X11_XFree(src);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
if (text == NULL) {
|
||||
text = SDL_strdup("");
|
||||
int X11_SetClipboardData(SDL_VideoDevice *_this, SDL_ClipboardDataCallback callback, size_t mime_count,
|
||||
const char **mime_types, void *userdata)
|
||||
{
|
||||
SDL_VideoData *videodata = _this->driverdata;
|
||||
Atom XA_CLIPBOARD = X11_XInternAtom(videodata->display, "CLIPBOARD", 0);
|
||||
if (XA_CLIPBOARD == None) {
|
||||
return SDL_SetError("Couldn't access X clipboard");
|
||||
}
|
||||
return SetSelectionData(_this, XA_CLIPBOARD, callback, mime_count, mime_types, userdata, SDL_FALSE);
|
||||
}
|
||||
|
||||
return text;
|
||||
void *X11_GetClipboardData(SDL_VideoDevice *_this, size_t *length, const char *mime_type)
|
||||
{
|
||||
SDL_VideoData *videodata = _this->driverdata;
|
||||
Atom XA_CLIPBOARD = X11_XInternAtom(videodata->display, "CLIPBOARD", 0);
|
||||
if (XA_CLIPBOARD == None) {
|
||||
SDL_SetError("Couldn't access X clipboard");
|
||||
*length = 0;
|
||||
return NULL;
|
||||
}
|
||||
return GetSelectionData(_this, XA_CLIPBOARD, length, mime_type, SDL_FALSE);
|
||||
}
|
||||
|
||||
SDL_bool X11_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
|
||||
{
|
||||
size_t length;
|
||||
void *data;
|
||||
data = X11_GetClipboardData(_this, &length, mime_type);
|
||||
if (data != NULL && length > 0) {
|
||||
SDL_free(data);
|
||||
}
|
||||
return length > 0;
|
||||
}
|
||||
|
||||
void *X11_GetClipboardUserdata(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDLX11_ClipboardData *cb = &_this->driverdata->clipboard;
|
||||
return cb->internal ? NULL : cb->userdata;
|
||||
}
|
||||
|
||||
int X11_SetClipboardText(SDL_VideoDevice *_this, const char *text)
|
||||
@ -221,30 +274,35 @@ int X11_SetClipboardText(SDL_VideoDevice *_this, const char *text)
|
||||
if (XA_CLIPBOARD == None) {
|
||||
return SDL_SetError("Couldn't access X clipboard");
|
||||
}
|
||||
return SetSelectionText(_this, text, XA_CLIPBOARD);
|
||||
return SetSelectionData(_this, XA_CLIPBOARD, X11_ClipboardTextCallback, TEXT_MIME_TYPES_LEN, text_mime_types,
|
||||
SDL_strdup(text), SDL_TRUE);
|
||||
}
|
||||
|
||||
int X11_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text)
|
||||
{
|
||||
return SetSelectionText(_this, text, XA_PRIMARY);
|
||||
return SetSelectionData(_this, XA_PRIMARY, X11_ClipboardTextCallback, TEXT_MIME_TYPES_LEN, text_mime_types,
|
||||
SDL_strdup(text), SDL_TRUE);
|
||||
}
|
||||
|
||||
char *
|
||||
X11_GetClipboardText(SDL_VideoDevice *_this)
|
||||
{
|
||||
size_t length;
|
||||
SDL_VideoData *videodata = _this->driverdata;
|
||||
Atom XA_CLIPBOARD = X11_XInternAtom(videodata->display, "CLIPBOARD", 0);
|
||||
if (XA_CLIPBOARD == None) {
|
||||
SDL_SetError("Couldn't access X clipboard");
|
||||
return SDL_strdup("");
|
||||
}
|
||||
return GetSelectionText(_this, XA_CLIPBOARD);
|
||||
|
||||
return GetSelectionData(_this, XA_CLIPBOARD, &length, text_mime_types[0], SDL_TRUE);
|
||||
}
|
||||
|
||||
char *
|
||||
X11_GetPrimarySelectionText(SDL_VideoDevice *_this)
|
||||
{
|
||||
return GetSelectionText(_this, XA_PRIMARY);
|
||||
size_t length;
|
||||
return GetSelectionData(_this, XA_PRIMARY, &length, text_mime_types[0], SDL_TRUE);
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
@ -271,4 +329,16 @@ X11_HasPrimarySelectionText(SDL_VideoDevice *_this)
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
X11_QuitClipboard(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *data = _this->driverdata;
|
||||
if (data->primary_selection.internal == SDL_TRUE) {
|
||||
SDL_free(data->primary_selection.userdata);
|
||||
}
|
||||
if (data->clipboard.internal == SDL_TRUE) {
|
||||
SDL_free(data->clipboard.userdata);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_X11 */
|
||||
|
@ -23,25 +23,27 @@
|
||||
#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
|
||||
};
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
typedef struct X11_ClipboardData {
|
||||
SDL_ClipboardDataCallback callback;
|
||||
void *userdata;
|
||||
const char **mime_types;
|
||||
size_t mime_count;
|
||||
SDL_bool internal;
|
||||
} SDLX11_ClipboardData;
|
||||
|
||||
extern int X11_SetClipboardData(SDL_VideoDevice *_this, SDL_ClipboardDataCallback callback, size_t mime_count,
|
||||
const char **mime_types, void *userdata);
|
||||
extern void *X11_GetClipboardData(SDL_VideoDevice *_this, size_t *length, const char *mime_type);
|
||||
extern SDL_bool X11_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type);
|
||||
extern void *X11_GetClipboardUserdata(SDL_VideoDevice *_this);
|
||||
extern int X11_SetClipboardText(SDL_VideoDevice *_this, const char *text);
|
||||
extern char *X11_GetClipboardText(SDL_VideoDevice *_this);
|
||||
extern SDL_bool X11_HasClipboardText(SDL_VideoDevice *_this);
|
||||
extern int X11_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text);
|
||||
extern char *X11_GetPrimarySelectionText(SDL_VideoDevice *_this);
|
||||
extern SDL_bool X11_HasPrimarySelectionText(SDL_VideoDevice *_this);
|
||||
extern Atom X11_GetSDLCutBufferClipboardType(Display *display, enum ESDLX11ClipboardMimeType mime_type, Atom selection_type);
|
||||
extern Atom X11_GetSDLCutBufferClipboardExternalFormat(Display *display, enum ESDLX11ClipboardMimeType mime_type);
|
||||
extern Atom X11_GetSDLCutBufferClipboardInternalFormat(Display *display, enum ESDLX11ClipboardMimeType mime_type);
|
||||
extern void X11_QuitClipboard(SDL_VideoDevice *_this);
|
||||
|
||||
#endif /* SDL_x11clipboard_h_ */
|
||||
|
@ -627,18 +627,28 @@ static void X11_HandleClipboardEvent(SDL_VideoDevice *_this, const XEvent *xeven
|
||||
{
|
||||
const XSelectionRequestEvent *req = &xevent->xselectionrequest;
|
||||
XEvent sevent;
|
||||
int seln_format, mime_formats;
|
||||
int mime_formats;
|
||||
unsigned long nbytes;
|
||||
unsigned long overflow;
|
||||
unsigned char *seln_data;
|
||||
Atom supportedFormats[SDL_X11_CLIPBOARD_MIME_TYPE_MAX + 1];
|
||||
Atom XA_TARGETS = X11_XInternAtom(display, "TARGETS", 0);
|
||||
SDLX11_ClipboardData *clipboard;
|
||||
|
||||
#ifdef DEBUG_XEVENTS
|
||||
printf("window CLIPBOARD: SelectionRequest (requestor = %ld, target = %ld)\n",
|
||||
req->requestor, req->target);
|
||||
char *atom_name;
|
||||
atom_name = X11_XGetAtomName(display, req->target);
|
||||
printf("window CLIPBOARD: SelectionRequest (requestor = %ld, target = %ld, mime_type = %s)\n",
|
||||
req->requestor, req->target, atom_name);
|
||||
if (atom_name) {
|
||||
X11_XFree(atom_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (req->selection == XA_PRIMARY) {
|
||||
clipboard = &videodata->primary_selection;
|
||||
} else {
|
||||
clipboard = &videodata->clipboard;
|
||||
}
|
||||
|
||||
SDL_zero(sevent);
|
||||
sevent.xany.type = SelectionNotify;
|
||||
sevent.xselection.selection = req->selection;
|
||||
@ -652,10 +662,12 @@ static void X11_HandleClipboardEvent(SDL_VideoDevice *_this, const XEvent *xeven
|
||||
this now (or ever, really). */
|
||||
|
||||
if (req->target == XA_TARGETS) {
|
||||
Atom *supportedFormats;
|
||||
supportedFormats = SDL_malloc((clipboard->mime_count + 1) * sizeof(Atom));
|
||||
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);
|
||||
for (i = 0; i < clipboard->mime_count; ++i) {
|
||||
supportedFormats[mime_formats++] = X11_XInternAtom(display, clipboard->mime_types[i], False);
|
||||
}
|
||||
X11_XChangeProperty(display, req->requestor, req->property,
|
||||
XA_ATOM, 32, PropModeReplace,
|
||||
@ -663,25 +675,25 @@ static void X11_HandleClipboardEvent(SDL_VideoDevice *_this, const XEvent *xeven
|
||||
mime_formats);
|
||||
sevent.xselection.property = req->property;
|
||||
sevent.xselection.target = XA_TARGETS;
|
||||
SDL_free(supportedFormats);
|
||||
} 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, req->selection), 0, INT_MAX / 4, False, X11_GetSDLCutBufferClipboardInternalFormat(display, i),
|
||||
&sevent.xselection.target, &seln_format, &nbytes,
|
||||
&overflow, &seln_data) == Success) {
|
||||
if (seln_format != None) {
|
||||
if (clipboard->callback) {
|
||||
for (i = 0; i < clipboard->mime_count; ++i) {
|
||||
const char *mime_type = clipboard->mime_types[i];
|
||||
if (X11_XInternAtom(display, mime_type, False) != req->target) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* FIXME: We don't support the X11 INCR protocol for large clipboards. Do we want that? */
|
||||
seln_data = clipboard->callback(&nbytes, mime_type, clipboard->userdata);
|
||||
if (seln_data != NULL) {
|
||||
X11_XChangeProperty(display, req->requestor, req->property,
|
||||
sevent.xselection.target, seln_format, PropModeReplace,
|
||||
req->target, 8, PropModeReplace,
|
||||
seln_data, nbytes);
|
||||
sevent.xselection.property = req->property;
|
||||
X11_XFree(seln_data);
|
||||
break;
|
||||
} else {
|
||||
X11_XFree(seln_data);
|
||||
sevent.xselection.target = req->target;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -702,15 +714,24 @@ static void X11_HandleClipboardEvent(SDL_VideoDevice *_this, const XEvent *xeven
|
||||
{
|
||||
/* !!! FIXME: cache atoms */
|
||||
Atom XA_CLIPBOARD = X11_XInternAtom(display, "CLIPBOARD", 0);
|
||||
SDLX11_ClipboardData *clipboard = NULL;
|
||||
|
||||
#ifdef DEBUG_XEVENTS
|
||||
printf("window CLIPBOARD: SelectionClear (requestor = %ld, target = %ld)\n",
|
||||
xevent->xselection.requestor, xevent->xselection.target);
|
||||
#endif
|
||||
|
||||
if (xevent->xselectionclear.selection == XA_PRIMARY ||
|
||||
(XA_CLIPBOARD != None && xevent->xselectionclear.selection == XA_CLIPBOARD)) {
|
||||
SDL_SendClipboardUpdate();
|
||||
if (xevent->xselectionclear.selection == XA_PRIMARY) {
|
||||
clipboard = &videodata->primary_selection;
|
||||
} else if (XA_CLIPBOARD != None && xevent->xselectionclear.selection == XA_CLIPBOARD) {
|
||||
clipboard = &videodata->clipboard;
|
||||
if (clipboard->internal == SDL_FALSE) {
|
||||
SDL_SendClipboardCancelled(clipboard->userdata);
|
||||
}
|
||||
}
|
||||
if (clipboard != NULL && clipboard->internal == SDL_TRUE) {
|
||||
SDL_free(clipboard->userdata);
|
||||
clipboard->userdata = NULL;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
@ -293,9 +293,13 @@ static SDL_VideoDevice *X11_CreateDevice(void)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
device->SetClipboardData = X11_SetClipboardData;
|
||||
device->GetClipboardData = X11_GetClipboardData;
|
||||
device->HasClipboardData = X11_HasClipboardData;
|
||||
device->SetClipboardText = X11_SetClipboardText;
|
||||
device->GetClipboardText = X11_GetClipboardText;
|
||||
device->HasClipboardText = X11_HasClipboardText;
|
||||
device->GetClipboardUserdata = X11_GetClipboardUserdata;
|
||||
device->SetPrimarySelectionText = X11_SetPrimarySelectionText;
|
||||
device->GetPrimarySelectionText = X11_GetPrimarySelectionText;
|
||||
device->HasPrimarySelectionText = X11_HasPrimarySelectionText;
|
||||
@ -498,6 +502,7 @@ void X11_VideoQuit(SDL_VideoDevice *_this)
|
||||
X11_QuitKeyboard(_this);
|
||||
X11_QuitMouse(_this);
|
||||
X11_QuitTouch(_this);
|
||||
X11_QuitClipboard(_this);
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
|
@ -77,6 +77,8 @@ struct SDL_VideoData
|
||||
int windowlistlength;
|
||||
XID window_group;
|
||||
Window clipboard_window;
|
||||
SDLX11_ClipboardData clipboard;
|
||||
SDLX11_ClipboardData primary_selection;
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
|
||||
SDL_Window *active_cursor_confined_window;
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XFIXES */
|
||||
|
Loading…
Reference in New Issue
Block a user