Dont detach when user presses esc to cancel drag and there is no drop

This commit is contained in:
Kovid Goyal 2026-02-22 07:42:42 +05:30
parent 0f10380773
commit eb23c18821
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
6 changed files with 96 additions and 87 deletions

View file

@ -3960,7 +3960,7 @@ void _glfwCocoaPostEmptyEvent(void) {
case NSDragOperationDelete: ev.type = GLFW_DRAG_CANCELLED; break;
case NSDragOperationNone: {
NSEvent *currentEvent = [NSApp currentEvent];
if (currentEvent.type == NSEventTypeKeyDown && currentEvent.keyCode == 53) {
if (currentEvent && currentEvent.type == NSEventTypeKeyDown && currentEvent.keyCode == 53) {
ev.type = GLFW_DRAG_CANCELLED;
} else ev.type = GLFW_DRAG_DROPPED;
} break;

1
glfw/glfw3.h vendored
View file

@ -1391,6 +1391,7 @@ typedef enum { GLFW_DROP_ENTER, GLFW_DROP_MOVE, GLFW_DROP_LEAVE, GLFW_DROP_DROP,
* @ingroup input
*/
typedef enum {
GLFW_DRAG_OPERATION_NONE = 0, // no operation, drop was not accepted
/*! Move the dragged data to the destination. */
GLFW_DRAG_OPERATION_MOVE = 1,
/*! Copy the dragged data to the destination. */

159
glfw/x11_window.c vendored
View file

@ -95,7 +95,7 @@ x11_cancel_momentum_scroll_timer(void) {
static unsigned _glfwDispatchX11Events(void);
// Forward declarations for drag source helper functions
static void send_drag_data(const char *mime_type, const char *data, size_t data_sz,
static void send_drag_data(const char *mime_type, const char *data, size_t data_sz,
Window requestor, Atom property, Atom target);
static bool add_pending_request(const char *mime_type, Window requestor, Atom property, Atom target);
static void handle_drag_motion(int root_x, int root_y, Time timestamp);
@ -1159,15 +1159,15 @@ handleSelectionRequest(XEvent* event) {
break;
}
}
if (data && data_sz > 0) {
// We have preset data, send it immediately
send_drag_data(mime_type, data, data_sz, request->requestor,
send_drag_data(mime_type, data, data_sz, request->requestor,
request->property, request->target);
reply.xselection.property = request->property;
} else {
// Add to pending requests for on-demand data
if (add_pending_request(mime_type, request->requestor,
if (add_pending_request(mime_type, request->requestor,
request->property, request->target)) {
// Request data from application
_GLFWwindow *window = _glfwWindowForId(_glfw.drag.window_id);
@ -1180,11 +1180,11 @@ handleSelectionRequest(XEvent* event) {
.err_num = 0
};
_glfwInputDragSourceRequest(window, &ev);
if (ev.data && ev.data_sz > 0) {
// Data provided synchronously
send_drag_data(mime_type, ev.data, ev.data_sz,
request->requestor, request->property,
request->requestor, request->property,
request->target);
reply.xselection.property = request->property;
} else {
@ -1510,6 +1510,7 @@ end_drop(_GLFWwindow *window, GLFWDragOperationType op) {
case GLFW_DRAG_OPERATION_COPY: reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy; break;
case GLFW_DRAG_OPERATION_MOVE: reply.xclient.data.l[2] = _glfw.x11.XdndActionMove; break;
case GLFW_DRAG_OPERATION_GENERIC: reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy; break;
case GLFW_DRAG_OPERATION_NONE: reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy; break;
}
}
XSendEvent(_glfw.x11.display, dnd.source, False, NoEventMask, &reply);
@ -2156,13 +2157,13 @@ static void processEvent(XEvent *event)
if (_glfw.x11.drag.active) {
int root_x, root_y;
Window child;
XTranslateCoordinates(_glfw.x11.display,
XTranslateCoordinates(_glfw.x11.display,
event->xmotion.window, _glfw.x11.root,
event->xmotion.x, event->xmotion.y,
&root_x, &root_y, &child);
handle_drag_motion(root_x, root_y, event->xmotion.time);
}
x11_cancel_momentum_scroll_timer();
glfw_cancel_momentum_scroll();
handle_mouse_move_event(window, event->xmotion.x, event->xmotion.y);
@ -3896,7 +3897,7 @@ window_supports_xdnd(Window win, int *version_out) {
unsigned long count, bytes_after;
unsigned char *data = NULL;
bool supported = false;
if (XGetWindowProperty(_glfw.x11.display, win, _glfw.x11.XdndAware,
0, 1, False, XA_ATOM,
&actual_type, &actual_format,
@ -3921,7 +3922,7 @@ find_xdnd_aware_target(Window root, int root_x, int root_y, int *version_out) {
Window parent = root;
Window *children = NULL;
unsigned int nchildren = 0;
// Walk down the window tree to find the deepest window at these coordinates
while (child != None) {
target = child;
@ -3932,7 +3933,7 @@ find_xdnd_aware_target(Window root, int root_x, int root_y, int *version_out) {
}
if (child == None) break;
}
// Walk up the tree to find an XdndAware window
while (target != None && target != root) {
if (window_supports_xdnd(target, version_out)) {
@ -3941,7 +3942,7 @@ find_xdnd_aware_target(Window root, int root_x, int root_y, int *version_out) {
int actual_format;
unsigned long count, bytes_after;
unsigned char *data = NULL;
if (XGetWindowProperty(_glfw.x11.display, target, _glfw.x11.XdndProxy,
0, 1, False, XA_WINDOW,
&actual_type, &actual_format,
@ -3959,7 +3960,7 @@ find_xdnd_aware_target(Window root, int root_x, int root_y, int *version_out) {
}
return target;
}
// Move to parent
Window new_parent;
if (XQueryTree(_glfw.x11.display, target, &parent, &new_parent, &children, &nchildren)) {
@ -3969,7 +3970,7 @@ find_xdnd_aware_target(Window root, int root_x, int root_y, int *version_out) {
break;
}
}
return None;
}
@ -3978,14 +3979,14 @@ static void
send_xdnd_enter(Window target, int version) {
XEvent event;
memset(&event, 0, sizeof(event));
event.xclient.type = ClientMessage;
event.xclient.window = target;
event.xclient.message_type = _glfw.x11.XdndEnter;
event.xclient.format = 32;
event.xclient.data.l[0] = _glfw.x11.drag.source_window;
event.xclient.data.l[1] = (version << 24);
// If we have more than 3 types, set the type list flag
if (_glfw.x11.drag.type_count > 3) {
event.xclient.data.l[1] |= 1; // More than 3 types, use property
@ -4001,7 +4002,7 @@ send_xdnd_enter(Window target, int version) {
event.xclient.data.l[2 + i] = _glfw.x11.drag.type_atoms[i];
}
}
XSendEvent(_glfw.x11.display, target, False, NoEventMask, &event);
XFlush(_glfw.x11.display);
}
@ -4011,7 +4012,7 @@ static void
send_xdnd_position(Window target, int root_x, int root_y, Time timestamp) {
XEvent event;
memset(&event, 0, sizeof(event));
event.xclient.type = ClientMessage;
event.xclient.window = target;
event.xclient.message_type = _glfw.x11.XdndPosition;
@ -4021,7 +4022,7 @@ send_xdnd_position(Window target, int root_x, int root_y, Time timestamp) {
event.xclient.data.l[2] = (root_x << 16) | root_y;
event.xclient.data.l[3] = timestamp;
event.xclient.data.l[4] = _glfw.x11.drag.action_atom;
XSendEvent(_glfw.x11.display, target, False, NoEventMask, &event);
XFlush(_glfw.x11.display);
_glfw.x11.drag.waiting_for_status = true;
@ -4032,13 +4033,13 @@ static void
send_xdnd_leave(Window target) {
XEvent event;
memset(&event, 0, sizeof(event));
event.xclient.type = ClientMessage;
event.xclient.window = target;
event.xclient.message_type = _glfw.x11.XdndLeave;
event.xclient.format = 32;
event.xclient.data.l[0] = _glfw.x11.drag.source_window;
XSendEvent(_glfw.x11.display, target, False, NoEventMask, &event);
XFlush(_glfw.x11.display);
}
@ -4048,7 +4049,7 @@ static void
send_xdnd_drop(Window target, Time timestamp) {
XEvent event;
memset(&event, 0, sizeof(event));
event.xclient.type = ClientMessage;
event.xclient.window = target;
event.xclient.message_type = _glfw.x11.XdndDrop;
@ -4056,7 +4057,7 @@ send_xdnd_drop(Window target, Time timestamp) {
event.xclient.data.l[0] = _glfw.x11.drag.source_window;
event.xclient.data.l[1] = 0; // Reserved
event.xclient.data.l[2] = timestamp;
XSendEvent(_glfw.x11.display, target, False, NoEventMask, &event);
XFlush(_glfw.x11.display);
}
@ -4072,7 +4073,7 @@ create_drag_thumbnail(const GLFWimage* thumbnail, int x, int y) {
XSetWindowAttributes attrs;
attrs.override_redirect = True;
attrs.background_pixel = 0;
_glfw.x11.drag.thumbnail_window = XCreateWindow(
_glfw.x11.display,
_glfw.x11.root,
@ -4085,7 +4086,7 @@ create_drag_thumbnail(const GLFWimage* thumbnail, int x, int y) {
CWOverrideRedirect | CWBackPixel,
&attrs
);
if (!_glfw.x11.drag.thumbnail_window) {
return false;
}
@ -4098,7 +4099,7 @@ create_drag_thumbnail(const GLFWimage* thumbnail, int x, int y) {
thumbnail->height,
DefaultDepth(_glfw.x11.display, _glfw.x11.screen)
);
if (!_glfw.x11.drag.thumbnail_pixmap) {
XDestroyWindow(_glfw.x11.display, _glfw.x11.drag.thumbnail_window);
_glfw.x11.drag.thumbnail_window = None;
@ -4129,7 +4130,7 @@ create_drag_thumbnail(const GLFWimage* thumbnail, int x, int y) {
32, // bitmap_pad
0 // bytes_per_line (auto-calculate)
);
if (!ximage) {
XFreeGC(_glfw.x11.display, _glfw.x11.drag.thumbnail_gc);
XFreePixmap(_glfw.x11.display, _glfw.x11.drag.thumbnail_pixmap);
@ -4153,7 +4154,7 @@ create_drag_thumbnail(const GLFWimage* thumbnail, int x, int y) {
_glfw.x11.drag.thumbnail_gc = None;
return false;
}
ximage->data = (char*)ximage_data;
// Convert RGBA to the format expected by XImage
@ -4164,38 +4165,38 @@ create_drag_thumbnail(const GLFWimage* thumbnail, int x, int y) {
unsigned char g = src[i * 4 + 1];
unsigned char b = src[i * 4 + 2];
unsigned char a = src[i * 4 + 3];
// Premultiply alpha
if (a < 255) {
r = (r * a) / 255;
g = (g * a) / 255;
b = (b * a) / 255;
}
// Convert to X11 pixel format (typically BGRA on little-endian)
if (ximage->byte_order == LSBFirst) {
pixel = (a << 24) | (r << 16) | (g << 8) | b;
} else {
pixel = (b << 24) | (g << 16) | (r << 8) | a;
}
XPutPixel(ximage, i % thumbnail->width, i / thumbnail->width, pixel);
}
// Draw the image to the pixmap
XPutImage(_glfw.x11.display, _glfw.x11.drag.thumbnail_pixmap, _glfw.x11.drag.thumbnail_gc,
ximage, 0, 0, 0, 0, thumbnail->width, thumbnail->height);
// Clean up XImage (including its data)
XDestroyImage(ximage); // This also frees ximage_data
// Set the pixmap as the window's background
XSetWindowBackgroundPixmap(_glfw.x11.display, _glfw.x11.drag.thumbnail_window, _glfw.x11.drag.thumbnail_pixmap);
// Map the window to make it visible
XMapRaised(_glfw.x11.display, _glfw.x11.drag.thumbnail_window);
XFlush(_glfw.x11.display);
return true;
}
@ -4203,32 +4204,32 @@ create_drag_thumbnail(const GLFWimage* thumbnail, int x, int y) {
static void
handle_drag_motion(int root_x, int root_y, Time timestamp) {
if (!_glfw.x11.drag.active) return;
// Move thumbnail window to follow cursor
if (_glfw.x11.drag.thumbnail_window != None) {
XMoveWindow(_glfw.x11.display, _glfw.x11.drag.thumbnail_window, root_x + 10, root_y + 10);
}
int version = _GLFW_XDND_VERSION;
Window new_target = find_xdnd_aware_target(_glfw.x11.root, root_x, root_y, &version);
if (new_target != _glfw.x11.drag.current_target) {
// Send leave to old target
if (_glfw.x11.drag.current_target != None) {
send_xdnd_leave(_glfw.x11.drag.current_target);
}
_glfw.x11.drag.current_target = new_target;
_glfw.x11.drag.waiting_for_status = false;
_glfw.x11.drag.accepted = false;
// Send enter to new target
if (new_target != None) {
_glfw.x11.drag.xdnd_version = version;
send_xdnd_enter(new_target, version);
}
}
// Send position to current target
if (_glfw.x11.drag.current_target != None && !_glfw.x11.drag.waiting_for_status) {
send_xdnd_position(_glfw.x11.drag.current_target, root_x, root_y, timestamp);
@ -4239,7 +4240,7 @@ handle_drag_motion(int root_x, int root_y, Time timestamp) {
static void
handle_drag_button_release(Time timestamp) {
if (!_glfw.x11.drag.active) return;
if (_glfw.x11.drag.current_target != None && _glfw.x11.drag.accepted) {
send_xdnd_drop(_glfw.x11.drag.current_target, timestamp);
} else {
@ -4258,10 +4259,10 @@ static void
handle_xdnd_status(const XClientMessageEvent *event) {
if (!_glfw.x11.drag.active) return;
if (event->data.l[0] != (long)_glfw.x11.drag.current_target) return;
_glfw.x11.drag.waiting_for_status = false;
_glfw.x11.drag.accepted = (event->data.l[1] & 1) != 0;
if (_glfw.x11.drag.accepted && event->data.l[4] != None) {
_glfw.x11.drag.accepted_action = event->data.l[4];
}
@ -4272,12 +4273,12 @@ static void
handle_xdnd_finished(const XClientMessageEvent *event) {
if (!_glfw.x11.drag.active) return;
if (event->data.l[0] != (long)_glfw.x11.drag.current_target) return;
_GLFWwindow *window = _glfwWindowForId(_glfw.drag.window_id);
if (window) {
bool accepted = (event->data.l[1] & 1) != 0;
GLFWDragOperationType action = 0;
if (accepted && event->data.l[2] != None) {
Atom action_atom = event->data.l[2];
if (action_atom == _glfw.x11.XdndActionCopy) {
@ -4288,11 +4289,11 @@ handle_xdnd_finished(const XClientMessageEvent *event) {
action = GLFW_DRAG_OPERATION_GENERIC;
}
}
GLFWDragEvent ev = {.type = GLFW_DRAG_FINSHED, .action = action};
_glfwInputDragSourceRequest(window, &ev);
}
_glfwFreeDragSourceData();
}
@ -4301,26 +4302,26 @@ static bool
add_pending_request(const char *mime_type, Window requestor, Atom property, Atom target) {
if (_glfw.x11.drag.pending_count >= _glfw.x11.drag.pending_capacity) {
size_t new_capacity = _glfw.x11.drag.pending_capacity == 0 ? 8 : _glfw.x11.drag.pending_capacity * 2;
void *new_ptr = realloc(_glfw.x11.drag.pending_requests,
void *new_ptr = realloc(_glfw.x11.drag.pending_requests,
new_capacity * sizeof(_glfw.x11.drag.pending_requests[0]));
if (!new_ptr) return false;
_glfw.x11.drag.pending_requests = new_ptr;
_glfw.x11.drag.pending_capacity = new_capacity;
}
size_t idx = _glfw.x11.drag.pending_count++;
_glfw.x11.drag.pending_requests[idx].mime_type = _glfw_strdup(mime_type);
_glfw.x11.drag.pending_requests[idx].requestor = requestor;
_glfw.x11.drag.pending_requests[idx].property = property;
_glfw.x11.drag.pending_requests[idx].target = target;
_glfw.x11.drag.pending_requests[idx].inflight = true;
return _glfw.x11.drag.pending_requests[idx].mime_type != NULL;
}
// Send drag data via XChangeProperty
static void
send_drag_data(const char *mime_type, const char *data, size_t data_sz,
send_drag_data(const char *mime_type, const char *data, size_t data_sz,
Window requestor, Atom property, Atom target) {
(void)mime_type; // Parameter kept for consistency with other platforms
if (data && data_sz > 0) {
@ -4341,20 +4342,20 @@ _glfwPlatformStartDrag(_GLFWwindow* window, const GLFWimage* thumbnail) {
if (_glfw.x11.drag.active) {
_glfwFreeDragSourceData();
}
// Convert MIME types to atoms
_glfw.x11.drag.type_count = _glfw.drag.item_count;
_glfw.x11.drag.type_atoms = calloc(_glfw.drag.item_count, sizeof(Atom));
if (!_glfw.x11.drag.type_atoms) {
return ENOMEM;
}
for (size_t i = 0; i < _glfw.drag.item_count; i++) {
_glfw.x11.drag.type_atoms[i] = XInternAtom(_glfw.x11.display,
_glfw.drag.items[i].mime_type,
_glfw.x11.drag.type_atoms[i] = XInternAtom(_glfw.x11.display,
_glfw.drag.items[i].mime_type,
False);
}
// Determine action atom based on operations
if (_glfw.drag.operations & GLFW_DRAG_OPERATION_COPY) {
_glfw.x11.drag.action_atom = _glfw.x11.XdndActionCopy;
@ -4363,18 +4364,18 @@ _glfwPlatformStartDrag(_GLFWwindow* window, const GLFWimage* thumbnail) {
} else {
_glfw.x11.drag.action_atom = _glfw.x11.XdndActionCopy;
}
_glfw.x11.drag.source_window = window->x11.handle;
_glfw.x11.drag.active = true;
_glfw.x11.drag.current_target = None;
_glfw.x11.drag.waiting_for_status = false;
_glfw.x11.drag.accepted = false;
// Initialize thumbnail fields
_glfw.x11.drag.thumbnail_window = None;
_glfw.x11.drag.thumbnail_pixmap = None;
_glfw.x11.drag.thumbnail_gc = None;
// Get current cursor position for thumbnail placement
Window root_return, child_return;
int root_x, root_y, win_x, win_y;
@ -4382,7 +4383,7 @@ _glfwPlatformStartDrag(_GLFWwindow* window, const GLFWimage* thumbnail) {
XQueryPointer(_glfw.x11.display, _glfw.x11.root,
&root_return, &child_return,
&root_x, &root_y, &win_x, &win_y, &mask_return);
// Create thumbnail window if thumbnail is provided
if (!create_drag_thumbnail(thumbnail, root_x + 10, root_y + 10)) {
// Thumbnail creation failed, but continue with drag operation
@ -4390,13 +4391,13 @@ _glfwPlatformStartDrag(_GLFWwindow* window, const GLFWimage* thumbnail) {
_glfw.x11.drag.thumbnail_pixmap = None;
_glfw.x11.drag.thumbnail_gc = None;
}
// Grab the pointer to track drag motion
int result = XGrabPointer(_glfw.x11.display, window->x11.handle, False,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
GrabModeAsync, GrabModeAsync,
None, None, CurrentTime);
if (result != GrabSuccess) {
free(_glfw.x11.drag.type_atoms);
_glfw.x11.drag.type_atoms = NULL;
@ -4417,11 +4418,11 @@ _glfwPlatformStartDrag(_GLFWwindow* window, const GLFWimage* thumbnail) {
}
return EIO;
}
// Set ourselves as the XdndSelection owner
XSetSelectionOwner(_glfw.x11.display, _glfw.x11.XdndSelection,
XSetSelectionOwner(_glfw.x11.display, _glfw.x11.XdndSelection,
window->x11.handle, CurrentTime);
return 0;
}
@ -4432,14 +4433,14 @@ _glfwPlatformFreeDragSourceData(void) {
if (_glfw.x11.drag.current_target != None) {
send_xdnd_leave(_glfw.x11.drag.current_target);
}
// Ungrab the pointer
XUngrabPointer(_glfw.x11.display, CurrentTime);
_glfw.x11.drag.active = false;
_glfw.x11.drag.current_target = None;
}
// Clean up thumbnail resources
if (_glfw.x11.drag.thumbnail_gc != None) {
XFreeGC(_glfw.x11.display, _glfw.x11.drag.thumbnail_gc);
@ -4453,14 +4454,14 @@ _glfwPlatformFreeDragSourceData(void) {
XDestroyWindow(_glfw.x11.display, _glfw.x11.drag.thumbnail_window);
_glfw.x11.drag.thumbnail_window = None;
}
// Free type atoms
if (_glfw.x11.drag.type_atoms) {
free(_glfw.x11.drag.type_atoms);
_glfw.x11.drag.type_atoms = NULL;
}
_glfw.x11.drag.type_count = 0;
// Free pending requests
if (_glfw.x11.drag.pending_requests) {
for (size_t i = 0; i < _glfw.x11.drag.pending_count; i++) {
@ -4479,11 +4480,11 @@ _glfwPlatformDragDataReady(const char *mime_type) {
for (size_t i = 0; i < _glfw.x11.drag.pending_count; i++) {
if (_glfw.x11.drag.pending_requests[i].inflight &&
strcmp(_glfw.x11.drag.pending_requests[i].mime_type, mime_type) == 0) {
// Get the drag event with data from the application
_GLFWwindow *window = _glfwWindowForId(_glfw.drag.window_id);
if (!window) return ENODEV;
GLFWDragEvent ev = {
.type = GLFW_DRAG_DATA_REQUEST,
.mime_type = mime_type,
@ -4491,15 +4492,15 @@ _glfwPlatformDragDataReady(const char *mime_type) {
.data_sz = 0,
.err_num = 0
};
_glfwInputDragSourceRequest(window, &ev);
// Send the data
send_drag_data(mime_type, ev.data, ev.data_sz,
_glfw.x11.drag.pending_requests[i].requestor,
_glfw.x11.drag.pending_requests[i].property,
_glfw.x11.drag.pending_requests[i].target);
// Send SelectionNotify
XEvent reply;
memset(&reply, 0, sizeof(reply));
@ -4510,16 +4511,16 @@ _glfwPlatformDragDataReady(const char *mime_type) {
reply.xselection.target = _glfw.x11.drag.pending_requests[i].target;
reply.xselection.property = _glfw.x11.drag.pending_requests[i].property;
reply.xselection.time = CurrentTime;
XSendEvent(_glfw.x11.display,
XSendEvent(_glfw.x11.display,
_glfw.x11.drag.pending_requests[i].requestor,
False, 0, &reply);
_glfw.x11.drag.pending_requests[i].inflight = false;
break;
}
}
return 0;
}
// }}}

View file

@ -1940,7 +1940,7 @@ class Boss:
set_tab_being_dragged()
for tm in self.all_tab_managers:
tm.on_tab_drop_move()
if not was_dropped: # detach tab into new OS Window
if was_dropped: # detach tab into new OS Window
tab_id = int(tidb.decode())
if (tab := self.tab_for_id(tab_id)):
self._move_tab_to(tab)

1
kitty/glfw-wrapper.h generated
View file

@ -1119,6 +1119,7 @@ typedef enum { GLFW_DROP_ENTER, GLFW_DROP_MOVE, GLFW_DROP_LEAVE, GLFW_DROP_DROP,
* @ingroup input
*/
typedef enum {
GLFW_DRAG_OPERATION_NONE = 0, // no operation, drop was not accepted
/*! Move the dragged data to the destination. */
GLFW_DRAG_OPERATION_MOVE = 1,
/*! Copy the dragged data to the destination. */

View file

@ -792,6 +792,13 @@ free_drag_source(void) {
static void
drag_source_callback(GLFWwindow *window UNUSED, GLFWDragEvent *ev) {
#define finish \
call_boss(on_drag_source_finished, "OOsiO", \
ds.was_dropped ? Py_True : Py_False, ds.was_canceled ? Py_True: Py_False, \
ds.accepted_mime_type ? ds.accepted_mime_type : "", \
ds.action, ds.drag_data ? ds.drag_data : Py_None); \
free_drag_source();
switch (ev->type) {
case GLFW_DRAG_DATA_REQUEST: // we currently pre-provide all data so this should never happen
if (ev->data_sz) {
@ -804,21 +811,20 @@ drag_source_callback(GLFWwindow *window UNUSED, GLFWDragEvent *ev) {
free(ds.accepted_mime_type);
ds.accepted_mime_type = ev->mime_type ? strdup(ev->mime_type) : NULL;
break;
case GLFW_DRAG_ACTION_CHANGED: ds.action = ev->action; break;
case GLFW_DRAG_ACTION_CHANGED:
ds.action = ev->action; break;
case GLFW_DRAG_DROPPED:
ds.was_dropped = true;
if (ev->action == GLFW_DRAG_OPERATION_NONE) { finish }
break;
case GLFW_DRAG_CANCELLED:
ds.was_canceled = true;
/* fallthrough */
case GLFW_DRAG_FINSHED:
call_boss(on_drag_source_finished, "OOsiO",
ds.was_dropped ? Py_True : Py_False, ds.was_canceled ? Py_True: Py_False,
ds.accepted_mime_type ? ds.accepted_mime_type : "",
ds.action, ds.drag_data ? ds.drag_data : Py_None);
free_drag_source();
finish
break;
}
#undef finish
}
#undef ds