mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-08-27 03:42:49 +00:00
Dont detach when user presses esc to cancel drag and there is no drop
This commit is contained in:
parent
0f10380773
commit
eb23c18821
6 changed files with 96 additions and 87 deletions
|
|
@ -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
1
glfw/glfw3.h
vendored
|
|
@ -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
159
glfw/x11_window.c
vendored
|
|
@ -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;
|
||||
}
|
||||
// }}}
|
||||
|
|
|
|||
|
|
@ -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
1
kitty/glfw-wrapper.h
generated
|
|
@ -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. */
|
||||
|
|
|
|||
18
kitty/glfw.c
18
kitty/glfw.c
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue