diff --git a/docs/dnd-protocol.rst b/docs/dnd-protocol.rst index d3eca8ff9..9ee8173a2 100644 --- a/docs/dnd-protocol.rst +++ b/docs/dnd-protocol.rst @@ -113,7 +113,18 @@ getting the data, the terminal must send an escape code of the form:: OSC _dnd_code ; t=R ; POSIX error name ST Here POSIX error name is a POSIX symbolic error name such as ``ENOENT`` or -``EIO`` or the value ``EUNKNOWN`` for an unknown error. +``EIO`` or the value ``EUNKNOWN`` for an unknown error. Note that if a client +sends a request for another MIME type before the data for the revious MIME type +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 +send an escape code of the form:: + + OSC _dnd_code ; t=r ST + +That is, it must send a request for data with no MIME type specified. The +terminal emulator must then inform the OS that the drop is completed. Metadata reference --------------------------- diff --git a/kitty/dnd.c b/kitty/dnd.c index 99d6b0f12..aa8b9e0c0 100644 --- a/kitty/dnd.c +++ b/kitty/dnd.c @@ -228,15 +228,16 @@ drop_set_status(Window *w, int operation, const char *payload, size_t payload_sz if (!w->drop.accept_in_progress) { drop_free_accepted_mimes(w); w->drop.accept_in_progress = true; w->drop.accepted_operation = 0; switch(operation) { - case 1: w->drop.accepted_operation = GLFW_DRAG_OPERATION_COPY; break; - case 2: w->drop.accepted_operation = GLFW_DRAG_OPERATION_MOVE; break; - default: w->drop.accepted_operation = GLFW_DRAG_OPERATION_NONE; break; + case 1: case 2: w->drop.accepted_operation = operation; break; + default: w->drop.accepted_operation = 0; break; } } - w->drop.accepted_mimes = realloc(w->drop.accepted_mimes, w->drop.accepted_mimes_sz + payload_sz + 2); - if (w->drop.accepted_mimes) { - memcpy(w->drop.accepted_mimes + w->drop.accepted_mimes_sz, payload, payload_sz); - w->drop.accepted_mimes_sz += payload_sz; + if (payload_sz) { + w->drop.accepted_mimes = realloc(w->drop.accepted_mimes, w->drop.accepted_mimes_sz + payload_sz + 2); + if (w->drop.accepted_mimes) { + memcpy(w->drop.accepted_mimes + w->drop.accepted_mimes_sz, payload, payload_sz); + w->drop.accepted_mimes_sz += payload_sz; + } } if (!more) { w->drop.accept_in_progress = false; @@ -250,11 +251,21 @@ drop_set_status(Window *w, int operation, const char *payload, size_t payload_sz } } +void +drop_finish(Window *w) { + OSWindow *osw = os_window_for_kitty_window(w->id); + if (osw && osw->handle) { + int op = GLFW_DRAG_OPERATION_GENERIC; + if (w->drop.accepted_operation == 1) op = GLFW_DRAG_OPERATION_COPY; + else if (w->drop.accepted_operation == 2) op = GLFW_DRAG_OPERATION_MOVE; + glfwEndDrop(osw->handle, op); + } +} size_t drop_update_mimes(Window *w, const char **allowed_mimes, size_t allowed_mimes_count) { if (w->drop.accept_in_progress) return allowed_mimes_count; - if (w->drop.accepted_operation == GLFW_DRAG_OPERATION_NONE) return 0; + if (!w->drop.accepted_operation) return 0; typedef struct mime_sorter { const char *m; ssize_t key; } mime_sorter; if (!w->drop.accepted_mimes) return allowed_mimes_count; RAII_ALLOC(mime_sorter, ms, malloc(sizeof(mime_sorter) * allowed_mimes_count)); diff --git a/kitty/dnd.h b/kitty/dnd.h index 6b56560ff..f7aa9f564 100644 --- a/kitty/dnd.h +++ b/kitty/dnd.h @@ -16,3 +16,4 @@ void drop_request_data(Window *w, const char *mime); void drop_set_status(Window *w, int operation, const char *payload, size_t payload_sz, bool more); size_t drop_update_mimes(Window *w, const char **allowed_mimes, size_t allowed_mimes_count); void drop_dispatch_data(Window *w, const char *data, ssize_t sz); +void drop_finish(Window *w); diff --git a/kitty/glfw.c b/kitty/glfw.c index 05001d944..ac23d34ff 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -847,10 +847,12 @@ on_drop(GLFWwindow *window, GLFWDropEvent *ev) { case GLFW_DROP_DATA_AVAILABLE: if (global_state.drop_dest.client_window_data_request) { if ((w = window_for_window_id(global_state.drop_dest.client_window_data_request))) { - char buf[3072]; - ssize_t ret = ev->read_data(window, ev, buf, sizeof(buf)); - drop_dispatch_data(w, buf, ret); - if (ret <= 0) ev->finish_drop(window, GLFW_DRAG_OPERATION_GENERIC); + if (w->drop.getting_data_for_mime && strcmp(w->drop.getting_data_for_mime, ev->mimes[0]) == 0) { + char buf[3072]; + ssize_t ret = ev->read_data(window, ev, buf, sizeof(buf)); + drop_dispatch_data(w, buf, ret); + if (ret <= 0) ev->finish_drop(window, GLFW_DRAG_OPERATION_GENERIC); + } } } else { if (!global_state.drop_dest.data) ev->finish_drop(window, GLFW_DRAG_OPERATION_GENERIC); diff --git a/kitty/screen.c b/kitty/screen.c index a912b8678..165138b06 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1519,7 +1519,8 @@ screen_handle_dnd_command(Screen *self, const DnDCommand *cmd, const uint8_t *pa case 'm': drop_set_status(w, cmd->operation, (const char*)payload, cmd->payload_sz, cmd->more); break; case 'r': { char buf[256]; - if (w && cmd->payload_sz + 1 < sizeof(buf)) { + if (!cmd->payload_sz) drop_finish(w); + else if (cmd->payload_sz + 1 < sizeof(buf)) { memcpy(buf, payload, cmd->payload_sz); buf[cmd->payload_sz] = 0; drop_request_data(w, buf); }