Skip to content

Commit 9e8ebc1

Browse files
committed
Add detection for dnd protocol
1 parent abcb7d0 commit 9e8ebc1

6 files changed

Lines changed: 43 additions & 4 deletions

File tree

docs/dnd-protocol.rst

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Only the first chunk is guaranteed to have metadata other than the ``m`` key.
2525
Subsequent chunks may optionally omit all
2626
metadata except the ``m`` and ``i`` keys. While a chunked transfer is in
2727
progress it is a protocol error to for the sending side to
28-
send any protocol related escape codes other than chunked ones.
28+
send any protocol related escape codes other than chunked ones or query (``t=q|Q``) ones.
2929
In particular, this means that the receiving side should use the metadata from
3030
the first chunk in a chain of chunks only.
3131

@@ -438,6 +438,31 @@ inform the client of it with::
438438
The error code for too many resources is ``EMFILE`` for IO errors is ``EIO``
439439
and so on.
440440

441+
Detecting support for this protocol
442+
-------------------------------------
443+
444+
Clients can query the terminal emulator for support of this protocol
445+
using::
446+
447+
OSC _dnd_code ; t=q:i=optional ST
448+
OSC _dnd_code ; t=Q:i=optional ST
449+
450+
The former queries support for drag and the latter for drop. The ``i`` key is
451+
optional, if present it will be echoed back in the responses from the terminal.
452+
A terminal supporting this protocol **must** respond with::
453+
454+
OSC _dnd_code ; t=q:i=echoed ; payload ST
455+
OSC _dnd_code ; t=Q:i=echoed ; payload ST
456+
457+
Here, ``payload`` is a colon separated list of ``key=value`` pairs. These
458+
specify support for optional/future parts of this protocol. Currently the
459+
payload is empty, but that might change as the protocol evolves.
460+
461+
The client should send these escape codes followed by a request for the `primary device
462+
attributes <https://vt100.net/docs/vt510-rm/DA1.html>`_. If a response for the
463+
device attributes is received before a response for the queries, then the
464+
terminal does not support this protocol.
465+
441466
Multiplexers
442467
-----------------
443468

@@ -469,6 +494,8 @@ Key Value Default Description
469494
``e`` - a drag offer event occurred
470495
``E`` - a drag offer data error occurred
471496
``k`` - data for uri-list items in drag offer
497+
``q`` - query support for drag
498+
``Q`` - query support for drop
472499

473500
``m`` Chunking indicator ``0`` ``0`` or ``1``
474501

gen/apc_parsers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ def parsers() -> None:
333333
write_header(text, 'kitty/parse-multicell-command.h')
334334

335335
keymap = {
336-
't': ('type', flag('aAmMrRopPeEk')),
336+
't': ('type', flag('aAmMrRopPqQeEk')),
337337
'm': ('more', 'uint'),
338338
'i': ('client_id', 'uint'),
339339
'o': ('operation', 'uint'),

kitty/dnd.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,13 @@ queue_payload_to_child(id_type id, uint32_t client_id, PendingData *pending, con
294294
if (pending->count) check_for_pending_writes();
295295
}
296296

297+
void
298+
dnd_query(Window *w, uint32_t client_id, bool for_drag) {
299+
char buf[64];
300+
ssize_t header_size = snprintf(buf, sizeof(buf), "\x1b]%d;t=%c", DND_CODE, for_drag ? 'q' : 'Q');
301+
send_payload_to_child(w->id, client_id, buf, header_size, NULL, 0, false);
302+
}
303+
297304
static bool
298305
is_same_machine(const char *client_machine_id, size_t sz) {
299306
if (!sz || !client_machine_id) return true;

kitty/dnd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "state.h"
1010

11+
void dnd_query(Window *w, uint32_t client_id, bool for_drag);
1112

1213
void drop_register_window(Window *w, const uint8_t *payload, size_t payload_sz, bool on, uint32_t client_id, bool more);
1314
void drop_register_machine_id(Window *w, const uint8_t *machine_id, size_t sz);

kitty/parse-dnd-command.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,9 @@ static inline void parse_dnd_code(PS *self, uint8_t *parser_buf,
8787
case type: {
8888
g.type = parser_buf[pos++];
8989
if (g.type != 'A' && g.type != 'E' && g.type != 'M' && g.type != 'P' &&
90-
g.type != 'R' && g.type != 'a' && g.type != 'e' && g.type != 'k' &&
91-
g.type != 'm' && g.type != 'o' && g.type != 'p' && g.type != 'r') {
90+
g.type != 'Q' && g.type != 'R' && g.type != 'a' && g.type != 'e' &&
91+
g.type != 'k' && g.type != 'm' && g.type != 'o' && g.type != 'p' &&
92+
g.type != 'q' && g.type != 'r') {
9293
REPORT_ERROR("Malformed DnDCommand control block, unknown flag value "
9394
"for type: 0x%x",
9495
g.type);

kitty/screen.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,6 +1583,9 @@ screen_handle_dnd_command(Screen *self, const DnDCommand *cmd_, const uint8_t *p
15831583
drag_remote_file_data(
15841584
w, cmd->cell_x, cmd->cell_y, cmd->pixel_x, cmd->pixel_y, cmd->more != 0, payload, cmd->payload_sz);
15851585
} break;
1586+
case 'q': case 'Q': {
1587+
dnd_query(w, cmd->client_id, cmd->type == 'q');
1588+
} break;
15861589
}
15871590
}
15881591

0 commit comments

Comments
 (0)