mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-06 01:05:48 +02:00
Allow drop clients to use machine id as well
This commit is contained in:
@@ -38,7 +38,7 @@ the end of the last chunk.
|
||||
Accepting drops
|
||||
-----------------
|
||||
|
||||
In order to inform the terminal emulator that the program accepts drops, it
|
||||
In order to inform the terminal emulator that the client accepts drops, it
|
||||
must send the following escape code::
|
||||
|
||||
OSC _dnd_code ; t=a ; payload ST
|
||||
@@ -48,7 +48,17 @@ The list of MIME types is optional, it is needed if the program wants to accept
|
||||
exotic or private use MIME types on platforms such as macOS, where the system
|
||||
does not deliver drop events unless the MIME type is registered.
|
||||
|
||||
When the program is done accepting drops, or at exit, it should send the escape
|
||||
The terminal emulator may respond to this escape code with an escape code of
|
||||
the form::
|
||||
|
||||
OSC _dnd_code ; t=a ; machine id ST
|
||||
|
||||
Here, the :ref:`machine id <machine_id>` is an id that identifies the machine
|
||||
the terminal is running on and can be used by the client to determine whether
|
||||
to request remote files from the terminal when a drop occurs.
|
||||
See :ref:`below <machine_id>` for the semantics of the machine id.
|
||||
|
||||
When the client is done accepting drops, or at exit, it should send the escape
|
||||
code::
|
||||
|
||||
OSC _dnd_code ; t=A ST
|
||||
@@ -132,8 +142,12 @@ terminal emulator must then inform the OS that the drop is completed.
|
||||
Dropping from remote machines
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In order to support dropping of files from remote machines,
|
||||
clients can first request the :rfc:`text/uri-list <2483>` MIME
|
||||
In order to support dropping of files from remote machines, the client
|
||||
can use the :ref:`machine id <machine_id>` previously sent by the terminal.
|
||||
If it is different from the id of the machine the client is running on, it
|
||||
can choose to request remote files, as follows.
|
||||
|
||||
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
|
||||
send the terminal emulator a data request of the form::
|
||||
|
||||
|
||||
81
kitty/dnd.c
81
kitty/dnd.c
@@ -144,40 +144,6 @@ reset_drop(Window *w) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
drop_register_window(Window *w, const uint8_t *payload, size_t payload_sz, bool on, uint32_t client_id, bool more) {
|
||||
w->drop.wanted = on;
|
||||
w->drop.client_id = client_id;
|
||||
if (!on) { drop_free_data(w); zero_at_ptr(&w->drop); return; }
|
||||
if (!payload || !payload_sz) return;
|
||||
size_t sz = w->drop.registered_mimes ? strlen(w->drop.registered_mimes) : 0;
|
||||
if (sz + payload_sz > MIME_LIST_SIZE_CAP) return;
|
||||
w->drop.registered_mimes = realloc(w->drop.registered_mimes, sz + payload_sz + 1);
|
||||
if (w->drop.registered_mimes) {
|
||||
memcpy(w->drop.registered_mimes + sz, payload, payload_sz);
|
||||
sz += payload_sz;
|
||||
w->drop.registered_mimes[sz] = 0;
|
||||
}
|
||||
if (more) return;
|
||||
if (w->drop.registered_mimes) {
|
||||
OSWindow *osw = os_window_for_kitty_window(w->id);
|
||||
if (osw) {
|
||||
size_t num = 0;
|
||||
RAII_ALLOC(const char*, mimes, malloc(sizeof(char*) * strlen(w->drop.registered_mimes)));
|
||||
if (mimes) {
|
||||
char* token = strtok(w->drop.registered_mimes, " ");
|
||||
while (token != NULL) {
|
||||
mimes[num++] = token;
|
||||
token = strtok(NULL, " ");
|
||||
}
|
||||
register_mimes_for_drop(osw, mimes, num);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(w->drop.registered_mimes); w->drop.registered_mimes = NULL;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
string_arrays_cmp(const char **a, size_t an, const char **b, size_t bn) {
|
||||
if (an != bn) return (int)an - (int)bn;
|
||||
@@ -289,6 +255,46 @@ queue_payload_to_child(id_type id, uint32_t client_id, PendingData *pending, con
|
||||
if (pending->count) check_for_pending_writes();
|
||||
}
|
||||
|
||||
void
|
||||
drop_register_window(Window *w, const uint8_t *payload, size_t payload_sz, bool on, uint32_t client_id, bool more) {
|
||||
w->drop.wanted = on;
|
||||
w->drop.client_id = client_id;
|
||||
if (!on) { drop_free_data(w); zero_at_ptr(&w->drop); return; }
|
||||
if (!payload || !payload_sz) return;
|
||||
size_t sz = w->drop.registered_mimes ? strlen(w->drop.registered_mimes) : 0;
|
||||
if (sz + payload_sz > MIME_LIST_SIZE_CAP) return;
|
||||
w->drop.registered_mimes = realloc(w->drop.registered_mimes, sz + payload_sz + 1);
|
||||
if (w->drop.registered_mimes) {
|
||||
memcpy(w->drop.registered_mimes + sz, payload, payload_sz);
|
||||
sz += payload_sz;
|
||||
w->drop.registered_mimes[sz] = 0;
|
||||
}
|
||||
if (more) return;
|
||||
if (w->drop.registered_mimes) {
|
||||
OSWindow *osw = os_window_for_kitty_window(w->id);
|
||||
if (osw) {
|
||||
size_t num = 0;
|
||||
RAII_ALLOC(const char*, mimes, malloc(sizeof(char*) * strlen(w->drop.registered_mimes)));
|
||||
if (mimes) {
|
||||
char* token = strtok(w->drop.registered_mimes, " ");
|
||||
while (token != NULL) {
|
||||
mimes[num++] = token;
|
||||
token = strtok(NULL, " ");
|
||||
}
|
||||
register_mimes_for_drop(osw, mimes, num);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(w->drop.registered_mimes); w->drop.registered_mimes = NULL;
|
||||
const char* host_machine_id = machine_id();
|
||||
if (host_machine_id) {
|
||||
char header[32] = {0};
|
||||
int n = snprintf(header, sizeof(header), "\x1b]%d;t=a", DND_CODE);
|
||||
queue_payload_to_child(
|
||||
w->id, w->drop.client_id, &w->drop.pending, header, n, host_machine_id, strlen(host_machine_id), false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
drop_move_on_child(Window *w, const char** mimes, size_t num_mimes, bool is_drop) {
|
||||
if (!w->drop.hovered) {
|
||||
@@ -866,13 +872,6 @@ do_drop_request_uri_data(Window *w, int32_t mime_idx, int32_t file_idx) {
|
||||
return sync;
|
||||
}
|
||||
|
||||
void
|
||||
drop_request_uri_data(Window *w, const char *payload, size_t payload_sz) {
|
||||
(void)w; (void)payload; (void)payload_sz;
|
||||
/* This function is no longer used in the new protocol; URI data requests
|
||||
* are now handled through the unified t=r queue via do_drop_request_uri_data. */
|
||||
}
|
||||
|
||||
/* Handle a directory request from the client.
|
||||
* handle_id: the directory handle (Y= key).
|
||||
* entry_num: 0 means close the handle; >=1 means read that entry (x= key, 1-based).
|
||||
|
||||
@@ -14,7 +14,6 @@ void drop_move_on_child(Window *w, const char **mimes, size_t num_mimes, bool is
|
||||
void drop_left_child(Window *w);
|
||||
void drop_free_data(Window *w);
|
||||
void drop_send_einval(Window *w);
|
||||
void drop_request_uri_data(Window *w, const char *payload, size_t payload_sz);
|
||||
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_set_status(Window *w, int operation, const char *payload, size_t payload_sz, bool more);
|
||||
|
||||
@@ -5,6 +5,7 @@ import errno
|
||||
import re
|
||||
from base64 import standard_b64decode, standard_b64encode
|
||||
from contextlib import contextmanager
|
||||
from functools import partial
|
||||
|
||||
from kitty.fast_data_types import (
|
||||
DND_CODE,
|
||||
@@ -16,6 +17,7 @@ from kitty.fast_data_types import (
|
||||
dnd_test_fake_drop_event,
|
||||
dnd_test_set_mouse_pos,
|
||||
)
|
||||
from kitty.machine_id import machine_id
|
||||
|
||||
from . import BaseTest, parse_bytes
|
||||
|
||||
@@ -321,6 +323,8 @@ def dnd_test_window():
|
||||
dnd_test_cleanup_fake_window(os_window_id)
|
||||
|
||||
|
||||
machine_id = partial(machine_id, 'tty-dnd-protocol-machine-id')
|
||||
|
||||
# ---- test class -------------------------------------------------------------
|
||||
|
||||
class TestDnDProtocol(BaseTest):
|
||||
@@ -328,6 +332,14 @@ class TestDnDProtocol(BaseTest):
|
||||
def _assert_no_output(self, capture: _WriteCapture, window_id: int) -> None:
|
||||
self.ae(capture.peek(window_id), b'', 'unexpected output to child')
|
||||
|
||||
def _register_for_drops(self, screen, cap, wid, mimes='text/plain text/uri-list', client_id=0) -> None:
|
||||
parse_bytes(screen, client_register(mimes, client_id=client_id))
|
||||
events = self._get_events(cap, wid)
|
||||
self.assertEqual(len(events), 1, events)
|
||||
self.ae(events[0]['type'], 'a')
|
||||
self.ae(events[0]['payload'].strip().decode(), machine_id())
|
||||
|
||||
|
||||
def _get_events(self, capture: _WriteCapture, window_id: int) -> list[dict]:
|
||||
return parse_escape_codes(capture.consume(window_id))
|
||||
|
||||
@@ -336,10 +348,7 @@ class TestDnDProtocol(BaseTest):
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
# Client registers – state is already wanted=True from fake-window creation,
|
||||
# but calling the escape code should not break things.
|
||||
parse_bytes(screen, client_register('text/plain text/uri-list'))
|
||||
# No output expected at this point (no drop in progress).
|
||||
self._assert_no_output(cap, wid)
|
||||
|
||||
self._register_for_drops(screen, cap, wid)
|
||||
# Client unregisters.
|
||||
parse_bytes(screen, client_unregister())
|
||||
self._assert_no_output(cap, wid)
|
||||
@@ -347,7 +356,7 @@ class TestDnDProtocol(BaseTest):
|
||||
def test_drop_move_sends_move_event(self) -> None:
|
||||
"""A drop entering and moving over the window generates t=m events."""
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 5, 3, 100, 60)
|
||||
dnd_test_fake_drop_event(wid, False, ['text/plain', 'text/uri-list'])
|
||||
|
||||
@@ -366,7 +375,7 @@ class TestDnDProtocol(BaseTest):
|
||||
def test_drop_move_mime_always_sent(self) -> None:
|
||||
"""The current implementation always includes the MIME list in move events."""
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
mimes = ['text/plain']
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, False, mimes)
|
||||
@@ -384,7 +393,7 @@ class TestDnDProtocol(BaseTest):
|
||||
def test_drop_leave_sends_leave_event(self) -> None:
|
||||
"""Drop leaving sends t=m with x=-1,y=-1."""
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, False, ['text/plain'])
|
||||
cap.consume(wid)
|
||||
@@ -400,7 +409,7 @@ class TestDnDProtocol(BaseTest):
|
||||
def test_client_accepts_drop(self) -> None:
|
||||
"""Client sending t=m:o=1 is recorded and does not trigger extra output."""
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, False, ['text/plain'])
|
||||
cap.consume(wid)
|
||||
@@ -414,7 +423,7 @@ class TestDnDProtocol(BaseTest):
|
||||
"""Complete happy-path: move → accept → drop → request → data → finish."""
|
||||
payload_data = b'hello world'
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
|
||||
# Move
|
||||
dnd_test_set_mouse_pos(wid, 2, 3, 16, 24)
|
||||
@@ -451,7 +460,7 @@ class TestDnDProtocol(BaseTest):
|
||||
def test_request_unknown_mime(self) -> None:
|
||||
"""Requesting an out-of-range MIME index yields an error."""
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, True, ['text/plain'])
|
||||
cap.consume(wid)
|
||||
@@ -466,7 +475,7 @@ class TestDnDProtocol(BaseTest):
|
||||
def test_data_error_propagation(self) -> None:
|
||||
"""When data retrieval fails the client receives a t=R error code."""
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, True, ['text/plain'])
|
||||
cap.consume(wid)
|
||||
@@ -483,7 +492,7 @@ class TestDnDProtocol(BaseTest):
|
||||
def test_data_eperm_error(self) -> None:
|
||||
"""EPERM error is correctly forwarded to the client."""
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, True, ['text/plain'])
|
||||
cap.consume(wid)
|
||||
@@ -501,7 +510,7 @@ class TestDnDProtocol(BaseTest):
|
||||
chunk_limit = 3072
|
||||
big_payload = b'X' * (chunk_limit * 3) # 3 chunks expected
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, True, ['text/plain'])
|
||||
cap.consume(wid)
|
||||
@@ -519,7 +528,7 @@ class TestDnDProtocol(BaseTest):
|
||||
"""The client_id (i=…) set during registration is echoed in all replies."""
|
||||
client_id = 42
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain', client_id=client_id))
|
||||
self._register_for_drops(screen, cap, wid, mimes='text/plain', client_id=client_id)
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, False, ['text/plain'])
|
||||
raw = cap.consume(wid)
|
||||
@@ -530,7 +539,7 @@ class TestDnDProtocol(BaseTest):
|
||||
def test_multiple_mimes_priority(self) -> None:
|
||||
"""The client can request data from any offered MIME type by index."""
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain text/uri-list'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain text/uri-list')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
# OS offers both types.
|
||||
dnd_test_fake_drop_event(wid, True, ['text/plain', 'text/uri-list'])
|
||||
@@ -569,7 +578,7 @@ class TestDnDProtocol(BaseTest):
|
||||
def test_move_event_after_mime_change(self) -> None:
|
||||
"""When offered MIME list changes, the new list is included in the move event."""
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, False, ['text/plain'])
|
||||
cap.consume(wid)
|
||||
@@ -585,7 +594,7 @@ class TestDnDProtocol(BaseTest):
|
||||
def test_drop_event_has_uppercase_M(self) -> None:
|
||||
"""A drop (not just a move) sends t=M (uppercase)."""
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, True, ['text/plain'])
|
||||
events = self._get_events(cap, wid)
|
||||
@@ -595,7 +604,7 @@ class TestDnDProtocol(BaseTest):
|
||||
def test_data_end_signal(self) -> None:
|
||||
"""The end-of-data signal is an empty payload escape code."""
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, True, ['text/plain'])
|
||||
cap.consume(wid)
|
||||
@@ -613,7 +622,7 @@ class TestDnDProtocol(BaseTest):
|
||||
def test_empty_data(self) -> None:
|
||||
"""Zero-byte payload is handled gracefully – only end signal is sent."""
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, True, ['text/plain'])
|
||||
cap.consume(wid)
|
||||
@@ -633,7 +642,7 @@ class TestDnDProtocol(BaseTest):
|
||||
"""Register, drop, deliver text/uri-list data, discard move/drop events."""
|
||||
if mimes is None:
|
||||
mimes = ['text/plain', 'text/uri-list']
|
||||
parse_bytes(screen, client_register('text/plain text/uri-list'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain text/uri-list')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, True, mimes)
|
||||
cap.consume(wid)
|
||||
@@ -728,7 +737,7 @@ class TestDnDProtocol(BaseTest):
|
||||
fpath = f.name
|
||||
try:
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, True, ['text/plain', 'text/uri-list'])
|
||||
cap.consume(wid)
|
||||
@@ -1826,7 +1835,7 @@ class TestDnDProtocol(BaseTest):
|
||||
"""x= key is echoed in data responses to identify which request is being answered."""
|
||||
payload_data = b'hello disambiguation'
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, True, ['text/plain'])
|
||||
cap.consume(wid)
|
||||
@@ -1843,7 +1852,7 @@ class TestDnDProtocol(BaseTest):
|
||||
def test_x_key_echoed_in_error_response(self) -> None:
|
||||
"""x= key is echoed in error responses."""
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, True, ['text/plain'])
|
||||
cap.consume(wid)
|
||||
@@ -1859,7 +1868,7 @@ class TestDnDProtocol(BaseTest):
|
||||
def test_x_key_in_error_for_io_failure(self) -> None:
|
||||
"""x= key is echoed in I/O error responses."""
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, True, ['text/plain'])
|
||||
cap.consume(wid)
|
||||
@@ -1875,7 +1884,7 @@ class TestDnDProtocol(BaseTest):
|
||||
def test_fifo_order_with_different_indices(self) -> None:
|
||||
"""Multiple requests with different x= values are served in FIFO order."""
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain text/html'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain text/html')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, True, ['text/plain', 'text/html'])
|
||||
cap.consume(wid)
|
||||
@@ -1905,7 +1914,7 @@ class TestDnDProtocol(BaseTest):
|
||||
def test_request_after_error_proceeds(self) -> None:
|
||||
"""After an error response, the next queued request is processed."""
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, True, ['text/plain'])
|
||||
cap.consume(wid)
|
||||
@@ -1934,7 +1943,7 @@ class TestDnDProtocol(BaseTest):
|
||||
def test_queue_overflow_returns_emfile(self) -> None:
|
||||
"""Exceeding 128 queued requests returns EMFILE and ends the drop."""
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, True, ['text/plain'])
|
||||
cap.consume(wid)
|
||||
@@ -2118,7 +2127,7 @@ class TestDnDProtocol(BaseTest):
|
||||
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 (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, True, ['text/plain'])
|
||||
cap.consume(wid)
|
||||
@@ -2139,7 +2148,7 @@ class TestDnDProtocol(BaseTest):
|
||||
def test_multiple_sync_errors_processed_immediately(self) -> None:
|
||||
"""Multiple queued requests that all fail synchronously are processed immediately."""
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 0, 0, 0, 0)
|
||||
dnd_test_fake_drop_event(wid, True, ['text/plain'])
|
||||
cap.consume(wid)
|
||||
@@ -2164,7 +2173,7 @@ class TestDnDProtocol(BaseTest):
|
||||
"""Responses must not contain the old r= key."""
|
||||
payload_data = b'no r= key test'
|
||||
with dnd_test_window() as (osw, wid, screen, cap):
|
||||
parse_bytes(screen, client_register('text/plain'))
|
||||
self._register_for_drops(screen, cap, wid, 'text/plain')
|
||||
dnd_test_set_mouse_pos(wid, 2, 3, 16, 24)
|
||||
dnd_test_fake_drop_event(wid, True, ['text/plain'])
|
||||
cap.consume(wid)
|
||||
|
||||
Reference in New Issue
Block a user