Accumulate DnD image data
This commit is contained in:
parent
950497ac0c
commit
0fcbd265b6
5 changed files with 55 additions and 16 deletions
|
|
@ -265,8 +265,9 @@ operation, it indicates the drag should be started by sending ``t=P:x=-1``. At
|
|||
this time if the user has already cancelled the drag or the terminal determines
|
||||
the drag operation is not allowed, it must respond with ``t=R ; EPERM``. If any
|
||||
other error occurs starting the drag operation, it must respond with the appropriate
|
||||
POSIX error code. If the drag operation is successfully started, it must respond with
|
||||
``t=R ; OK``.
|
||||
POSIX error code. If it determines that the image data after conversion to
|
||||
display format is too large, it must respond with ``t=R ; EFBIG``. If the drag
|
||||
operation is successfully started, it must respond with ``t=R ; OK``.
|
||||
|
||||
Multiplexers
|
||||
-----------------
|
||||
|
|
|
|||
59
kitty/dnd.c
59
kitty/dnd.c
|
|
@ -18,6 +18,7 @@
|
|||
#include <errno.h>
|
||||
|
||||
static const size_t MIME_LIST_SIZE_CAP = 1024 * 1024;
|
||||
static const size_t PRESENT_DATA_CAP = 64 * 1024 * 1024;
|
||||
|
||||
// In test mode, this callable is invoked instead of schedule_write_to_child_if_possible.
|
||||
// It receives (window_id: int, data: bytes) and its return value is ignored.
|
||||
|
|
@ -869,8 +870,13 @@ drag_free_offer(Window *w) {
|
|||
for (size_t i=0; i < ds.num_mimes; i++) free(ds.items[i].optional_data);
|
||||
free(ds.items);
|
||||
}
|
||||
for (size_t i = 0; i < arraysz(ds.images); i++) {
|
||||
if (ds.images[i].data) free(ds.images[i].data);
|
||||
zero_at_ptr(ds.images + i);
|
||||
}
|
||||
ds.num_mimes = 0;
|
||||
ds.pre_sent_total_sz = 0;
|
||||
ds.images_sent_total_sz = 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -912,22 +918,49 @@ drag_add_mimes(Window *w, int allowed_operations, const char *data, size_t sz, b
|
|||
void
|
||||
drag_add_pre_sent_data(Window *w, unsigned idx, const uint8_t *payload, size_t sz) {
|
||||
if (!ds.offer_being_built || idx >= ds.num_mimes) abrt(EINVAL);
|
||||
if (sz + ds.pre_sent_total_sz > 64 * 1024 * 1024) abrt(EFBIG);
|
||||
if (sz + ds.pre_sent_total_sz > PRESENT_DATA_CAP) abrt(EFBIG);
|
||||
ds.pre_sent_total_sz += sz;
|
||||
DragSourceItem *item = ds.items + idx;
|
||||
if (!item->data_decode_initialized) {
|
||||
item->data_decode_initialized = true;
|
||||
base64_init_stream_decoder(&item->base64_state);
|
||||
#define item ds.items[idx]
|
||||
if (!item.data_decode_initialized) {
|
||||
item.data_decode_initialized = true;
|
||||
base64_init_stream_decoder(&item.base64_state);
|
||||
}
|
||||
if (item->data_capacity < sz + item->data_size) {
|
||||
size_t newcap = MAX(item->data_size * 2, sz + item->data_size);
|
||||
item->optional_data = realloc(item->optional_data, newcap);
|
||||
if (!item->optional_data) abrt(ENOMEM);
|
||||
item->data_capacity = newcap;
|
||||
if (item.data_capacity < sz + item.data_size) {
|
||||
size_t newcap = MAX(item.data_size * 2, sz + item.data_size);
|
||||
item.optional_data = realloc(item.optional_data, newcap);
|
||||
if (!item.optional_data) abrt(ENOMEM);
|
||||
item.data_capacity = newcap;
|
||||
}
|
||||
size_t outlen = item->data_capacity - item->data_size;
|
||||
if (!base64_decode_stream(&item->base64_state, payload, sz, item->optional_data + item->data_size, &outlen)) abrt(EINVAL);
|
||||
item->data_size += outlen;
|
||||
size_t outlen = item.data_capacity - item.data_size;
|
||||
if (!base64_decode_stream(&item.base64_state, payload, sz, item.optional_data + item.data_size, &outlen)) abrt(EINVAL);
|
||||
item.data_size += outlen;
|
||||
#undef item
|
||||
}
|
||||
|
||||
void
|
||||
drag_add_image(Window *w, unsigned idx, int fmt, int width, int height, const uint8_t *payload, size_t sz) {
|
||||
if (idx + 1 >= arraysz(ds.images)) abrt(EFBIG);
|
||||
if (ds.images_sent_total_sz + sz > PRESENT_DATA_CAP) abrt(EFBIG);
|
||||
ds.images_sent_total_sz += sz;
|
||||
#define img ds.images[idx]
|
||||
if (!img.started) {
|
||||
if (fmt != 24 && fmt != 32 && fmt != 100) abrt(EINVAL);
|
||||
if (width < 1 || height < 1) abrt(EINVAL);
|
||||
img.started = true;
|
||||
img.width = width; img.height = height;
|
||||
img.fmt = fmt;
|
||||
base64_init_stream_decoder(&img.base64_state);
|
||||
}
|
||||
if (img.capacity < sz + img.sz) {
|
||||
size_t newcap = MAX(img.sz * 2, sz + img.sz);
|
||||
img.data = realloc(img.data, newcap);
|
||||
if (!img.data) abrt(ENOMEM);
|
||||
img.capacity = newcap;
|
||||
}
|
||||
size_t outlen = img.capacity - img.sz;
|
||||
if (!base64_decode_stream(&img.base64_state, payload, sz, img.data + img.sz, &outlen)) abrt(EINVAL);
|
||||
img.sz += outlen;
|
||||
#undef img
|
||||
}
|
||||
|
||||
#undef abrt
|
||||
|
|
|
|||
|
|
@ -26,3 +26,4 @@ void dnd_set_test_write_func(PyObject *func);
|
|||
void drag_free_offer(Window *w);
|
||||
void drag_add_mimes(Window *w, int allowed_operations, const char *data, size_t sz, bool has_more);
|
||||
void drag_add_pre_sent_data(Window *w, unsigned idx, const uint8_t *payload, size_t sz);
|
||||
void drag_add_image(Window *w, unsigned idx_, int fmt, int width, int height, const uint8_t *payload, size_t sz);
|
||||
|
|
|
|||
|
|
@ -1550,6 +1550,7 @@ screen_handle_dnd_command(Screen *self, const DnDCommand *cmd, const uint8_t *pa
|
|||
} break;
|
||||
case 'p': {
|
||||
if (cmd->cell_x >= 0) drag_add_pre_sent_data(w, cmd->cell_x, payload, cmd->payload_sz);
|
||||
else drag_add_image(w, -cmd->cell_x, cmd->cell_y, cmd->pixel_x, cmd->pixel_y, payload, cmd->payload_sz);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -299,7 +299,10 @@ typedef struct Window {
|
|||
struct { double x, y; monotonic_t at; } initial_left_press;
|
||||
char *mimes_buf; size_t num_mimes, bufsz;
|
||||
DragSourceItem *items;
|
||||
size_t pre_sent_total_sz;
|
||||
struct {
|
||||
int width, height, fmt; uint8_t *data; size_t sz, capacity; bool started; base64_state base64_state;
|
||||
} images[16];
|
||||
size_t pre_sent_total_sz, images_sent_total_sz;
|
||||
int allowed_operations;
|
||||
bool offer_being_built;
|
||||
} drag_source;
|
||||
|
|
|
|||
Loading…
Reference in a new issue