From 9acc16cc44a5d583b0847910a57a259b7aa45958 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 26 Apr 2026 22:34:30 +0530 Subject: [PATCH] Clarify that end of drop escape code discards queued requests --- docs/dnd-protocol.rst | 3 ++- kitty/dnd.c | 4 ++-- kitty_tests/dnd.py | 21 --------------------- 3 files changed, 4 insertions(+), 24 deletions(-) diff --git a/docs/dnd-protocol.rst b/docs/dnd-protocol.rst index 5008fea81..097918f7b 100644 --- a/docs/dnd-protocol.rst +++ b/docs/dnd-protocol.rst @@ -127,7 +127,8 @@ send an escape code of the form:: OSC _dnd_code ; t=r 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. +terminal emulator must then inform the OS that the drop is completed. Any +queued data requests must be discarded by the terminal. Dropping from remote machines ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/kitty/dnd.c b/kitty/dnd.c index c5bee51cd..ec718f3cd 100644 --- a/kitty/dnd.c +++ b/kitty/dnd.c @@ -1145,9 +1145,9 @@ drop_process_queue(Window *w) { void drop_enqueue_request(Window *w, int32_t cell_x, int32_t cell_y, int32_t pixel_y) { - /* Handle finish (x=0, y=0, Y=0): if there are no in-flight requests, finish immediately */ - if (cell_x == 0 && cell_y == 0 && pixel_y == 0 && w->drop.num_data_requests == 0) { + if (cell_x == 0 && cell_y == 0 && pixel_y == 0) { // drop finished drop_finish_and_clear_queue(w); + reset_drop(w); return; } diff --git a/kitty_tests/dnd.py b/kitty_tests/dnd.py index 07743c157..940d8272a 100644 --- a/kitty_tests/dnd.py +++ b/kitty_tests/dnd.py @@ -2242,27 +2242,6 @@ class TestDnDProtocol(BaseTest): finally: os.unlink(fpath) - def test_finish_after_queued_requests(self) -> None: - """A finish (empty t=r) after queued requests processes remaining then finishes.""" - with dnd_test_window() as (screen, cap): - self._register_for_drops(screen, cap, 'text/plain') - dnd_test_set_mouse_pos(cap.window_id, 0, 0, 0, 0) - dnd_test_fake_drop_event(cap.window_id, True, ['text/plain']) - cap.consume() - - # Queue: data request then finish - parse_bytes(screen, client_request_data(1)) - parse_bytes(screen, client_request_data()) # finish - - # Serve the data request - dnd_test_fake_drop_data(cap.window_id, 'text/plain', b'data before finish') - raw = cap.consume() - events = parse_escape_codes_b64(raw) - r_events = [e for e in events if e['type'] == 'r'] - self.assertTrue(r_events, 'no t=r events') - for ev in r_events: - self.ae(ev['meta'].get('x'), '1') - def test_multiple_sync_errors_processed_immediately(self) -> None: """Multiple queued requests that all fail synchronously are processed immediately.""" with dnd_test_window() as (screen, cap):