XDnD implementation from Davey Taylor, need some cleanup
This commit is contained in:
parent
d1c430023f
commit
124288fdb9
5 changed files with 240 additions and 3 deletions
|
@ -41,6 +41,62 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char *data;
|
||||||
|
int format, count;
|
||||||
|
Atom type;
|
||||||
|
} SDL_x11Prop;
|
||||||
|
|
||||||
|
/* Reads property
|
||||||
|
Must call XFree on results
|
||||||
|
*/
|
||||||
|
static void X11_ReadProperty(SDL_x11Prop *p, Display *disp, Window w, Atom prop)
|
||||||
|
{
|
||||||
|
unsigned char *ret=NULL;
|
||||||
|
Atom type;
|
||||||
|
int fmt;
|
||||||
|
unsigned long count;
|
||||||
|
unsigned long bytes_left;
|
||||||
|
int bytes_fetch = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (ret != 0) XFree(ret);
|
||||||
|
XGetWindowProperty(disp, w, prop, 0, bytes_fetch, False, AnyPropertyType, &type, &fmt, &count, &bytes_left, &ret);
|
||||||
|
bytes_fetch += bytes_left;
|
||||||
|
} while (bytes_left != 0);
|
||||||
|
|
||||||
|
p->data=ret;
|
||||||
|
p->format=fmt;
|
||||||
|
p->count=count;
|
||||||
|
p->type=type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find text-uri-list in a list of targets and return it's atom
|
||||||
|
if available, else return None */
|
||||||
|
static Atom X11_PickTarget(Display *disp, Atom list[], int list_count)
|
||||||
|
{
|
||||||
|
Atom request = None;
|
||||||
|
char *name;
|
||||||
|
int i;
|
||||||
|
for (i=0; i < list_count && request == None; i++) {
|
||||||
|
name = XGetAtomName(disp, list[i]);
|
||||||
|
if (strcmp("text/uri-list", name)==0) request = list[i];
|
||||||
|
XFree(name);
|
||||||
|
}
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapper for X11_PickTarget for a maximum of three targets, a special
|
||||||
|
case in the Xdnd protocol */
|
||||||
|
static Atom X11_PickTargetFromAtoms(Display *disp, Atom a0, Atom a1, Atom a2)
|
||||||
|
{
|
||||||
|
int count=0;
|
||||||
|
Atom atom[3];
|
||||||
|
if (a0 != None) atom[count++] = a0;
|
||||||
|
if (a1 != None) atom[count++] = a1;
|
||||||
|
if (a2 != None) atom[count++] = a2;
|
||||||
|
return X11_PickTarget(disp, atom, count);
|
||||||
|
}
|
||||||
/*#define DEBUG_XEVENTS*/
|
/*#define DEBUG_XEVENTS*/
|
||||||
|
|
||||||
/* Check to see if this is a repeated key.
|
/* Check to see if this is a repeated key.
|
||||||
|
@ -92,6 +148,41 @@ static SDL_bool X11_IsWheelEvent(Display * display,XEvent * event,int * ticks)
|
||||||
return SDL_FALSE;
|
return SDL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert URI to local filename
|
||||||
|
return filename if possible, else NULL
|
||||||
|
*/
|
||||||
|
static char* X11_URIToLocal(char* uri) {
|
||||||
|
char *file = NULL;
|
||||||
|
|
||||||
|
if (memcmp(uri,"file:/",6) == 0) uri += 6; /* local file? */
|
||||||
|
else if (strstr(uri,":/") != NULL) return file; /* wrong scheme */
|
||||||
|
|
||||||
|
SDL_bool local = uri[0] != '/' || ( uri[0] != '\0' && uri[1] == '/' );
|
||||||
|
|
||||||
|
/* got a hostname? */
|
||||||
|
if ( !local && uri[0] == '/' && uri[2] != '/' ) {
|
||||||
|
char* hostname_end = strchr( uri+1, '/' );
|
||||||
|
if ( hostname_end != NULL ) {
|
||||||
|
char hostname[ 257 ];
|
||||||
|
if ( gethostname( hostname, 255 ) == 0 ) {
|
||||||
|
hostname[ 256 ] = '\0';
|
||||||
|
if ( memcmp( uri+1, hostname, hostname_end - ( uri+1 )) == 0 ) {
|
||||||
|
uri = hostname_end + 1;
|
||||||
|
local = SDL_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( local ) {
|
||||||
|
file = uri;
|
||||||
|
if ( uri[1] == '/' ) {
|
||||||
|
file++;
|
||||||
|
} else {
|
||||||
|
file--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
#if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
|
#if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
|
||||||
static void X11_HandleGenericEvent(SDL_VideoData *videodata,XEvent event)
|
static void X11_HandleGenericEvent(SDL_VideoData *videodata,XEvent event)
|
||||||
|
@ -400,7 +491,68 @@ X11_DispatchEvent(_THIS)
|
||||||
|
|
||||||
/* Have we been requested to quit (or another client message?) */
|
/* Have we been requested to quit (or another client message?) */
|
||||||
case ClientMessage:{
|
case ClientMessage:{
|
||||||
if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
|
|
||||||
|
int xdnd_version=0;
|
||||||
|
|
||||||
|
if (xevent.xclient.message_type == videodata->XdndEnter) {
|
||||||
|
SDL_bool use_list = xevent.xclient.data.l[1] & 1;
|
||||||
|
data->xdnd_source = xevent.xclient.data.l[0];
|
||||||
|
xdnd_version = ( xevent.xclient.data.l[1] >> 24);
|
||||||
|
if (use_list) {
|
||||||
|
/* fetch conversion targets */
|
||||||
|
SDL_x11Prop p;
|
||||||
|
X11_ReadProperty(&p, display, data->xdnd_source, videodata->XdndTypeList);
|
||||||
|
/* pick one */
|
||||||
|
data->xdnd_req = X11_PickTarget(display, (Atom*)p.data, p.count);
|
||||||
|
XFree(p.data);
|
||||||
|
} else {
|
||||||
|
/* pick from list of three */
|
||||||
|
data->xdnd_req = X11_PickTargetFromAtoms(display, xevent.xclient.data.l[2], xevent.xclient.data.l[3], xevent.xclient.data.l[4]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (xevent.xclient.message_type == videodata->XdndPosition) {
|
||||||
|
|
||||||
|
/* reply with status */
|
||||||
|
XClientMessageEvent m;
|
||||||
|
memset(&m, 0, sizeof(XClientMessageEvent));
|
||||||
|
m.type = ClientMessage;
|
||||||
|
m.display = xevent.xclient.display;
|
||||||
|
m.window = xevent.xclient.data.l[0];
|
||||||
|
m.message_type = videodata->XdndStatus;
|
||||||
|
m.format=32;
|
||||||
|
m.data.l[0] = data->xwindow;
|
||||||
|
m.data.l[1] = (data->xdnd_req != None);
|
||||||
|
m.data.l[2] = 0; /* specify an empty rectangle */
|
||||||
|
m.data.l[3] = 0;
|
||||||
|
m.data.l[4] = videodata->XdndActionCopy; /* we only accept copying anyway */
|
||||||
|
|
||||||
|
XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
|
||||||
|
XFlush(display);
|
||||||
|
}
|
||||||
|
else if(xevent.xclient.message_type == videodata->XdndDrop) {
|
||||||
|
if (data->xdnd_req == None) {
|
||||||
|
/* say again - not interested! */
|
||||||
|
XClientMessageEvent m;
|
||||||
|
memset(&m, 0, sizeof(XClientMessageEvent));
|
||||||
|
m.type = ClientMessage;
|
||||||
|
m.display = xevent.xclient.display;
|
||||||
|
m.window = xevent.xclient.data.l[0];
|
||||||
|
m.message_type = videodata->XdndFinished;
|
||||||
|
m.format=32;
|
||||||
|
m.data.l[0] = data->xwindow;
|
||||||
|
m.data.l[1] = 0;
|
||||||
|
m.data.l[2] = None; /* fail! */
|
||||||
|
XSendEvent(display, xevent.xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
|
||||||
|
} else {
|
||||||
|
/* convert */
|
||||||
|
if(xdnd_version >= 1) {
|
||||||
|
XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, xevent.xclient.data.l[2]);
|
||||||
|
} else {
|
||||||
|
XConvertSelection(display, videodata->XdndSelection, data->xdnd_req, videodata->PRIMARY, data->xwindow, CurrentTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) &&
|
||||||
(xevent.xclient.format == 32) &&
|
(xevent.xclient.format == 32) &&
|
||||||
(xevent.xclient.data.l[0] == videodata->_NET_WM_PING)) {
|
(xevent.xclient.data.l[0] == videodata->_NET_WM_PING)) {
|
||||||
Window root = DefaultRootWindow(display);
|
Window root = DefaultRootWindow(display);
|
||||||
|
@ -601,7 +753,66 @@ X11_DispatchEvent(_THIS)
|
||||||
printf("window %p: SelectionNotify (requestor = %ld, target = %ld)\n", data,
|
printf("window %p: SelectionNotify (requestor = %ld, target = %ld)\n", data,
|
||||||
xevent.xselection.requestor, xevent.xselection.target);
|
xevent.xselection.requestor, xevent.xselection.target);
|
||||||
#endif
|
#endif
|
||||||
videodata->selection_waiting = SDL_FALSE;
|
Atom target = xevent.xselection.target;
|
||||||
|
if (target == data->xdnd_req) {
|
||||||
|
|
||||||
|
/* read data */
|
||||||
|
SDL_x11Prop p;
|
||||||
|
X11_ReadProperty(&p, display, data->xwindow, videodata->PRIMARY);
|
||||||
|
|
||||||
|
if(p.format==8) {
|
||||||
|
SDL_bool expect_lf = SDL_FALSE;
|
||||||
|
char *start = NULL;
|
||||||
|
char *scan = (char*)p.data;
|
||||||
|
char *fn;
|
||||||
|
char *uri;
|
||||||
|
int length = 0;
|
||||||
|
while (p.count--) {
|
||||||
|
if (!expect_lf) {
|
||||||
|
if (*scan==0x0D) {
|
||||||
|
expect_lf = SDL_TRUE;
|
||||||
|
} else if(start == NULL) {
|
||||||
|
start = scan;
|
||||||
|
length = 0;
|
||||||
|
}
|
||||||
|
length++;
|
||||||
|
} else {
|
||||||
|
if (*scan==0x0A && length>0) {
|
||||||
|
uri = malloc(length--);
|
||||||
|
memcpy(uri, start, length);
|
||||||
|
uri[length] = 0;
|
||||||
|
fn = X11_URIToLocal(uri);
|
||||||
|
if (fn) SDL_SendDropFile(fn);
|
||||||
|
free(uri);
|
||||||
|
}
|
||||||
|
expect_lf = SDL_FALSE;
|
||||||
|
start = NULL;
|
||||||
|
}
|
||||||
|
scan++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XFree(p.data);
|
||||||
|
|
||||||
|
/* send reply */
|
||||||
|
XClientMessageEvent m;
|
||||||
|
memset(&m, 0, sizeof(XClientMessageEvent));
|
||||||
|
m.type = ClientMessage;
|
||||||
|
m.display = display;
|
||||||
|
m.window = data->xdnd_source;
|
||||||
|
m.message_type = videodata->XdndFinished;
|
||||||
|
m.format=32;
|
||||||
|
m.data.l[0] = data->xwindow;
|
||||||
|
m.data.l[1] = 1;
|
||||||
|
m.data.l[2] = videodata->XdndActionCopy;
|
||||||
|
XSendEvent(display, data->xdnd_source, False, NoEventMask, (XEvent*)&m);
|
||||||
|
|
||||||
|
XSync(display, False);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
videodata->selection_waiting = SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -524,6 +524,15 @@ X11_VideoInit(_THIS)
|
||||||
GET_ATOM(_NET_WM_PING);
|
GET_ATOM(_NET_WM_PING);
|
||||||
GET_ATOM(_NET_ACTIVE_WINDOW);
|
GET_ATOM(_NET_ACTIVE_WINDOW);
|
||||||
GET_ATOM(UTF8_STRING);
|
GET_ATOM(UTF8_STRING);
|
||||||
|
GET_ATOM(PRIMARY);
|
||||||
|
GET_ATOM(XdndEnter);
|
||||||
|
GET_ATOM(XdndPosition);
|
||||||
|
GET_ATOM(XdndStatus);
|
||||||
|
GET_ATOM(XdndTypeList);
|
||||||
|
GET_ATOM(XdndActionCopy);
|
||||||
|
GET_ATOM(XdndDrop);
|
||||||
|
GET_ATOM(XdndFinished);
|
||||||
|
GET_ATOM(XdndSelection);
|
||||||
|
|
||||||
/* Detect the window manager */
|
/* Detect the window manager */
|
||||||
X11_CheckWindowManager(_this);
|
X11_CheckWindowManager(_this);
|
||||||
|
|
|
@ -101,7 +101,16 @@ typedef struct SDL_VideoData
|
||||||
Atom _NET_WM_PING;
|
Atom _NET_WM_PING;
|
||||||
Atom _NET_ACTIVE_WINDOW;
|
Atom _NET_ACTIVE_WINDOW;
|
||||||
Atom UTF8_STRING;
|
Atom UTF8_STRING;
|
||||||
|
Atom PRIMARY;
|
||||||
|
Atom XdndEnter;
|
||||||
|
Atom XdndPosition;
|
||||||
|
Atom XdndStatus;
|
||||||
|
Atom XdndTypeList;
|
||||||
|
Atom XdndActionCopy;
|
||||||
|
Atom XdndDrop;
|
||||||
|
Atom XdndFinished;
|
||||||
|
Atom XdndSelection;
|
||||||
|
|
||||||
SDL_Scancode key_layout[256];
|
SDL_Scancode key_layout[256];
|
||||||
SDL_bool selection_waiting;
|
SDL_bool selection_waiting;
|
||||||
|
|
||||||
|
|
|
@ -344,6 +344,7 @@ X11_CreateWindow(_THIS, SDL_Window * window)
|
||||||
Atom _NET_WM_WINDOW_TYPE;
|
Atom _NET_WM_WINDOW_TYPE;
|
||||||
Atom _NET_WM_WINDOW_TYPE_NORMAL;
|
Atom _NET_WM_WINDOW_TYPE_NORMAL;
|
||||||
Atom _NET_WM_PID;
|
Atom _NET_WM_PID;
|
||||||
|
Atom XdndAware, xdnd_version = 5;
|
||||||
Uint32 fevent = 0;
|
Uint32 fevent = 0;
|
||||||
|
|
||||||
#if SDL_VIDEO_OPENGL_GLX || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
|
#if SDL_VIDEO_OPENGL_GLX || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
|
||||||
|
@ -567,6 +568,11 @@ X11_CreateWindow(_THIS, SDL_Window * window)
|
||||||
PropertyChangeMask | StructureNotifyMask |
|
PropertyChangeMask | StructureNotifyMask |
|
||||||
KeymapStateMask | fevent));
|
KeymapStateMask | fevent));
|
||||||
|
|
||||||
|
XdndAware = XInternAtom(display, "XdndAware", False);
|
||||||
|
XChangeProperty(display, w, XdndAware, XA_ATOM, 32,
|
||||||
|
PropModeReplace,
|
||||||
|
(unsigned char*)&xdnd_version, 1);
|
||||||
|
|
||||||
XFlush(display);
|
XFlush(display);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -57,6 +57,8 @@ typedef struct
|
||||||
Uint32 pending_focus_time;
|
Uint32 pending_focus_time;
|
||||||
XConfigureEvent last_xconfigure;
|
XConfigureEvent last_xconfigure;
|
||||||
struct SDL_VideoData *videodata;
|
struct SDL_VideoData *videodata;
|
||||||
|
Atom xdnd_req;
|
||||||
|
Window xdnd_source;
|
||||||
} SDL_WindowData;
|
} SDL_WindowData;
|
||||||
|
|
||||||
extern void X11_SetNetWMState(_THIS, Window xwindow, Uint32 flags);
|
extern void X11_SetNetWMState(_THIS, Window xwindow, Uint32 flags);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue