From b915e3317e0223f62e739145c50d2204ad1f20d5 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 28 Apr 2026 17:17:38 +0530 Subject: [PATCH] Drop protocol: have the final drop operation be reported at the end. This is needed for when there are errors in the client processing the dropped data. --- docs/dnd-protocol.rst | 6 ++++-- kitty/dnd.c | 18 ++++++++++++------ kitty/dnd.h | 2 +- kitty/screen.c | 2 +- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/docs/dnd-protocol.rst b/docs/dnd-protocol.rst index 097918f7b..1e066a21b 100644 --- a/docs/dnd-protocol.rst +++ b/docs/dnd-protocol.rst @@ -124,11 +124,13 @@ any error response means the drop is terminated. Once the client program finishes reading all the dropped data it needs, it must send an escape code of the form:: - OSC _dnd_code ; t=r ST + OSC _dnd_code ; t=r:o=operation ST That is, it must send a request for data with no MIME type specified. The terminal emulator must then inform the OS that the drop is completed. Any -queued data requests must be discarded by the terminal. +queued data requests must be discarded by the terminal. The ``operation`` +is required and must specify the final action the client took with the data. +If unset (aka ``0``) the terminal must assume the drop was canceled. Dropping from remote machines ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/kitty/dnd.c b/kitty/dnd.c index ec718f3cd..f52b37e28 100644 --- a/kitty/dnd.c +++ b/kitty/dnd.c @@ -509,15 +509,20 @@ drop_move_on_child(Window *w, const char** mimes, size_t num_mimes, bool is_drop } } +static GLFWDragOperationType +drop_operation_to_enum(uint32_t op) { + switch(op) { + case 1: return GLFW_DRAG_OPERATION_COPY; + case 2: return GLFW_DRAG_OPERATION_MOVE; + default: return GLFW_DRAG_OPERATION_NONE; + } +} + void drop_set_status(Window *w, int operation, const char *payload, size_t payload_sz, bool more) { if (!w->drop.accept_in_progress) { drop_free_accepted_mimes(w); w->drop.accept_in_progress = true; - switch(operation) { - case 1: w->drop.accepted_operation = GLFW_DRAG_OPERATION_COPY; break; - case 2: w->drop.accepted_operation = GLFW_DRAG_OPERATION_MOVE; break; - default: w->drop.accepted_operation = GLFW_DRAG_OPERATION_NONE; break; - } + w->drop.accepted_operation = drop_operation_to_enum(operation); } if (payload_sz) { if (w->drop.accepted_mimes_sz + payload_sz > MIME_LIST_SIZE_CAP) return; @@ -1144,8 +1149,9 @@ drop_process_queue(Window *w) { } void -drop_enqueue_request(Window *w, int32_t cell_x, int32_t cell_y, int32_t pixel_y) { +drop_enqueue_request(Window *w, int32_t cell_x, int32_t cell_y, int32_t pixel_y, uint32_t operation) { if (cell_x == 0 && cell_y == 0 && pixel_y == 0) { // drop finished + w->drop.accepted_operation = drop_operation_to_enum(operation); drop_finish_and_clear_queue(w); reset_drop(w); return; diff --git a/kitty/dnd.h b/kitty/dnd.h index a1ed4effa..998c06ee4 100644 --- a/kitty/dnd.h +++ b/kitty/dnd.h @@ -16,7 +16,7 @@ void drop_left_child(Window *w); void drop_free_data(Window *w); void drop_send_einval(Window *w); void drop_handle_dir_request(Window *w, uint32_t handle_id, int32_t entry_num); -void drop_enqueue_request(Window *w, int32_t cell_x, int32_t cell_y, int32_t pixel_y); +void drop_enqueue_request(Window *w, int32_t cell_x, int32_t cell_y, int32_t pixel_y, uint32_t operation); void drop_set_status(Window *w, int operation, const char *payload, size_t payload_sz, bool more); size_t drop_update_mimes(Window *w, const char **allowed_mimes, size_t allowed_mimes_count); void drop_dispatch_data(Window *w, const char *mime_type, const char *data, ssize_t sz); diff --git a/kitty/screen.c b/kitty/screen.c index 0c7d16b2a..08f28908f 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1535,7 +1535,7 @@ screen_handle_dnd_command(Screen *self, const DnDCommand *cmd, const uint8_t *pa case 'A': drop_register_window(w, NULL, 0, false, cmd->client_id, cmd->more); break; case 'm': drop_set_status(w, cmd->operation, (const char*)payload, cmd->payload_sz, cmd->more); break; case 'r': { - drop_enqueue_request(w, cmd->cell_x, cmd->cell_y, cmd->pixel_y); + drop_enqueue_request(w, cmd->cell_x, cmd->cell_y, cmd->pixel_y, cmd->operation); } break; case 'o': { switch (cmd->cell_x) {