aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar nyorain <nyorain@gmail.com>2017-07-11 17:07:04 +0200
committerLibravatar nyorain <nyorain@gmail.com>2017-07-11 17:07:06 +0200
commit727215c90754a8c20d1a5b78d8c4194f885178b9 (patch)
tree81c432e536aa0d0d56d454ba878a5b5bf27a0eef
parentSignal base64 in clipboard type; Reimplement loop (diff)
downloadsway-727215c90754a8c20d1a5b78d8c4194f885178b9.tar.gz
sway-727215c90754a8c20d1a5b78d8c4194f885178b9.tar.zst
sway-727215c90754a8c20d1a5b78d8c4194f885178b9.zip
Add timeout; Fix receive loop & style issues
-rw-r--r--sway/ipc-server.c196
1 files changed, 114 insertions, 82 deletions
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index ae758883..937382af 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -59,9 +59,13 @@ struct get_pixels_request {
59struct get_clipboard_request { 59struct get_clipboard_request {
60 struct ipc_client *client; 60 struct ipc_client *client;
61 json_object *json; 61 json_object *json;
62 struct wlc_event_source *event_source; 62 struct wlc_event_source *fd_event_source;
63 struct wlc_event_source *timer_event_source;
63 char *type; 64 char *type;
64 unsigned int *pending; 65 unsigned int *pending;
66 char *buf;
67 size_t buf_size;
68 size_t buf_position;
65}; 69};
66 70
67struct sockaddr_un *ipc_user_sockaddr(void); 71struct sockaddr_un *ipc_user_sockaddr(void);
@@ -339,54 +343,69 @@ static bool is_text_target(const char *target) {
339 || strcmp(target, "COMPOUND_TEXT") == 0); 343 || strcmp(target, "COMPOUND_TEXT") == 0);
340} 344}
341 345
346static void release_clipboard_request(struct get_clipboard_request *req) {
347 if (--(*req->pending) == 0) {
348 const char *str = json_object_to_json_string(req->json);
349 ipc_send_reply(req->client, str, (uint32_t)strlen(str));
350 json_object_put(req->json);
351 }
352
353 free(req->type);
354 free(req->buf);
355 wlc_event_source_remove(req->fd_event_source);
356 wlc_event_source_remove(req->timer_event_source);
357 free(req);
358}
359
342static int ipc_selection_data_cb(int fd, uint32_t mask, void *data) { 360static int ipc_selection_data_cb(int fd, uint32_t mask, void *data) {
343 assert(data); 361 assert(data);
344 struct get_clipboard_request *req = (struct get_clipboard_request *)data; 362 struct get_clipboard_request *req = (struct get_clipboard_request *)data;
345 363
346 if (mask & WLC_EVENT_ERROR) { 364 if (mask & WLC_EVENT_ERROR) {
347 sway_log(L_ERROR, "Selection data fd error"); 365 sway_log(L_ERROR, "Selection data fd error");
348 goto cleanup; 366 goto release;
349 } 367 }
350 368
351 if (mask & WLC_EVENT_READABLE) { 369 if (mask & WLC_EVENT_READABLE) {
352 static const int max_size = 8192 * 1000; 370 static const unsigned int max_size = 8192 * 1024;
353 int len = 512; 371 int amt = 0;
354 int i = 0; 372
355 char *buf = malloc(len); 373 do {
356 374 int size = req->buf_size - req->buf_position;
357 // read data as long as there is data avilable 375 int amt = read(fd, req->buf + req->buf_position, size - 1);
358 // grow the buffer step_size in every iteration 376 if (amt < 0) {
359 for(;;) { 377 if (errno == EAGAIN) {
360 int amt = read(fd, buf + i, len - i - 1); 378 return 0;
361 if (amt <= 0) 379 }
362 break; 380
363 381 sway_log_errno(L_INFO, "Failed to read from clipboard data fd");
364 i += amt; 382 goto release;
365 if (i >= len - 1) { 383 }
366 if (len >= max_size) { 384
367 sway_log(L_ERROR, "selection data too large"); 385 req->buf_position += amt;
368 free(buf); 386 if (req->buf_position >= req->buf_size - 1) {
369 goto cleanup; 387 if (req->buf_size >= max_size) {
388 sway_log(L_ERROR, "get_clipbard: selection data too large");
389 goto release;
370 } 390 }
371 char *next = realloc(buf, (len *= 2)); 391 char *next = realloc(req->buf, req->buf_size *= 2);
372 if (!next) { 392 if (!next) {
373 sway_log_errno(L_ERROR, "relloc failed"); 393 sway_log_errno(L_ERROR, "get_clipboard: realloc data buffer failed");
374 free(buf); 394 goto release;
375 goto cleanup;
376 } 395 }
377 396
378 buf = next; 397 req->buf = next;
379 } 398 }
380 } 399 } while(amt != 0);
381 400
382 buf[i] = '\0'; 401 req->buf[req->buf_position] = '\0';
383 402
384 if (is_text_target(req->type)) { 403 if (is_text_target(req->type)) {
385 json_object_object_add(req->json, req->type, 404 json_object_object_add(req->json, req->type,
386 json_object_new_string(buf)); 405 json_object_new_string(req->buf));
387 } else { 406 } else {
388 size_t outlen; 407 size_t outlen;
389 char *b64 = b64_encode(buf, i, &outlen); 408 char *b64 = b64_encode(req->buf, req->buf_position, &outlen);
390 char *type = malloc(strlen(req->type) + 8); 409 char *type = malloc(strlen(req->type) + 8);
391 strcat(type, ";base64"); 410 strcat(type, ";base64");
392 json_object_object_add(req->json, type, 411 json_object_object_add(req->json, type,
@@ -394,22 +413,19 @@ static int ipc_selection_data_cb(int fd, uint32_t mask, void *data) {
394 free(type); 413 free(type);
395 free(b64); 414 free(b64);
396 } 415 }
397
398 free(buf);
399 } 416 }
400 417
401cleanup: 418release:
402 close(fd); 419 release_clipboard_request(req);
420 return 0;
421}
403 422
404 if (--(*req->pending) == 0) { 423static int ipc_selection_timer_cb(void *data) {
405 const char *str = json_object_to_json_string(req->json); 424 assert(data);
406 ipc_send_reply(req->client, str, (uint32_t)strlen(str)); 425 struct get_clipboard_request *req = (struct get_clipboard_request *)data;
407 json_object_put(req->json);
408 }
409 426
410 free(req->type); 427 sway_log(L_INFO, "get_clipbard: timeout for type %s", req->type);
411 wlc_event_source_remove(req->event_source); 428 release_clipboard_request(req);
412 free(req);
413 return 0; 429 return 0;
414} 430}
415 431
@@ -471,53 +487,69 @@ void ipc_get_clipboard(struct ipc_client *client, char *buf) {
471 const char *pattern = requested->items[l]; 487 const char *pattern = requested->items[l];
472 bool found = false; 488 bool found = false;
473 for (size_t i = 0; i < size; ++i) { 489 for (size_t i = 0; i < size; ++i) {
474 if (mime_type_matches(types[i], pattern)) { 490 if (!mime_type_matches(types[i], pattern)) {
475 found = true; 491 continue;
492 }
476 493
477 struct get_clipboard_request *req = malloc(sizeof(*req)); 494 found = true;
478 if (!req) {
479 sway_log(L_ERROR, "Cannot allocate get_clipboard_request");
480 goto data_error;
481 }
482 495
483 int pipes[2]; 496 struct get_clipboard_request *req = malloc(sizeof(*req));
484 if (pipe(pipes) == -1) { 497 if (!req) {
485 sway_log_errno(L_ERROR, "pipe call failed"); 498 sway_log(L_ERROR, "get_clipboard: request malloc failed");
486 free(req); 499 goto data_error;
487 goto data_error; 500 }
488 }
489 501
490 fcntl(pipes[0], F_SETFD, FD_CLOEXEC | O_NONBLOCK); 502 int pipes[2];
491 fcntl(pipes[1], F_SETFD, FD_CLOEXEC | O_NONBLOCK); 503 if (pipe(pipes) == -1) {
504 sway_log_errno(L_ERROR, "get_clipboard: pipe call failed");
505 free(req);
506 goto data_error;
507 }
492 508
493 if (!wlc_get_selection_data(types[i], pipes[1])) { 509 fcntl(pipes[0], F_SETFD, FD_CLOEXEC | O_NONBLOCK);
494 close(pipes[0]); 510 fcntl(pipes[1], F_SETFD, FD_CLOEXEC | O_NONBLOCK);
495 close(pipes[1]); 511
496 free(req); 512 if (!wlc_get_selection_data(types[i], pipes[1])) {
497 sway_log(L_ERROR, "wlc_get_selection_data failed"); 513 close(pipes[0]);
498 goto data_error; 514 close(pipes[1]);
499 } 515 free(req);
516 sway_log(L_ERROR, "get_clipboard: failed to retrieve "
517 "selection data");
518 goto data_error;
519 }
500 520
501 (*pending)++; 521 if (!(req->buf = malloc(512))) {
502 522 close(pipes[0]);
503 req->client = client; 523 close(pipes[1]);
504 req->type = strdup(types[i]); 524 free(req);
505 req->json = json; 525 sway_log_errno(L_ERROR, "get_clipboard: buf malloc failed");
506 req->pending = pending; 526 goto data_error;
507 req->event_source = wlc_event_loop_add_fd(pipes[0],
508 WLC_EVENT_READABLE | WLC_EVENT_ERROR | WLC_EVENT_HANGUP,
509 &ipc_selection_data_cb, req);
510
511 // NOTE: remove this goto to enable retrieving multiple
512 // targets at once. The whole implementation is already
513 // made for it. The only reason it was disabled
514 // at the time of writing is that neither wlc's xselection
515 // implementation nor (apparently) gtk on wayland supports
516 // multiple send requests at the same time which makes
517 // every request except the last one fail (and therefore
518 // return empty data)
519 goto cleanup;
520 } 527 }
528
529 (*pending)++;
530
531 req->client = client;
532 req->type = strdup(types[i]);
533 req->json = json;
534 req->pending = pending;
535 req->buf_position = 0;
536 req->buf_size = 512;
537 req->timer_event_source = wlc_event_loop_add_timer(ipc_selection_timer_cb, req);
538 req->fd_event_source = wlc_event_loop_add_fd(pipes[0],
539 WLC_EVENT_READABLE | WLC_EVENT_ERROR | WLC_EVENT_HANGUP,
540 &ipc_selection_data_cb, req);
541
542 wlc_event_source_timer_update(req->timer_event_source, 1000);
543
544 // NOTE: remove this goto to enable retrieving multiple
545 // targets at once. The whole implementation is already
546 // made for it. The only reason it was disabled
547 // at the time of writing is that neither wlc's xselection
548 // implementation nor (apparently) gtk on wayland supports
549 // multiple send requests at the same time which makes
550 // every request except the last one fail (and therefore
551 // return empty data)
552 goto cleanup;
521 } 553 }
522 554
523 if (!found) { 555 if (!found) {