mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-07-04 23:03:29 +00:00
Fix 4 bugs in t=k implementation and add test infrastructure
Bug 1: remote_items allocation used ds.num_mimes instead of mi.num_uris Bug 2: Off-by-one in uri_item_idx > mi.num_uris (should be >=) Bug 3: Off-by-one in entry_num > parent->children_sz (should be >=) Bug 4: DRAG_SOURCE_DROPPED state never set in drag_notify Also add dnd_test_force_drag_dropped() helper and make notify_drag_data_ready() succeed in test mode. Agent-Logs-Url: https://github.com/kovidgoyal/kitty/sessions/9da0bff7-6a1a-490f-a4c5-8cb328e056ce Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com>
This commit is contained in:
parent
6bd41c94a2
commit
2018f8b134
3 changed files with 41 additions and 5 deletions
15
kitty/dnd.c
15
kitty/dnd.c
|
|
@ -170,6 +170,11 @@ dnd_set_test_write_func(PyObject *func, size_t mime_list_size_cap, size_t presen
|
|||
REMOTE_DRAG_LIMIT = remote_drag_limit ? remote_drag_limit : DEFAULT_REMOTE_DRAG_LIMIT;
|
||||
}
|
||||
|
||||
bool
|
||||
dnd_is_test_mode(void) {
|
||||
return g_dnd_test_write_func != 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;
|
||||
|
|
@ -1438,7 +1443,7 @@ drag_notify(Window *w, DragNotifyType type) {
|
|||
default:
|
||||
sz += snprintf(buf + sz, sizeof(buf) - sz, "o=1"); break;
|
||||
} break;
|
||||
case DRAG_NOTIFY_DROPPED: break;
|
||||
case DRAG_NOTIFY_DROPPED: ds.state = DRAG_SOURCE_DROPPED; break;
|
||||
case DRAG_NOTIFY_FINISHED:
|
||||
sz += snprintf(buf + sz, sizeof(buf) - sz, "y=%d", global_state.drag_source.was_canceled ? 1 : 0); break;
|
||||
}
|
||||
|
|
@ -1780,9 +1785,9 @@ toplevel_data_for_drag(
|
|||
bool has_more, const uint8_t *payload, size_t payload_sz
|
||||
) {
|
||||
if (!mi.remote_items) {
|
||||
mi.remote_items = calloc(ds.num_mimes, sizeof(mi.remote_items[0]));
|
||||
mi.remote_items = calloc(mi.num_uris, sizeof(mi.remote_items[0]));
|
||||
if (!mi.remote_items) abrt(ENOMEM);
|
||||
mi.num_remote_items = ds.num_mimes;
|
||||
mi.num_remote_items = mi.num_uris;
|
||||
}
|
||||
if (!mi.base_dir_for_remote_items) {
|
||||
int fd;
|
||||
|
|
@ -1796,7 +1801,7 @@ toplevel_data_for_drag(
|
|||
ri->started = true;
|
||||
ri->type = item_type;
|
||||
base64_init_stream_decoder(&ri->base64_state);
|
||||
if (uri_item_idx > mi.num_uris) abrt(EINVAL);
|
||||
if (uri_item_idx >= mi.num_uris) abrt(EINVAL);
|
||||
const char *uri = mi.uri_list[uri_item_idx];
|
||||
char *fname = sanitized_filename_from_url(uri);
|
||||
if (!fname) abrt(EINVAL);
|
||||
|
|
@ -1860,7 +1865,7 @@ subdir_data_for_drag(
|
|||
parent->fd_plus_one = fd + 1;
|
||||
}
|
||||
}
|
||||
if (entry_num > parent->children_sz) abrt(EINVAL);
|
||||
if (entry_num >= parent->children_sz) abrt(EINVAL);
|
||||
DragRemoteItem *ri = parent->children + entry_num;
|
||||
if (!ri->started) {
|
||||
ri->started = true;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ size_t drop_update_mimes(Window *w, const char **allowed_mimes, size_t allowed_m
|
|||
void drop_dispatch_data(Window *w, const char *mime_type, const char *data, ssize_t sz);
|
||||
void drop_finish(Window *w);
|
||||
void dnd_set_test_write_func(PyObject*, size_t, size_t, size_t);
|
||||
bool dnd_is_test_mode(void);
|
||||
|
||||
|
||||
typedef enum { DRAG_NOTIFY_ACCEPTED, DRAG_NOTIFY_ACTION_CHANGED, DRAG_NOTIFY_DROPPED, DRAG_NOTIFY_FINISHED } DragNotifyType;
|
||||
|
|
|
|||
30
kitty/glfw.c
30
kitty/glfw.c
|
|
@ -1052,6 +1052,34 @@ dnd_test_fake_drop_data(PyObject *self UNUSED, PyObject *args) {
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
dnd_test_force_drag_dropped(PyObject *self UNUSED, PyObject *args) {
|
||||
// Force the drag source state to DROPPED for testing purposes.
|
||||
// This simulates what would happen after start_window_drag() succeeds
|
||||
// and the drop target receives the data.
|
||||
unsigned long long window_id;
|
||||
if (!PyArg_ParseTuple(args, "K", &window_id)) return NULL;
|
||||
Window *w = window_for_window_id((id_type)window_id);
|
||||
if (!w) { PyErr_SetString(PyExc_ValueError, "Window not found"); return NULL; }
|
||||
if (w->drag_source.state != DRAG_SOURCE_BEING_BUILT) {
|
||||
PyErr_SetString(PyExc_ValueError, "Drag source state is not BEING_BUILT");
|
||||
return NULL;
|
||||
}
|
||||
// Simulate what drag_start does on success, without calling start_window_drag
|
||||
for (size_t i = 0; i < w->drag_source.num_mimes; i++) {
|
||||
free(w->drag_source.items[i].optional_data);
|
||||
w->drag_source.items[i].optional_data = NULL;
|
||||
w->drag_source.items[i].data_size = 0;
|
||||
w->drag_source.items[i].data_capacity = 0;
|
||||
w->drag_source.items[i].data_decode_initialized = false;
|
||||
}
|
||||
for (size_t i = 0; i < arraysz(w->drag_source.images); i++) {
|
||||
if (w->drag_source.images[i].data) free(w->drag_source.images[i].data);
|
||||
zero_at_ptr(w->drag_source.images + i);
|
||||
}
|
||||
w->drag_source.state = DRAG_SOURCE_DROPPED;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
// }}}
|
||||
|
||||
static void
|
||||
|
|
@ -1150,6 +1178,7 @@ drag_source_callback(GLFWwindow *window UNUSED, GLFWDragEvent *ev) {
|
|||
|
||||
int
|
||||
notify_drag_data_ready(id_type os_window_id, const char *mime_type) {
|
||||
if (dnd_is_test_mode()) return 0; // In test mode, always succeed
|
||||
OSWindow *w = os_window_for_id(os_window_id);
|
||||
GLFWDragSourceItem item = {.mime_type = mime_type};
|
||||
if (w && w->handle) return glfwStartDrag(w->handle, &item, 1, NULL, -1, false);
|
||||
|
|
@ -3363,6 +3392,7 @@ static PyMethodDef module_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_force_drag_dropped, METH_VARARGS),
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue