summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Brian Ashworth <bosrsf04@gmail.com>2018-11-28 11:19:18 -0500
committerLibravatar Brian Ashworth <bosrsf04@gmail.com>2018-11-28 11:19:18 -0500
commitbf9a52bab0f8ae9b4ace43c7d9c75ece0c76b562 (patch)
tree812af4f8fee1f289bc244136ac21acca44de15b0
parentMerge pull request #3211 from emersion/child-view-unmapped-segfault (diff)
downloadsway-bf9a52bab0f8ae9b4ace43c7d9c75ece0c76b562.tar.gz
sway-bf9a52bab0f8ae9b4ace43c7d9c75ece0c76b562.tar.zst
sway-bf9a52bab0f8ae9b4ace43c7d9c75ece0c76b562.zip
Implement support for swaymsg -t SUBSCRIBE [-m]
In `i3 4.16`, `i3-msg` can be used with the message type `subscribe` and has the ability to monitor for responses until killed. This adds support for both to swaymsg. If the JSON array of event types is malformed or contains an invalid event, sway will send a response with `success` set to `false`. If swaymsg sees this, it will not display the failure and exit. If the `subscribe` event is successful, swaymsg will wait for the first response and display that instead of the success message. If `-m/--monitor` is given, swaymsg will continue monitor for responses until killed or a malformed response is received. For the `subscribe` event, the responses will always be printed as JSON. If `-r/--raw` is given, the JSON will not be pretty printed, which may be preferred when monitoring due to there being multiple responses. Example: `swaymsg -t SUBSCRIBE -m "['window']"`
-rw-r--r--sway/ipc-server.c13
-rw-r--r--swaymsg/main.c70
-rw-r--r--swaymsg/swaymsg.1.scd11
3 files changed, 76 insertions, 18 deletions
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 95433d97..e3d73522 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -668,7 +668,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
668 // TODO: Check if they're permitted to use these events 668 // TODO: Check if they're permitted to use these events
669 struct json_object *request = json_tokener_parse(buf); 669 struct json_object *request = json_tokener_parse(buf);
670 if (request == NULL) { 670 if (request == NULL) {
671 client_valid = ipc_send_reply(client, "{\"success\": false}", 18); 671 const char msg[] = "[{\"success\": false}]";
672 client_valid = ipc_send_reply(client, msg, strlen(msg));
672 wlr_log(WLR_INFO, "Failed to parse subscribe request"); 673 wlr_log(WLR_INFO, "Failed to parse subscribe request");
673 goto exit_cleanup; 674 goto exit_cleanup;
674 } 675 }
@@ -695,8 +696,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
695 client->subscribed_events |= event_mask(IPC_EVENT_TICK); 696 client->subscribed_events |= event_mask(IPC_EVENT_TICK);
696 is_tick = true; 697 is_tick = true;
697 } else { 698 } else {
698 client_valid = 699 const char msg[] = "[{\"success\": false}]";
699 ipc_send_reply(client, "{\"success\": false}", 18); 700 client_valid = ipc_send_reply(client, msg, strlen(msg));
700 json_object_put(request); 701 json_object_put(request);
701 wlr_log(WLR_INFO, "Unsupported event type in subscribe request"); 702 wlr_log(WLR_INFO, "Unsupported event type in subscribe request");
702 goto exit_cleanup; 703 goto exit_cleanup;
@@ -704,10 +705,12 @@ void ipc_client_handle_command(struct ipc_client *client) {
704 } 705 }
705 706
706 json_object_put(request); 707 json_object_put(request);
707 client_valid = ipc_send_reply(client, "{\"success\": true}", 17); 708 const char msg[] = "[{\"success\": true}]";
709 client_valid = ipc_send_reply(client, msg, strlen(msg));
708 if (is_tick) { 710 if (is_tick) {
709 client->current_command = IPC_EVENT_TICK; 711 client->current_command = IPC_EVENT_TICK;
710 ipc_send_reply(client, "{\"first\": true, \"payload\": \"\"}", 30); 712 const char tickmsg[] = "{\"first\": true, \"payload\": \"\"}";
713 ipc_send_reply(client, tickmsg, strlen(tickmsg));
711 } 714 }
712 goto exit_cleanup; 715 goto exit_cleanup;
713 } 716 }
diff --git a/swaymsg/main.c b/swaymsg/main.c
index e640cadf..3e61b94a 100644
--- a/swaymsg/main.c
+++ b/swaymsg/main.c
@@ -305,8 +305,9 @@ static void pretty_print(int type, json_object *resp) {
305} 305}
306 306
307int main(int argc, char **argv) { 307int main(int argc, char **argv) {
308 static int quiet = 0; 308 static bool quiet = false;
309 static int raw = 0; 309 static bool raw = false;
310 static bool monitor = false;
310 char *socket_path = NULL; 311 char *socket_path = NULL;
311 char *cmdtype = NULL; 312 char *cmdtype = NULL;
312 313
@@ -314,6 +315,7 @@ int main(int argc, char **argv) {
314 315
315 static struct option long_options[] = { 316 static struct option long_options[] = {
316 {"help", no_argument, NULL, 'h'}, 317 {"help", no_argument, NULL, 'h'},
318 {"monitor", no_argument, NULL, 'm'},
317 {"quiet", no_argument, NULL, 'q'}, 319 {"quiet", no_argument, NULL, 'q'},
318 {"raw", no_argument, NULL, 'r'}, 320 {"raw", no_argument, NULL, 'r'},
319 {"socket", required_argument, NULL, 's'}, 321 {"socket", required_argument, NULL, 's'},
@@ -326,6 +328,7 @@ int main(int argc, char **argv) {
326 "Usage: swaymsg [options] [message]\n" 328 "Usage: swaymsg [options] [message]\n"
327 "\n" 329 "\n"
328 " -h, --help Show help message and quit.\n" 330 " -h, --help Show help message and quit.\n"
331 " -m, --monitor Monitor until killed (-t SUBSCRIBE only)\n"
329 " -q, --quiet Be quiet.\n" 332 " -q, --quiet Be quiet.\n"
330 " -r, --raw Use raw output even if using a tty\n" 333 " -r, --raw Use raw output even if using a tty\n"
331 " -s, --socket <socket> Use the specified socket.\n" 334 " -s, --socket <socket> Use the specified socket.\n"
@@ -337,16 +340,19 @@ int main(int argc, char **argv) {
337 int c; 340 int c;
338 while (1) { 341 while (1) {
339 int option_index = 0; 342 int option_index = 0;
340 c = getopt_long(argc, argv, "hqrs:t:v", long_options, &option_index); 343 c = getopt_long(argc, argv, "hmqrs:t:v", long_options, &option_index);
341 if (c == -1) { 344 if (c == -1) {
342 break; 345 break;
343 } 346 }
344 switch (c) { 347 switch (c) {
348 case 'm': // Monitor
349 monitor = true;
350 break;
345 case 'q': // Quiet 351 case 'q': // Quiet
346 quiet = 1; 352 quiet = true;
347 break; 353 break;
348 case 'r': // Raw 354 case 'r': // Raw
349 raw = 1; 355 raw = true;
350 break; 356 break;
351 case 's': // Socket 357 case 's': // Socket
352 socket_path = strdup(optarg); 358 socket_path = strdup(optarg);
@@ -400,12 +406,20 @@ int main(int argc, char **argv) {
400 type = IPC_GET_CONFIG; 406 type = IPC_GET_CONFIG;
401 } else if (strcasecmp(cmdtype, "send_tick") == 0) { 407 } else if (strcasecmp(cmdtype, "send_tick") == 0) {
402 type = IPC_SEND_TICK; 408 type = IPC_SEND_TICK;
409 } else if (strcasecmp(cmdtype, "subscribe") == 0) {
410 type = IPC_SUBSCRIBE;
403 } else { 411 } else {
404 sway_abort("Unknown message type %s", cmdtype); 412 sway_abort("Unknown message type %s", cmdtype);
405 } 413 }
406 414
407 free(cmdtype); 415 free(cmdtype);
408 416
417 if (monitor && type != IPC_SUBSCRIBE) {
418 wlr_log(WLR_ERROR, "Monitor can only be used with -t SUBSCRIBE");
419 free(socket_path);
420 return 1;
421 }
422
409 char *command = NULL; 423 char *command = NULL;
410 if (optind < argc) { 424 if (optind < argc) {
411 command = join_args(argv + optind, argc - optind); 425 command = join_args(argv + optind, argc - optind);
@@ -422,26 +436,56 @@ int main(int argc, char **argv) {
422 json_object *obj = json_tokener_parse(resp); 436 json_object *obj = json_tokener_parse(resp);
423 437
424 if (obj == NULL) { 438 if (obj == NULL) {
425 fprintf(stderr, "ERROR: Could not parse json response from ipc. This is a bug in sway."); 439 fprintf(stderr, "ERROR: Could not parse json response from ipc. "
440 "This is a bug in sway.");
426 printf("%s\n", resp); 441 printf("%s\n", resp);
427 ret = 1; 442 ret = 1;
428 } else { 443 } else {
429 if (!success(obj, true)) { 444 if (!success(obj, true)) {
430 ret = 1; 445 ret = 1;
431 } 446 }
432 if (raw) { 447 if (type != IPC_SUBSCRIBE || ret != 0) {
433 printf("%s\n", json_object_to_json_string_ext(obj, 448 if (raw) {
434 JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED)); 449 printf("%s\n", json_object_to_json_string_ext(obj,
435 } else { 450 JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED));
436 pretty_print(type, obj); 451 } else {
452 pretty_print(type, obj);
453 }
437 } 454 }
438 json_object_put(obj); 455 json_object_put(obj);
439 } 456 }
440 } 457 }
441 close(socketfd);
442
443 free(command); 458 free(command);
444 free(resp); 459 free(resp);
460
461 if (type == IPC_SUBSCRIBE && ret == 0) {
462 do {
463 struct ipc_response *reply = ipc_recv_response(socketfd);
464 if (!reply) {
465 break;
466 }
467
468 json_object *obj = json_tokener_parse(reply->payload);
469 if (obj == NULL) {
470 fprintf(stderr, "ERROR: Could not parse json response from ipc"
471 ". This is a bug in sway.");
472 ret = 1;
473 break;
474 } else {
475 if (raw) {
476 printf("%s\n", json_object_to_json_string(obj));
477 } else {
478 printf("%s\n", json_object_to_json_string_ext(obj,
479 JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED));
480 }
481 json_object_put(obj);
482 }
483
484 free_ipc_response(reply);
485 } while (monitor);
486 }
487
488 close(socketfd);
445 free(socket_path); 489 free(socket_path);
446 return ret; 490 return ret;
447} 491}
diff --git a/swaymsg/swaymsg.1.scd b/swaymsg/swaymsg.1.scd
index eaac8105..f55f86a9 100644
--- a/swaymsg/swaymsg.1.scd
+++ b/swaymsg/swaymsg.1.scd
@@ -13,6 +13,12 @@ _swaymsg_ [options...] [message]
13*-h, --help* 13*-h, --help*
14 Show help message and quit. 14 Show help message and quit.
15 15
16*-m, --monitor*
17 Monitor for responses until killed instead of exiting after the first
18 response. This can only be used with the IPC message type _subscribe_. If
19 there is a malformed response or an invalid event type was requested,
20 swaymsg will stop monitoring and exit.
21
16*-q, --quiet* 22*-q, --quiet*
17 Sends the IPC message but does not print the response from sway. 23 Sends the IPC message but does not print the response from sway.
18 24
@@ -71,3 +77,8 @@ _swaymsg_ [options...] [message]
71 77
72*send\_tick* 78*send\_tick*
73 Sends a tick event to all subscribed clients. 79 Sends a tick event to all subscribed clients.
80
81*subscribe*
82 Subscribe to a list of event types. The argument for this type should be
83 provided in the form of a valid JSON array. If any of the types are invalid
84 or if an valid JSON array is not provided, this will result in an failure.