|
@@ -48,6 +48,8 @@
|
|
|
#define Button6 6
|
|
|
#define Button7 7
|
|
|
|
|
|
+#define _GLFW_XDND_VERSION 5
|
|
|
+
|
|
|
|
|
|
// Wait for data to arrive using select
|
|
|
// This avoids blocking other threads via the per-display Xlib lock that also
|
|
@@ -415,7 +417,12 @@ static char** parseUriList(char* text, int* count)
|
|
|
continue;
|
|
|
|
|
|
if (strncmp(line, prefix, strlen(prefix)) == 0)
|
|
|
+ {
|
|
|
line += strlen(prefix);
|
|
|
+ // TODO: Validate hostname
|
|
|
+ while (*line != '/')
|
|
|
+ line++;
|
|
|
+ }
|
|
|
|
|
|
(*count)++;
|
|
|
|
|
@@ -619,10 +626,9 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
|
|
|
XFree(hint);
|
|
|
}
|
|
|
|
|
|
- if (_glfw.x11.XdndAware)
|
|
|
+ // Announce support for Xdnd (drag and drop)
|
|
|
{
|
|
|
- // Announce support for Xdnd (drag and drop)
|
|
|
- const Atom version = 5;
|
|
|
+ const Atom version = _GLFW_XDND_VERSION;
|
|
|
XChangeProperty(_glfw.x11.display, window->x11.handle,
|
|
|
_glfw.x11.XdndAware, XA_ATOM, 32,
|
|
|
PropModeReplace, (unsigned char*) &version, 1);
|
|
@@ -1307,44 +1313,121 @@ static void processEvent(XEvent *event)
|
|
|
else if (event->xclient.message_type == _glfw.x11.XdndEnter)
|
|
|
{
|
|
|
// A drag operation has entered the window
|
|
|
- // TODO: Check if UTF-8 string is supported by the source
|
|
|
+ unsigned long i, count;
|
|
|
+ Atom* formats = NULL;
|
|
|
+ const GLFWbool list = event->xclient.data.l[1] & 1;
|
|
|
+
|
|
|
+ _glfw.x11.xdnd.source = event->xclient.data.l[0];
|
|
|
+ _glfw.x11.xdnd.version = event->xclient.data.l[1] >> 24;
|
|
|
+ _glfw.x11.xdnd.format = None;
|
|
|
+
|
|
|
+ if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (list)
|
|
|
+ {
|
|
|
+ count = _glfwGetWindowPropertyX11(_glfw.x11.xdnd.source,
|
|
|
+ _glfw.x11.XdndTypeList,
|
|
|
+ XA_ATOM,
|
|
|
+ (unsigned char**) &formats);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ count = 3;
|
|
|
+ formats = (Atom*) event->xclient.data.l + 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < count; i++)
|
|
|
+ {
|
|
|
+ if (formats[i] == _glfw.x11.text_uri_list)
|
|
|
+ {
|
|
|
+ _glfw.x11.xdnd.format = _glfw.x11.text_uri_list;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (list && formats)
|
|
|
+ XFree(formats);
|
|
|
}
|
|
|
else if (event->xclient.message_type == _glfw.x11.XdndDrop)
|
|
|
{
|
|
|
- // The drag operation has finished dropping on
|
|
|
- // the window, ask to convert it to a UTF-8 string
|
|
|
- _glfw.x11.xdnd.source = event->xclient.data.l[0];
|
|
|
- XConvertSelection(_glfw.x11.display,
|
|
|
- _glfw.x11.XdndSelection,
|
|
|
- _glfw.x11.UTF8_STRING,
|
|
|
- _glfw.x11.XdndSelection,
|
|
|
- window->x11.handle, CurrentTime);
|
|
|
+ // The drag operation has finished by dropping on the window
|
|
|
+ Time time = CurrentTime;
|
|
|
+
|
|
|
+ if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (_glfw.x11.xdnd.format)
|
|
|
+ {
|
|
|
+ if (_glfw.x11.xdnd.version >= 1)
|
|
|
+ time = event->xclient.data.l[2];
|
|
|
+
|
|
|
+ // Request the chosen format from the source window
|
|
|
+ XConvertSelection(_glfw.x11.display,
|
|
|
+ _glfw.x11.XdndSelection,
|
|
|
+ _glfw.x11.xdnd.format,
|
|
|
+ _glfw.x11.XdndSelection,
|
|
|
+ window->x11.handle,
|
|
|
+ time);
|
|
|
+ }
|
|
|
+ else if (_glfw.x11.xdnd.version >= 2)
|
|
|
+ {
|
|
|
+ XEvent reply;
|
|
|
+ memset(&reply, 0, sizeof(reply));
|
|
|
+
|
|
|
+ reply.type = ClientMessage;
|
|
|
+ reply.xclient.window = _glfw.x11.xdnd.source;
|
|
|
+ reply.xclient.message_type = _glfw.x11.XdndFinished;
|
|
|
+ reply.xclient.format = 32;
|
|
|
+ reply.xclient.data.l[0] = window->x11.handle;
|
|
|
+ reply.xclient.data.l[1] = 0; // The drag was rejected
|
|
|
+ reply.xclient.data.l[2] = None;
|
|
|
+
|
|
|
+ XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source,
|
|
|
+ False, NoEventMask, &reply);
|
|
|
+ XFlush(_glfw.x11.display);
|
|
|
+ }
|
|
|
}
|
|
|
else if (event->xclient.message_type == _glfw.x11.XdndPosition)
|
|
|
{
|
|
|
// The drag operation has moved over the window
|
|
|
- const int absX = (event->xclient.data.l[2] >> 16) & 0xFFFF;
|
|
|
- const int absY = (event->xclient.data.l[2]) & 0xFFFF;
|
|
|
- int x, y;
|
|
|
+ const int xabs = (event->xclient.data.l[2] >> 16) & 0xffff;
|
|
|
+ const int yabs = (event->xclient.data.l[2]) & 0xffff;
|
|
|
+ Window dummy;
|
|
|
+ int xpos, ypos;
|
|
|
+
|
|
|
+ if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
|
|
|
+ return;
|
|
|
+
|
|
|
+ XTranslateCoordinates(_glfw.x11.display,
|
|
|
+ window->x11.handle,
|
|
|
+ _glfw.x11.root,
|
|
|
+ xabs, yabs,
|
|
|
+ &xpos, &ypos,
|
|
|
+ &dummy);
|
|
|
|
|
|
- _glfwPlatformGetWindowPos(window, &x, &y);
|
|
|
- _glfwInputCursorPos(window, absX - x, absY - y);
|
|
|
+ _glfwInputCursorPos(window, xpos, ypos);
|
|
|
|
|
|
- // Reply that we are ready to copy the dragged data
|
|
|
XEvent reply;
|
|
|
memset(&reply, 0, sizeof(reply));
|
|
|
|
|
|
reply.type = ClientMessage;
|
|
|
- reply.xclient.window = event->xclient.data.l[0];
|
|
|
+ reply.xclient.window = _glfw.x11.xdnd.source;
|
|
|
reply.xclient.message_type = _glfw.x11.XdndStatus;
|
|
|
reply.xclient.format = 32;
|
|
|
reply.xclient.data.l[0] = window->x11.handle;
|
|
|
- reply.xclient.data.l[1] = 1; // Always accept the dnd with no rectangle
|
|
|
reply.xclient.data.l[2] = 0; // Specify an empty rectangle
|
|
|
reply.xclient.data.l[3] = 0;
|
|
|
- reply.xclient.data.l[4] = _glfw.x11.XdndActionCopy;
|
|
|
|
|
|
- XSendEvent(_glfw.x11.display, event->xclient.data.l[0],
|
|
|
+ if (_glfw.x11.xdnd.format)
|
|
|
+ {
|
|
|
+ // Reply that we are ready to copy the dragged data
|
|
|
+ reply.xclient.data.l[1] = 1; // Accept with no rectangle
|
|
|
+ if (_glfw.x11.xdnd.version >= 2)
|
|
|
+ reply.xclient.data.l[4] = _glfw.x11.XdndActionCopy;
|
|
|
+ }
|
|
|
+
|
|
|
+ XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source,
|
|
|
False, NoEventMask, &reply);
|
|
|
XFlush(_glfw.x11.display);
|
|
|
}
|
|
@@ -1354,11 +1437,11 @@ static void processEvent(XEvent *event)
|
|
|
|
|
|
case SelectionNotify:
|
|
|
{
|
|
|
- if (event->xselection.property)
|
|
|
+ if (event->xselection.property == _glfw.x11.XdndSelection)
|
|
|
{
|
|
|
// The converted data from the drag operation has arrived
|
|
|
char* data;
|
|
|
- const int result =
|
|
|
+ const unsigned long result =
|
|
|
_glfwGetWindowPropertyX11(event->xselection.requestor,
|
|
|
event->xselection.property,
|
|
|
event->xselection.target,
|
|
@@ -1379,21 +1462,23 @@ static void processEvent(XEvent *event)
|
|
|
if (data)
|
|
|
XFree(data);
|
|
|
|
|
|
- XEvent reply;
|
|
|
- memset(&reply, 0, sizeof(reply));
|
|
|
-
|
|
|
- reply.type = ClientMessage;
|
|
|
- reply.xclient.window = _glfw.x11.xdnd.source;
|
|
|
- reply.xclient.message_type = _glfw.x11.XdndFinished;
|
|
|
- reply.xclient.format = 32;
|
|
|
- reply.xclient.data.l[0] = window->x11.handle;
|
|
|
- reply.xclient.data.l[1] = result;
|
|
|
- reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy;
|
|
|
-
|
|
|
- // Reply that all is well
|
|
|
- XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source,
|
|
|
- False, NoEventMask, &reply);
|
|
|
- XFlush(_glfw.x11.display);
|
|
|
+ if (_glfw.x11.xdnd.version >= 2)
|
|
|
+ {
|
|
|
+ XEvent reply;
|
|
|
+ memset(&reply, 0, sizeof(reply));
|
|
|
+
|
|
|
+ reply.type = ClientMessage;
|
|
|
+ reply.xclient.window = _glfw.x11.xdnd.source;
|
|
|
+ reply.xclient.message_type = _glfw.x11.XdndFinished;
|
|
|
+ reply.xclient.format = 32;
|
|
|
+ reply.xclient.data.l[0] = window->x11.handle;
|
|
|
+ reply.xclient.data.l[1] = result;
|
|
|
+ reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy;
|
|
|
+
|
|
|
+ XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source,
|
|
|
+ False, NoEventMask, &reply);
|
|
|
+ XFlush(_glfw.x11.display);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
return;
|