Implement drop leaving window

This commit is contained in:
Kovid Goyal 2026-03-06 11:18:33 +05:30
parent fba67322d6
commit 111b35b6a7
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
6 changed files with 49 additions and 8 deletions

View file

@ -63,6 +63,12 @@ list of MIME types that are available for dropping. To avoid overhead, the
terminal should only send this list for the first move event and subsequently
only if the list changes.
When the drag leaves the window, the terminal will send the same event but
with ``x, y = -1, -1`` to indicate that the drag has left the window. For such
events the list of MIME types must be empty. Note that the terminal must never
send negative cell co-ordinates for any other reason.
Metadata reference
---------------------------
@ -85,8 +91,8 @@ Key Value Default Description
have it set to the same value.
**Keys for location**
-----------------------------------------------------------
``x`` Positive integer ``0`` Cell x-coordinate origin is 0, 0 at top left of screen
``y`` Positive integer ``0`` Cell y-coordinate origin is 0, 0 at top left of screen
``x`` Integer ``0`` Cell x-coordinate origin is 0, 0 at top left of screen
``y`` Integer ``0`` Cell y-coordinate origin is 0, 0 at top left of screen
``X`` Integer ``0`` Pixel x-coordinate origin is 0, 0 at top left of screen
``Y`` Integer ``0`` Pixel y-coordinate origin is 0, 0 at top left of screen
======= ==================== ========= =================

View file

@ -44,11 +44,18 @@ string_arrays_cmp(const char **a, size_t an, const char **b, size_t bn) {
}
static size_t
send_payload_to_child(id_type id, const char *header, size_t header_sz, const char *data, size_t data_sz) {
send_payload_to_child(id_type id, const char *header, size_t header_sz, const char *data, const size_t data_sz) {
size_t offset = 0;
char buf[4096 + 1024];
memcpy(buf, header, header_sz);
buf[header_sz++] = ':'; buf[header_sz++] = 'm'; buf[header_sz++] = '=';
if (!data_sz) {
buf[header_sz++] = 0x1b; buf[header_sz++] = '\\';
bool found, too_much_data;
schedule_write_to_child_if_possible(id, buf, header_sz, &found, &too_much_data);
if (too_much_data) return 0;
return 1;
}
while (offset < data_sz) {
size_t chunk = data_sz - offset;
size_t p = header_sz;
@ -79,7 +86,8 @@ flush_pending(id_type id, PendingData *pending) {
}
break;
} else {
free(e->buf);
if (!e->data_sz && !written) break;
free(e->buf); zero_at_ptr(e);
remove_i_from_array(pending->items, 0, pending->count);
}
}
@ -90,7 +98,7 @@ static void
queue_payload_to_child(id_type id, PendingData *pending, const char *header, size_t header_sz, const char *data, size_t data_sz) {
size_t offset = 0;
if (flush_pending(id, pending)) offset = send_payload_to_child(id, header, header_sz, data, data_sz);
if (offset < data_sz) {
if (offset < data_sz || (!offset && !data_sz)) {
ensure_space_for(pending, items, PendingEntry, pending->count + 1, capacity, 32, true);
char *buf = malloc(header_sz + data_sz - offset);
if (!buf) fatal("Out of memory");
@ -145,3 +153,14 @@ drop_move_on_child(Window *w, const char** mimes, size_t num_mimes) {
schedule_write_to_child_if_possible(w->id, buf, header_size, &found, &too_much_data);
}
}
void
drop_left_child(Window *w) {
w->drop.hovered = false;
drop_free_offered_mimes(w);
if (w->drop.allowed) {
char buf[128];
int header_size = snprintf(buf, sizeof(buf), "\x1b]%d;i=%u:t=m:x=-1:y=-1", DND_CODE, w->drop.client_id);
queue_payload_to_child(w->id, &w->drop.pending, buf, header_size, NULL, 0);
}
}

View file

@ -9,4 +9,5 @@
#include "state.h"
void drop_move_on_child(Window *w, const char **mimes, size_t num_mimes);
void drop_left_child(Window *w);
void drop_free_data(Window *w);

View file

@ -796,13 +796,17 @@ on_drop(GLFWwindow *window, GLFWDropEvent *ev) {
if (!set_callback_window(window)) return;
OSWindow *os_window = global_state.callback_os_window;
Window *w = NULL;
bool is_kitty_ui_drag = false;
for (size_t i = 0; i < ev->num_mimes; i++) {
if (is_droppable_mime(ev->mimes[i]) >= TAB_DRAG_MIME_NUMBER) { is_kitty_ui_drag = true; break;}
}
switch (ev->type) {
case GLFW_DROP_ENTER:
case GLFW_DROP_MOVE:
os_window->last_drag_event.x = (int)(ev->xpos * os_window->viewport_x_ratio);
os_window->last_drag_event.y = (int)(ev->ypos * os_window->viewport_y_ratio);
on_mouse_position_update(ev->xpos, ev->ypos);
if (global_state.mouse_hover_in_window && (w = window_for_window_id(global_state.mouse_hover_in_window)) && w->drop.allowed) {
if (!is_kitty_ui_drag && global_state.mouse_hover_in_window && (w = window_for_window_id(global_state.mouse_hover_in_window)) && w->drop.allowed) {
drop_move_on_child(w, ev->mimes, ev->num_mimes);
return;
}
@ -811,9 +815,18 @@ on_drop(GLFWwindow *window, GLFWDropEvent *ev) {
ev->from_self ? Py_True : Py_False, Py_False);
/* fallthrough */
case GLFW_DROP_STATUS_UPDATE:
update_allowed_mimes_for_drop(ev);
if (is_kitty_ui_drag) update_allowed_mimes_for_drop(ev);
else {
}
break;
case GLFW_DROP_LEAVE:
for (size_t tc = 0; tc < os_window->num_tabs; tc++) {
Tab *t = os_window->tabs + tc;
for (size_t i = 0; i < t->num_windows; i++) {
Window *w = t->windows + i;
if (w->drop.hovered) drop_left_child(w);
}
}
call_boss(on_drop_move, "KiiOO",
os_window->id, os_window->last_drag_event.x, os_window->last_drag_event.y,
ev->from_self ? Py_True : Py_False, Py_True);

View file

@ -8,6 +8,7 @@
#include "state.h"
#include "screen.h"
#include "charsets.h"
#include "dnd.h"
#include <limits.h>
#include <math.h>
#include "glfw-wrapper.h"
@ -179,6 +180,7 @@ set_currently_hovered_window(id_type window_id, int modifiers) {
if (left_window) {
if (left_window->scrollbar.is_hovering) update_scrollbar_hover_state(left_window, false);
if (left_window->render_data.screen) screen_mark_url(left_window->render_data.screen, 0, 0, 0, 0);
if (left_window->drop.hovered) drop_left_child(left_window);
int sz = encode_mouse_event(left_window, 0, LEAVE, modifiers);
if (sz > 0) {
mouse_event_buf[sz] = 0;

View file

@ -180,7 +180,7 @@ typedef struct ClickQueue {
} ClickQueue;
typedef struct MousePosition {
unsigned int cell_x, cell_y;
unsigned cell_x, cell_y;
double global_x, global_y;
bool in_left_half_of_cell;
} MousePosition;