diff --git a/docs/dnd-protocol.rst b/docs/dnd-protocol.rst index da30f725f..796d0d8ff 100644 --- a/docs/dnd-protocol.rst +++ b/docs/dnd-protocol.rst @@ -214,7 +214,9 @@ copy, ``2`` for move and ``3`` for either. The transmission should be chunked if the list of MIME types is too long. Note that at this time the drag operation has not actually started, this gives the terminal program the opportunity to pre-send some data or set one or more images to act as -thumbnails for the drag operation. +thumbnails for the drag operation. If the list of MIME types is too long the +terminal may cancel the operation by responding with ``t=R ; EFBIG`` or ``t=R ; +ENOMEM``. If at the time the terminal receives this request the drag gesture has already been terminated or the terminal otherwise determines that it is not appropriate diff --git a/kitty/dnd.c b/kitty/dnd.c index 7168de829..ca83b3b47 100644 --- a/kitty/dnd.c +++ b/kitty/dnd.c @@ -855,7 +855,45 @@ drop_left_child(Window *w) { } } +#define ds w->drag_source + void drag_free_offer(Window *w) { - (void)w; + free(ds.mimes); ds.mimes = NULL; + free(ds.mimes_buf); ds.mimes_buf = NULL; + ds.allowed_operations = 0; + ds.offer_being_built = false; } + +void +drag_add_mimes(Window *w, int allowed_operations, const char *data, size_t sz, bool has_more) { +#define abrt(code) drop_send_error(w, code); drag_free_offer(w); return + if (allowed_operations && ds.offer_being_built) drag_free_offer(w); + if (allowed_operations && !ds.allowed_operations) ds.allowed_operations = allowed_operations; + if (!ds.allowed_operations) { abrt(EINVAL); } + ds.offer_being_built = true; + size_t new_sz = ds.bufsz + sz; + if (new_sz > 1024 * 1024) { abrt(EFBIG); } + ds.mimes = realloc(ds.mimes, ds.bufsz + sz + 1); + if (!ds.mimes) { abrt(ENOMEM); } + memcpy(ds.mimes_buf + ds.bufsz, data, sz); + ds.bufsz = new_sz; + ds.mimes_buf[ds.bufsz] = 0; + if (!has_more) { + char *ptr = ds.mimes_buf; + size_t rough_count = 0; + while ((ptr = strchr(ptr, ' ')) != NULL) { + *ptr = 0; ptr++; + rough_count++; + } + ds.mimes = calloc(rough_count + 1, sizeof(void*)); + if (!ds.mimes) { abrt(ENOMEM); } + ds.num_mimes = 0; + // TODO: Populate ds.mimes with pointers to the mime strings in + // ds.mimes_buf and set ds.num_mimes to the number of such + // strings. + } +#undef abrt +} + +#undef ds diff --git a/kitty/state.h b/kitty/state.h index 741125e48..86879b9db 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -288,6 +288,9 @@ typedef struct Window { struct { bool can_offer; struct { double x, y; monotonic_t at; } initial_left_press; + char *mimes_buf; const char **mimes; size_t num_mimes, bufsz; + int allowed_operations; + bool offer_being_built; } drag_source; } Window;