diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m index 0d9be8de5..10da335ce 100644 --- a/glfw/cocoa_window.m +++ b/glfw/cocoa_window.m @@ -1581,6 +1581,11 @@ reset_drop_copy_mimes(_GLFWDropData *d) { window->ns.drop_data.mimes = mime_array; window->ns.drop_data.mimes_count = mime_count; bool from_self = ([sender draggingSource] != nil); + NSDragOperation src_ops = [sender draggingSourceOperationMask]; + window->drop_operation.source_actions = GLFW_DRAG_OPERATION_NONE; + if (src_ops & NSDragOperationCopy) window->drop_operation.source_actions |= GLFW_DRAG_OPERATION_COPY; + if (src_ops & NSDragOperationMove) window->drop_operation.source_actions |= GLFW_DRAG_OPERATION_MOVE; + if (src_ops & NSDragOperationGeneric) window->drop_operation.source_actions |= GLFW_DRAG_OPERATION_GENERIC; _GLFWDropData *d = &window->ns.drop_data; if (reset_drop_copy_mimes(d)) { size_t accepted_count = _glfwInputDropEvent(window, GLFW_DROP_ENTER, xpos, ypos, d->copy_mimes, d->copy_mimes_count, from_self); @@ -1598,6 +1603,11 @@ reset_drop_copy_mimes(_GLFWDropData *d) { double ypos = contentRect.size.height - pos.y; bool from_self = ([sender draggingSource] != nil); + NSDragOperation src_ops = [sender draggingSourceOperationMask]; + window->drop_operation.source_actions = GLFW_DRAG_OPERATION_NONE; + if (src_ops & NSDragOperationCopy) window->drop_operation.source_actions |= GLFW_DRAG_OPERATION_COPY; + if (src_ops & NSDragOperationMove) window->drop_operation.source_actions |= GLFW_DRAG_OPERATION_MOVE; + if (src_ops & NSDragOperationGeneric) window->drop_operation.source_actions |= GLFW_DRAG_OPERATION_GENERIC; _GLFWDropData *d = &window->ns.drop_data; if (reset_drop_copy_mimes(d)) { size_t accepted_count = _glfwInputDropEvent(window, GLFW_DROP_MOVE, xpos, ypos, d->copy_mimes, d->copy_mimes_count, from_self); diff --git a/glfw/x11_init.c b/glfw/x11_init.c index 44385df0e..0ff634e97 100644 --- a/glfw/x11_init.c +++ b/glfw/x11_init.c @@ -520,6 +520,8 @@ static bool initExtensions(void) _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False); _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False); _glfw.x11.XdndTypeList = XInternAtom(_glfw.x11.display, "XdndTypeList", False); + _glfw.x11.XdndActionList = XInternAtom(_glfw.x11.display, "XdndActionList", False); + _glfw.x11.XdndActionAsk = XInternAtom(_glfw.x11.display, "XdndActionAsk", False); _glfw.x11.XdndLeave = XInternAtom(_glfw.x11.display, "XdndLeave", False); _glfw.x11.XdndProxy = XInternAtom(_glfw.x11.display, "XdndProxy", False); diff --git a/glfw/x11_platform.h b/glfw/x11_platform.h index d44a44f4e..ad2099a8c 100644 --- a/glfw/x11_platform.h +++ b/glfw/x11_platform.h @@ -327,6 +327,8 @@ typedef struct _GLFWlibraryX11 Atom XdndFinished; Atom XdndSelection; Atom XdndTypeList; + Atom XdndActionList; + Atom XdndActionAsk; Atom XdndLeave; Atom XdndProxy; diff --git a/glfw/x11_window.c b/glfw/x11_window.c index ecc94ae2e..d307466eb 100644 --- a/glfw/x11_window.c +++ b/glfw/x11_window.c @@ -1691,6 +1691,24 @@ _glfwPlatformEndDrop(GLFWwindow *w, GLFWDragOperationType op) { } +static void +update_drop_source_actions(_GLFWwindow *window) { + window->drop_operation.source_actions = GLFW_DRAG_OPERATION_NONE; + Atom *actions = NULL; + unsigned long count = _glfwGetWindowPropertyX11(dnd.source, _glfw.x11.XdndActionList, XA_ATOM, (unsigned char**)&actions); + if (actions) { + for (unsigned long i = 0; i < count; i++) { + if (actions[i] == _glfw.x11.XdndActionCopy) window->drop_operation.source_actions |= GLFW_DRAG_OPERATION_COPY; + else if (actions[i] == _glfw.x11.XdndActionMove) window->drop_operation.source_actions |= GLFW_DRAG_OPERATION_MOVE; + else if (actions[i] == _glfw.x11.XdndActionAsk) window->drop_operation.source_actions |= GLFW_DRAG_OPERATION_GENERIC; + } + XFree(actions); + } else { + // XdndActionList not present; default to copy only + window->drop_operation.source_actions = GLFW_DRAG_OPERATION_COPY; + } +} + static void drop_start(_GLFWwindow *window, XEvent *event) { // A drag operation has entered the window @@ -1703,6 +1721,7 @@ drop_start(_GLFWwindow *window, XEvent *event) { dnd.format_priority = 0; update_dnd_mimes(event); dnd.from_self = _glfw.x11.drag.source_window != None && dnd.source == _glfw.x11.drag.source_window; + update_drop_source_actions(window); // Position is not known yet at enter time, will be updated with XdndPosition if (reset_dnd_copy_mimes()) { size_t accepted_count = _glfwInputDropEvent(