Respond to load commands when an id is present

This commit is contained in:
Kovid Goyal 2017-09-27 18:27:36 +05:30
parent 9601ed79f1
commit 9860ed544f
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 56 additions and 49 deletions

View File

@ -127,6 +127,10 @@ img_by_internal_id(GraphicsManager *self, size_t id) {
return NULL; return NULL;
} }
static char add_response[512] = {0};
static bool has_add_respose = false;
#define ABRT(...) { snprintf(add_response, (sizeof(add_response)/sizeof(add_response[0])) - 1, __VA_ARGS__); has_add_respose = true; goto err; }
static inline bool static inline bool
inflate_zlib(GraphicsManager UNUSED *self, Image *img, uint8_t *buf, size_t bufsz) { inflate_zlib(GraphicsManager UNUSED *self, Image *img, uint8_t *buf, size_t bufsz) {
bool ok = false; bool ok = false;
@ -141,18 +145,9 @@ inflate_zlib(GraphicsManager UNUSED *self, Image *img, uint8_t *buf, size_t bufs
z.avail_out = img->load_data.data_sz; z.avail_out = img->load_data.data_sz;
z.next_out = decompressed; z.next_out = decompressed;
int ret; int ret;
if ((ret = inflateInit(&z)) != Z_OK) { if ((ret = inflateInit(&z)) != Z_OK) ABRT("Failed to initialize inflate with error code: %d", ret);
REPORT_ERROR("Failed to initialize inflate with error code: %d", ret); if ((ret = inflate(&z, Z_FINISH)) != Z_STREAM_END) ABRT("Failed to inflate image data with error code: %d", ret);
goto err; if (z.avail_out) ABRT("Failed to inflate image data with error code: %d", ret);
}
if ((ret = inflate(&z, Z_FINISH)) != Z_STREAM_END) {
REPORT_ERROR("Failed to inflate image data with error code: %d", ret);
goto err;
}
if (z.avail_out) {
REPORT_ERROR("Failed to inflate image data with error code: %d", ret);
goto err;
}
free_load_data(&img->load_data); free_load_data(&img->load_data);
img->load_data.buf_capacity = img->load_data.data_sz; img->load_data.buf_capacity = img->load_data.data_sz;
img->load_data.buf = decompressed; img->load_data.buf = decompressed;
@ -238,15 +233,16 @@ err:
return ok; return ok;
#undef RE #undef RE
} }
#undef ABRT
static bool static bool
add_trim_predicate(Image *img) { add_trim_predicate(Image *img) {
return !img->data_loaded || (!img->client_id && !img->refcnt); return !img->data_loaded || (!img->client_id && !img->refcnt);
} }
static bool
static void
handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_t *payload) { handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_t *payload) {
#define ABRT(...) { snprintf(add_response, (sizeof(add_response)/sizeof(add_response[0])) - 1, __VA_ARGS__); has_add_respose = true; return false; }
bool existing, init_img = true; bool existing, init_img = true;
Image *img; Image *img;
unsigned char tt = g->transmission_type ? g->transmission_type : 'd'; unsigned char tt = g->transmission_type ? g->transmission_type : 'd';
@ -255,7 +251,7 @@ handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_
if (tt == 'd' && (g->more && self->loading_image)) init_img = false; if (tt == 'd' && (g->more && self->loading_image)) init_img = false;
if (init_img) { if (init_img) {
size_t sz = g->data_width * g->data_height; size_t sz = g->data_width * g->data_height;
if (!sz) return; // ignore images with zero size if (!sz) return false; // ignore images with zero size
remove_images(self, add_trim_predicate); remove_images(self, add_trim_predicate);
img = find_or_create_image(self, g->id, &existing); img = find_or_create_image(self, g->id, &existing);
if (existing) { if (existing) {
@ -277,8 +273,7 @@ handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_
img->load_data.is_4byte_aligned = fmt == RGBA || (img->width % 4 == 0); img->load_data.is_4byte_aligned = fmt == RGBA || (img->width % 4 == 0);
break; break;
default: default:
REPORT_ERROR("Unknown image format: %u", fmt); ABRT("Unknown image format: %u", fmt);
return;
} }
img->load_data.data_sz = sz; img->load_data.data_sz = sz;
if (tt == 'd') { if (tt == 'd') {
@ -292,16 +287,14 @@ handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_
img = img_by_internal_id(self, self->loading_image); img = img_by_internal_id(self, self->loading_image);
if (img == NULL) { if (img == NULL) {
self->loading_image = 0; self->loading_image = 0;
REPORT_ERROR("%s", "More payload loading refers to non-existent image"); ABRT("%s", "More payload loading refers to non-existent image");
return;
} }
} }
int fd; int fd;
switch(tt) { switch(tt) {
case 'd': // direct case 'd': // direct
if (g->payload_sz >= img->load_data.buf_capacity - img->load_data.buf_used) { if (g->payload_sz >= img->load_data.buf_capacity - img->load_data.buf_used) {
REPORT_ERROR("%s", "Too much data transmitted"); ABRT("%s", "Too much data transmitted");
return;
} }
memcpy(img->load_data.buf + img->load_data.buf_used, payload, g->payload_sz); memcpy(img->load_data.buf + img->load_data.buf_used, payload, g->payload_sz);
img->load_data.buf_used += g->payload_sz; img->load_data.buf_used += g->payload_sz;
@ -313,8 +306,7 @@ handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_
if (tt == 's') fd = shm_open((const char*)payload, O_RDONLY, 0); if (tt == 's') fd = shm_open((const char*)payload, O_RDONLY, 0);
else fd = open((const char*)payload, O_CLOEXEC | O_RDONLY); else fd = open((const char*)payload, O_CLOEXEC | O_RDONLY);
if (fd == -1) { if (fd == -1) {
REPORT_ERROR("Failed to open file for graphics transmission with error: [%d] %s", errno, strerror(errno)); ABRT("Failed to open file for graphics transmission with error: [%d] %s", errno, strerror(errno));
return;
} }
img->load_data.fd = fd; img->load_data.fd = fd;
img->data_loaded = mmap_img_file(self, img); img->data_loaded = mmap_img_file(self, img);
@ -322,10 +314,9 @@ handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_
else if (tt == 's') shm_unlink((const char*)payload); else if (tt == 's') shm_unlink((const char*)payload);
break; break;
default: default:
REPORT_ERROR("Unknown transmission type: %c", g->transmission_type); ABRT("Unknown transmission type: %c", g->transmission_type);
return;
} }
if (!img->data_loaded) return; if (!img->data_loaded) return false;
bool needs_processing = g->compressed || fmt == PNG; bool needs_processing = g->compressed || fmt == PNG;
if (needs_processing) { if (needs_processing) {
uint8_t *buf; size_t bufsz; uint8_t *buf; size_t bufsz;
@ -334,20 +325,20 @@ handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_
case 'z': case 'z':
IB; IB;
if (!inflate_zlib(self, img, buf, bufsz)) { if (!inflate_zlib(self, img, buf, bufsz)) {
img->data_loaded = false; return; img->data_loaded = false; return false;
} }
break; break;
case 0: case 0:
break; break;
default: default:
REPORT_ERROR("Unknown image compression: %c", g->compressed); ABRT("Unknown image compression: %c", g->compressed);
img->data_loaded = false; return; img->data_loaded = false; return false;
} }
switch(fmt) { switch(fmt) {
case PNG: case PNG:
IB; IB;
if (!inflate_png(self, img, buf, bufsz)) { if (!inflate_png(self, img, buf, bufsz)) {
img->data_loaded = false; return; img->data_loaded = false; return false;
} }
break; break;
default: break; default: break;
@ -355,35 +346,50 @@ handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_
#undef IB #undef IB
img->load_data.data = img->load_data.buf; img->load_data.data = img->load_data.buf;
if (img->load_data.buf_used < img->load_data.data_sz) { if (img->load_data.buf_used < img->load_data.data_sz) {
REPORT_ERROR("Insufficient image data: %zu < %zu", img->load_data.buf_used, img->load_data.data_sz); ABRT("Insufficient image data: %zu < %zu", img->load_data.buf_used, img->load_data.data_sz);
img->data_loaded = false; img->data_loaded = false;
} }
} else { } else {
if (tt == 'd') { if (tt == 'd') {
if (img->load_data.buf_used < img->load_data.data_sz) { if (img->load_data.buf_used < img->load_data.data_sz) {
REPORT_ERROR("Insufficient image data: %zu < %zu", img->load_data.buf_used, img->load_data.data_sz); ABRT("Insufficient image data: %zu < %zu", img->load_data.buf_used, img->load_data.data_sz);
img->data_loaded = false; img->data_loaded = false;
} else img->load_data.data = img->load_data.buf; } else img->load_data.data = img->load_data.buf;
} else { } else {
if (img->load_data.mapped_file_sz < img->load_data.data_sz) { if (img->load_data.mapped_file_sz < img->load_data.data_sz) {
REPORT_ERROR("Insufficient image data: %zu < %zu", img->load_data.mapped_file_sz, img->load_data.data_sz); ABRT("Insufficient image data: %zu < %zu", img->load_data.mapped_file_sz, img->load_data.data_sz);
img->data_loaded = false; img->data_loaded = false;
} else img->load_data.data = img->load_data.mapped_file; } else img->load_data.data = img->load_data.mapped_file;
} }
} }
return img->data_loaded;
#undef ABRT
} }
void const char*
grman_handle_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_t *payload) { grman_handle_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_t *payload) {
static char rbuf[sizeof(add_response)/sizeof(add_response[0])];
bool data_loaded;
switch(g->action) { switch(g->action) {
case 0: case 0:
case 't': case 't':
handle_add_command(self, g, payload); has_add_respose = false;
data_loaded = handle_add_command(self, g, payload);
if (g->id) {
if (!has_add_respose) {
if (!data_loaded) break;
snprintf(add_response, 10, "OK");
}
snprintf(rbuf, sizeof(rbuf)/sizeof(rbuf[0]) - 1, "\033_Gq=%u;%s\033\\", g->id, add_response);
return rbuf;
}
break; break;
default: default:
REPORT_ERROR("Unknown graphics command action: %c", g->action); REPORT_ERROR("Unknown graphics command action: %c", g->action);
break; break;
} }
return NULL;
} }
void void

View File

@ -50,4 +50,4 @@ PyTypeObject GraphicsManager_Type;
GraphicsManager* grman_realloc(GraphicsManager *, index_type lines, index_type columns); GraphicsManager* grman_realloc(GraphicsManager *, index_type lines, index_type columns);
void grman_clear(GraphicsManager*); void grman_clear(GraphicsManager*);
GraphicsManager* grman_free(GraphicsManager*); GraphicsManager* grman_free(GraphicsManager*);
void grman_handle_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_t *payload); const char* grman_handle_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_t *payload);

View File

@ -409,9 +409,18 @@ END_ALLOW_CASE_RANGE
} }
} }
static inline void
write_to_child(Screen *self, const char *data, size_t sz) {
if (self->window_id) schedule_write_to_child(self->window_id, data, sz);
if (self->test_child != Py_None) { PyObject *r = PyObject_CallMethod(self->test_child, "write", "y#", data, sz); if (r == NULL) PyErr_Print(); Py_CLEAR(r); }
}
#define write_str_to_child(s) write_to_child(self, (s), sizeof((s)) - 1)
void void
screen_handle_graphics_command(Screen *self, const GraphicsCommand *cmd, const uint8_t *payload) { screen_handle_graphics_command(Screen *self, const GraphicsCommand *cmd, const uint8_t *payload) {
grman_handle_command(self->grman, cmd, payload); const char *response = grman_handle_command(self->grman, cmd, payload);
if (response != NULL) write_to_child(self, response, strlen(response));
} }
// }}} // }}}
@ -973,14 +982,6 @@ screen_bell(Screen UNUSED *self) {
request_window_attention(); request_window_attention();
} }
static inline void
write_to_child(Screen *self, const char *data, size_t sz) {
if (self->window_id) schedule_write_to_child(self->window_id, data, sz);
if (self->test_child != Py_None) { PyObject *r = PyObject_CallMethod(self->test_child, "write", "y#", data, sz); if (r == NULL) PyErr_Print(); Py_CLEAR(r); }
}
#define write_str_to_child(s) write_to_child(self, (s), sizeof((s)) - 1)
void void
report_device_attributes(Screen *self, unsigned int mode, char start_modifier) { report_device_attributes(Screen *self, unsigned int mode, char start_modifier) {
if (mode == 0) { if (mode == 0) {

View File

@ -218,10 +218,10 @@ escape code will look like:
``` ```
Here the `q` value will be the same as was sent by the client in the original Here the `q` value will be the same as was sent by the client in the original
request. The payload data will be a base-64 encoded UTF-8 string. The string request. The payload data will be a ASCII encoded string containing only
will be `OK` if reading the pixel data succeeded or an error message. Clients printable characters and spaces. The string will be `OK` if reading the pixel
can set the width and height to zero to avoid actually drawing anything on data succeeded or an error message. Clients can set the width and height to
screen during the test. zero to avoid actually drawing anything on screen during the test.
===== Remote client ===== Remote client