diff --git a/kitty/dnd.c b/kitty/dnd.c index 6f5afd9f5..d46ceee66 100644 --- a/kitty/dnd.c +++ b/kitty/dnd.c @@ -1916,7 +1916,7 @@ void drag_offer_start_to_child(Window *w, int32_t cell_x, int32_t cell_y, int32_t pixel_x, int32_t pixel_y) { char buf[256]; int header_size = snprintf( - buf, sizeof(buf), "%d;t=o:x=%d:y=%d:X=%d:Y=%d", DND_CODE, cell_x, cell_y, pixel_x, pixel_y); + buf, sizeof(buf), "\x1b]%d;t=o:x=%d:y=%d:X=%d:Y=%d", DND_CODE, cell_x, cell_y, pixel_x, pixel_y); queue_payload_to_child( w->id, w->drag_source.client_id, &w->drag_source.pending, buf, header_size, NULL, 0, false); } @@ -2229,6 +2229,25 @@ dnd_test_probe_state(PyObject *self UNUSED, PyObject *args) { if (strcmp(q, "drop_getting_data_for_mime") == 0) { return PyUnicode_FromString(w->drop.getting_data_for_mime ? w->drop.getting_data_for_mime : ""); } + if (strcmp(q, "drag_operations") == 0) { + return PyLong_FromLong((long)w->drag_source.allowed_operations); + } + if (strcmp(q, "drag_mimes") == 0) { + PyObject *ans = PyTuple_New(w->drag_source.num_mimes); + for (size_t i = 0; i < w->drag_source.num_mimes; i++) PyTuple_SET_ITEM( + ans, i, PyUnicode_FromString(w->drag_source.items[i].mime_type)); + return ans; + } + Py_RETURN_NONE; +} + +static PyObject* +dnd_test_start_drag_offer(PyObject *self UNUSED, PyObject *args) { + unsigned long long window_id; int x=0, y=0, X=0, Y=0; + if (!PyArg_ParseTuple(args, "K|iiii", &window_id, &x, &y, &X, &Y)) return NULL; + Window *w = window_for_window_id((id_type)window_id); + if (!w) { PyErr_SetString(PyExc_ValueError, "Window not found"); return NULL; } + drag_offer_start_to_child(w, x, y, X, Y); Py_RETURN_NONE; } @@ -2239,6 +2258,7 @@ static PyMethodDef dnd_methods[] = { METHODB(dnd_test_set_mouse_pos, METH_VARARGS), METHODB(dnd_test_fake_drop_event, METH_VARARGS), METHODB(dnd_test_fake_drop_data, METH_VARARGS), + METHODB(dnd_test_start_drag_offer, METH_VARARGS), METHODB(dnd_test_force_drag_dropped, METH_VARARGS), METHODB(dnd_test_request_drag_data, METH_VARARGS), METHODB(dnd_test_drag_notify, METH_VARARGS), diff --git a/kitty_tests/dnd_kitten.py b/kitty_tests/dnd_kitten.py index de863ef97..806e02673 100644 --- a/kitty_tests/dnd_kitten.py +++ b/kitty_tests/dnd_kitten.py @@ -24,6 +24,7 @@ from kitty.fast_data_types import ( dnd_test_fake_drop_data, dnd_test_fake_drop_event, dnd_test_probe_state, + dnd_test_start_drag_offer, ) from kitty.utils import as_file_url @@ -315,8 +316,22 @@ class TestDnDKitten(BaseTest): self.assertEqual(expected_dest_content, f.read()) do_overwrite_drop(enter_content, '\x1b[13u') - do_overwrite_drop(b'overwrite-esc-test-content', '\x1b[27u', 0) + do_overwrite_drop(b'overwrite-esc-test-content', '\x1b[27u', 0) # ]]] def assert_files_have_same_content(self, a, b): with open(a, 'rb') as fa, open(b, 'rb') as fb: self.assertEqual(fa.read(), fb.read(), f'{a} ({os.path.getsize(a)}) != {b} ({os.path.getsize(b)})') + + def test_dnd_kitten_drag(self): + img_drag_path = 'image.png' + with open(os.path.join(self.kitten_wd, img_drag_path), 'wb') as f: + f.write(os.urandom(1113)) + create_fs(self.src_data_dir) + self.finish_setup(cli_args=(f'--drag=image/png:{img_drag_path}', self.src_data_dir)) # ))) + with self.subTest(remote=False): + self.dnd_kitten_drag(False, img_drag_path) + + def dnd_kitten_drag(self, remote_client, img_drop_path): + copy, move = self.get_button_geometry() + dnd_test_start_drag_offer(self.capture.window_id, 1, 1) + self.wait_for_state('drag_operations', 3)