mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-27 10:41:58 +02:00
Refactor the drop protocol
Get rid of request_id. Instead use the x, y, and Y fields to disambiguate requests. Specify error handling a little more robustly. Implementation needed.
This commit is contained in:
@@ -104,23 +104,22 @@ it is interested in.
|
|||||||
|
|
||||||
Requesting data is done by sending an escape code of the form::
|
Requesting data is done by sending an escape code of the form::
|
||||||
|
|
||||||
OSC _dnd_code ; t=r:r=request_id ; MIME type ST
|
OSC _dnd_code ; t=r:x=idx ST
|
||||||
|
|
||||||
|
Here ``idx`` is a 1-based index into the list of MIME types sent previously.
|
||||||
This will request data for the specified MIME type. The terminal must respond
|
This will request data for the specified MIME type. The terminal must respond
|
||||||
with a series of escape codes of the form::
|
with a series of escape codes of the form::
|
||||||
|
|
||||||
OSC _dnd_code ; t=r:r=request_id ; base64 encoded data ST
|
OSC _dnd_code ; t=r:x=idx; base64 encoded data possibly chunked ST
|
||||||
|
|
||||||
End of data is indicated by an empty payload. If some error occurs while
|
End of data is indicated by an empty payload and ``m=0``. If some error occurs while
|
||||||
getting the data, the terminal must send an escape code of the form::
|
getting the data, the terminal must send an escape code of the form::
|
||||||
|
|
||||||
OSC _dnd_code ; t=R:r=request_id ; POSIX error name ST
|
OSC _dnd_code ; t=R:x=idx ; POSIX error name ST
|
||||||
|
|
||||||
Here POSIX error name is a POSIX symbolic error name such as ``ENOENT`` or
|
Here ``POSIX error name`` is a POSIX symbolic error name such as ``ENOENT`` or
|
||||||
``EIO`` or the value ``EUNKNOWN`` for an unknown error. Note that if a client
|
``EIO`` or the value ``EUNKNOWN`` for an unknown error. Unless otherwise noted,
|
||||||
sends a request for another MIME type before the data for the previous MIME type
|
any error response means the drop is terminated.
|
||||||
is completed, the terminal *must* switch over to sending data for the new MIME
|
|
||||||
type.
|
|
||||||
|
|
||||||
Once the client program finishes reading all the dropped data it needs, it must
|
Once the client program finishes reading all the dropped data it needs, it must
|
||||||
send an escape code of the form::
|
send an escape code of the form::
|
||||||
@@ -138,51 +137,78 @@ clients can first request the :rfc:`text/uri-list <2483>` MIME
|
|||||||
type to get a list of dropped URIs. For every URI in the list, they can
|
type to get a list of dropped URIs. For every URI in the list, they can
|
||||||
send the terminal emulator a data request of the form::
|
send the terminal emulator a data request of the form::
|
||||||
|
|
||||||
OSC _dnd_code ; t=s:r=request_id ; text/uri-list:idx ST
|
OSC _dnd_code ; t=r:x=idx:y=subidx ST
|
||||||
|
|
||||||
Here ``idx`` is the zero based index into the array of MIME types in
|
Here ``idx`` is the one based index of the ``text/uri-list`` MIME type. And
|
||||||
|
``subidx`` is the one based index into the array of MIME types in
|
||||||
the ``text/uri-list`` entry. The terminal will then read the file and
|
the ``text/uri-list`` entry. The terminal will then read the file and
|
||||||
transmit the data as for a normal MIME data request.
|
transmit the data as for a normal MIME data request, except it will have
|
||||||
|
``y=subidx`` as well in its response, for example::
|
||||||
|
|
||||||
Terminals must reply with ``t=R:r=request_id ; ENOENT`` if the index is out of bounds.
|
OSC _dnd_code ; t=r:x=idx:y=subidx ; base64 encoded data possibly chunked ST
|
||||||
|
|
||||||
|
Similarly, error responses are as above, except for the addition of
|
||||||
|
``y=subidx``, for example::
|
||||||
|
|
||||||
|
OSC _dnd_code ; t=R:x=idx:y=subidx ; POSIX error name ST
|
||||||
|
|
||||||
|
Terminals must reply with ``ENOENT`` if the index is out of bounds.
|
||||||
If the client does not first request the ``text/uri-list`` MIME type or that
|
If the client does not first request the ``text/uri-list`` MIME type or that
|
||||||
MIME type is not present in the drop, the terminal must reply with
|
MIME type is not present in the drop, the terminal must reply with
|
||||||
``t=R:r=request_id ; EINVAL``. Terminals must support at least ``file://`` URIs.
|
``EINVAL``. Terminals must support at least ``file://`` URIs.
|
||||||
If the client requests an entry that is not a supported URI type the
|
If the client requests an entry that is not a supported URI type the
|
||||||
terminal must reply with ``t=R:r=request_id ; EUNKNOWN``.
|
terminal must reply with ``EUNKNOWN``.
|
||||||
|
|
||||||
Terminals must ONLY send data for regular files or directories. Symbolic links must be
|
Terminals must ONLY send data for regular files or directories. Symbolic links must be
|
||||||
resolved and the corresponding file or directory read. If the terminal does not have
|
resolved and the corresponding file or directory read. If the terminal does not have
|
||||||
permission to read the file it must reply with ``t=R:r=request_id ; EPERM``. Terminals
|
permission to read the file it must reply with ``EPERM``. Terminals
|
||||||
must respond with ``t=R:r=request_id ; EINVAL`` if the file is not a regular file after
|
must respond with ``EINVAL`` if the file is not a regular file after
|
||||||
resolving symlinks and ``t=R:r=request_id ; ENOENT`` if the file does not exist. If an
|
resolving symlinks and ``ENOENT`` if the file does not exist. If an
|
||||||
I/O error occurs the terminal must send ``t=R:r=request_id ; EIO``.
|
I/O error occurs the terminal must send ``EIO``.
|
||||||
|
|
||||||
For security reasons, terminals must reply with ``t=R:r=request_id ; EPERM`` if the drag
|
For security reasons, terminals must reply with ``EPERM`` if the drag
|
||||||
originated in the same window as the drop, this prevents malicious programs
|
originated in the same window as the drop, this prevents malicious programs
|
||||||
from reading files on the computer by starting their own drag. This is a
|
from reading files on the computer by starting their own drag. This is a
|
||||||
defense in depth feature since drags can only be started by the terminal, but
|
defense in depth feature since drags can only be started by the terminal, but
|
||||||
it helps in case of accidental drag starts and drops into the same window.
|
it helps in case of accidental drag starts and drops into the same window.
|
||||||
|
|
||||||
Terminals may queue requests with different ids and respond in order, or they
|
Clients may send multiple requests without waiting for any request to complete.
|
||||||
may respond in any order. If too many requests are received, they must deny
|
Terminals may queue requests and respond in any order they choose, including
|
||||||
the request with ``t:R:r=request_id ; EMFILE`` and end the drop.
|
interleaving responses to different requests. However, for simplicity, this
|
||||||
|
specification recommends terminals queue requests and respond in first-in,
|
||||||
|
first-out order. Every response can be matched to a corresponding request
|
||||||
|
using the ``x``, ``y`` and ``Y`` keys. To prevent Denial of service attacks,
|
||||||
|
if too many requests are received, terminals must deny the request
|
||||||
|
with ``EMFILE`` and end the drop.
|
||||||
|
|
||||||
|
|
||||||
Reading remote directories
|
Reading remote directories
|
||||||
+++++++++++++++++++++++++++
|
+++++++++++++++++++++++++++
|
||||||
|
|
||||||
If the file is actually a directory the terminal must respond with ``t=d:x=idx:r=request_id ; payload``.
|
If the file is actually a directory the terminal must instead respond with::
|
||||||
Here payload is a null byte separated list of entries in the directory that are
|
|
||||||
|
OSC _dnd_code ; t=r:x=idx:y=subidx:Y=handle:X=2 ; base64 encoded list of dir entries ST
|
||||||
|
|
||||||
|
The presence of ``X=2`` indicates this is a directory response not a regular
|
||||||
|
file. Here, the payload is a null byte separated list of entries in the directory that are
|
||||||
either regular files, directories or symlinks. The payload must be base64
|
either regular files, directories or symlinks. The payload must be base64
|
||||||
encoded and might be chunked if the directory has a lot of entries.
|
encoded and might be chunked if the directory has a lot of entries.
|
||||||
|
|
||||||
``idx`` is an arbitrary 32 bit integer that acts as a handle to this
|
``handle`` is an arbitrary non-zero integer that acts as a handle to this
|
||||||
directory. The client can now read the files in this directory using requests of the form
|
directory. The client can now read the files in this directory using requests of the form::
|
||||||
``t=d:x=idx:y=num:r=request_id``, here ``num`` is the 1-based index into the list of
|
|
||||||
directory entries previously transmitted to the client, where, ``1`` will
|
OSC _dnd_code ; t=r:Y=handle:x=num ST
|
||||||
correspond to the first entry in the directory. Once the client is done
|
|
||||||
reading a directory it should transmit ``t=d:x=idx:r=request_id`` to the terminal. The
|
Here ``num`` is the 1-based index into the list of directory entries previously transmitted
|
||||||
|
to the client. The terminal will respond with an escape code of the form::
|
||||||
|
|
||||||
|
OSC _dnd_code ; t=r:Y=handle:x=num ; base64 encoded data of entry ST
|
||||||
|
|
||||||
|
In case of any errors, the terminal will respond with::
|
||||||
|
|
||||||
|
OSC _dnd_code ; t=R:Y=handle:x=num ; POSIX error name ST
|
||||||
|
|
||||||
|
Once the client is done reading a directory it should transmit ``t=r:Y=handle`` to the terminal. The
|
||||||
terminal can then free any resources associated with that directory. The
|
terminal can then free any resources associated with that directory. The
|
||||||
directory handle is now invalid and terminals must return ``EINVAL`` if the
|
directory handle is now invalid and terminals must return ``EINVAL`` if the
|
||||||
client sends a request using an invalid directory handle. It is recommended
|
client sends a request using an invalid directory handle. It is recommended
|
||||||
@@ -192,12 +218,13 @@ resources are used, in order to prevent denial or service attacks. In such
|
|||||||
cases the terminal must respond with ``ENOMEM``.
|
cases the terminal must respond with ``ENOMEM``.
|
||||||
|
|
||||||
When transmitting a symlink that is inside a directory,
|
When transmitting a symlink that is inside a directory,
|
||||||
the terminal responds with escape code of the form::
|
the terminal responds with an escape code of the form::
|
||||||
|
|
||||||
OSC _dnd_code ; t=r:r=request_id:X=1 ; base64 encoded symlink target ST
|
OSC _dnd_code ; t=r:Y=handle:x=num:X=1 ; base64 encoded symlink target ST
|
||||||
|
|
||||||
Here, the presence of ``X=1`` indicates that the file is a symlink, not a
|
The presence of ``X=1`` indicates that the file is a symlink, not a
|
||||||
regular file.
|
regular file. Similarly for sub-directories it would be ``X=2`` and the payload
|
||||||
|
would be the null separated list of directory entries, as above.
|
||||||
|
|
||||||
|
|
||||||
Starting drags
|
Starting drags
|
||||||
@@ -351,9 +378,7 @@ Key Value Default Description
|
|||||||
``m`` - a drop move event
|
``m`` - a drop move event
|
||||||
``M`` - a drop dropped event
|
``M`` - a drop dropped event
|
||||||
``r`` - request dropped data
|
``r`` - request dropped data
|
||||||
``R`` - report an error to the terminal program
|
``R`` - report an error
|
||||||
``s`` - request data from the URI list entry
|
|
||||||
``d`` - send directory contents
|
|
||||||
``o`` - start offering drags
|
``o`` - start offering drags
|
||||||
``O`` - stop offering drags
|
``O`` - stop offering drags
|
||||||
``p`` - present data for drag offers
|
``p`` - present data for drag offers
|
||||||
@@ -372,8 +397,6 @@ Key Value Default Description
|
|||||||
means rejected, ``1`` means copy and
|
means rejected, ``1`` means copy and
|
||||||
``2`` means move.
|
``2`` means move.
|
||||||
|
|
||||||
``r`` Positive integer ``0`` The request id
|
|
||||||
|
|
||||||
**Keys for location**
|
**Keys for location**
|
||||||
-----------------------------------------------------------
|
-----------------------------------------------------------
|
||||||
``x`` Integer ``0`` Cell x-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
|
||||||
|
|||||||
@@ -333,11 +333,10 @@ def parsers() -> None:
|
|||||||
write_header(text, 'kitty/parse-multicell-command.h')
|
write_header(text, 'kitty/parse-multicell-command.h')
|
||||||
|
|
||||||
keymap = {
|
keymap = {
|
||||||
't': ('type', flag('aAmMrRsdoOpPeE')),
|
't': ('type', flag('aAmMrRoOpPeE')),
|
||||||
'm': ('more', 'uint'),
|
'm': ('more', 'uint'),
|
||||||
'i': ('client_id', 'uint'),
|
'i': ('client_id', 'uint'),
|
||||||
'o': ('operation', 'uint'),
|
'o': ('operation', 'uint'),
|
||||||
'r': ('request_id', 'uint'),
|
|
||||||
'x': ('cell_x', 'int'),
|
'x': ('cell_x', 'int'),
|
||||||
'y': ('cell_y', 'int'),
|
'y': ('cell_y', 'int'),
|
||||||
'X': ('pixel_x', 'int'),
|
'X': ('pixel_x', 'int'),
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ static inline void parse_dnd_code(PS *self, uint8_t *parser_buf,
|
|||||||
more = 'm',
|
more = 'm',
|
||||||
client_id = 'i',
|
client_id = 'i',
|
||||||
operation = 'o',
|
operation = 'o',
|
||||||
request_id = 'r',
|
|
||||||
cell_x = 'x',
|
cell_x = 'x',
|
||||||
cell_y = 'y',
|
cell_y = 'y',
|
||||||
pixel_x = 'X',
|
pixel_x = 'X',
|
||||||
@@ -52,9 +51,6 @@ static inline void parse_dnd_code(PS *self, uint8_t *parser_buf,
|
|||||||
case operation:
|
case operation:
|
||||||
value_state = UINT;
|
value_state = UINT;
|
||||||
break;
|
break;
|
||||||
case request_id:
|
|
||||||
value_state = UINT;
|
|
||||||
break;
|
|
||||||
case cell_x:
|
case cell_x:
|
||||||
value_state = INT;
|
value_state = INT;
|
||||||
break;
|
break;
|
||||||
@@ -91,9 +87,8 @@ static inline void parse_dnd_code(PS *self, uint8_t *parser_buf,
|
|||||||
case type: {
|
case type: {
|
||||||
g.type = parser_buf[pos++];
|
g.type = parser_buf[pos++];
|
||||||
if (g.type != 'A' && g.type != 'E' && g.type != 'M' && g.type != 'O' &&
|
if (g.type != 'A' && g.type != 'E' && g.type != 'M' && g.type != 'O' &&
|
||||||
g.type != 'P' && g.type != 'R' && g.type != 'a' && g.type != 'd' &&
|
g.type != 'P' && g.type != 'R' && g.type != 'a' && g.type != 'e' &&
|
||||||
g.type != 'e' && g.type != 'm' && g.type != 'o' && g.type != 'p' &&
|
g.type != 'm' && g.type != 'o' && g.type != 'p' && g.type != 'r') {
|
||||||
g.type != 'r' && g.type != 's') {
|
|
||||||
REPORT_ERROR("Malformed DnDCommand control block, unknown flag value "
|
REPORT_ERROR("Malformed DnDCommand control block, unknown flag value "
|
||||||
"for type: 0x%x",
|
"for type: 0x%x",
|
||||||
g.type);
|
g.type);
|
||||||
@@ -160,7 +155,6 @@ static inline void parse_dnd_code(PS *self, uint8_t *parser_buf,
|
|||||||
U(more);
|
U(more);
|
||||||
U(client_id);
|
U(client_id);
|
||||||
U(operation);
|
U(operation);
|
||||||
U(request_id);
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -212,13 +206,12 @@ static inline void parse_dnd_code(PS *self, uint8_t *parser_buf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
REPORT_VA_COMMAND(
|
REPORT_VA_COMMAND(
|
||||||
"K s {sc sI sI sI sI si si si si ss#}", self->window_id, "dnd_command",
|
"K s {sc sI sI sI si si si si ss#}", self->window_id, "dnd_command",
|
||||||
|
|
||||||
"type", g.type,
|
"type", g.type,
|
||||||
|
|
||||||
"more", (unsigned int)g.more, "client_id", (unsigned int)g.client_id,
|
"more", (unsigned int)g.more, "client_id", (unsigned int)g.client_id,
|
||||||
"operation", (unsigned int)g.operation, "request_id",
|
"operation", (unsigned int)g.operation,
|
||||||
(unsigned int)g.request_id,
|
|
||||||
|
|
||||||
"cell_x", (int)g.cell_x, "cell_y", (int)g.cell_y, "pixel_x",
|
"cell_x", (int)g.cell_x, "cell_y", (int)g.cell_y, "pixel_x",
|
||||||
(int)g.pixel_x, "pixel_y", (int)g.pixel_y,
|
(int)g.pixel_x, "pixel_y", (int)g.pixel_y,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ typedef enum ScrollTypes { SCROLL_LINE = -999999, SCROLL_PAGE, SCROLL_FULL } Scr
|
|||||||
typedef struct DnDCommand {
|
typedef struct DnDCommand {
|
||||||
char type;
|
char type;
|
||||||
unsigned more;
|
unsigned more;
|
||||||
uint32_t client_id, request_id;
|
uint32_t client_id;
|
||||||
size_t payload_sz;
|
size_t payload_sz;
|
||||||
int32_t cell_x, cell_y, pixel_x, pixel_y;
|
int32_t cell_x, cell_y, pixel_x, pixel_y;
|
||||||
uint32_t operation;
|
uint32_t operation;
|
||||||
|
|||||||
Reference in New Issue
Block a user