From bf9a52bab0f8ae9b4ace43c7d9c75ece0c76b562 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Wed, 28 Nov 2018 11:19:18 -0500 Subject: 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']"` --- sway/ipc-server.c | 13 ++++++---- swaymsg/main.c | 70 +++++++++++++++++++++++++++++++++++++++++---------- swaymsg/swaymsg.1.scd | 11 ++++++++ 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) { // TODO: Check if they're permitted to use these events struct json_object *request = json_tokener_parse(buf); if (request == NULL) { - client_valid = ipc_send_reply(client, "{\"success\": false}", 18); + const char msg[] = "[{\"success\": false}]"; + client_valid = ipc_send_reply(client, msg, strlen(msg)); wlr_log(WLR_INFO, "Failed to parse subscribe request"); goto exit_cleanup; } @@ -695,8 +696,8 @@ void ipc_client_handle_command(struct ipc_client *client) { client->subscribed_events |= event_mask(IPC_EVENT_TICK); is_tick = true; } else { - client_valid = - ipc_send_reply(client, "{\"success\": false}", 18); + const char msg[] = "[{\"success\": false}]"; + client_valid = ipc_send_reply(client, msg, strlen(msg)); json_object_put(request); wlr_log(WLR_INFO, "Unsupported event type in subscribe request"); goto exit_cleanup; @@ -704,10 +705,12 @@ void ipc_client_handle_command(struct ipc_client *client) { } json_object_put(request); - client_valid = ipc_send_reply(client, "{\"success\": true}", 17); + const char msg[] = "[{\"success\": true}]"; + client_valid = ipc_send_reply(client, msg, strlen(msg)); if (is_tick) { client->current_command = IPC_EVENT_TICK; - ipc_send_reply(client, "{\"first\": true, \"payload\": \"\"}", 30); + const char tickmsg[] = "{\"first\": true, \"payload\": \"\"}"; + ipc_send_reply(client, tickmsg, strlen(tickmsg)); } goto exit_cleanup; } 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) { } int main(int argc, char **argv) { - static int quiet = 0; - static int raw = 0; + static bool quiet = false; + static bool raw = false; + static bool monitor = false; char *socket_path = NULL; char *cmdtype = NULL; @@ -314,6 +315,7 @@ int main(int argc, char **argv) { static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, + {"monitor", no_argument, NULL, 'm'}, {"quiet", no_argument, NULL, 'q'}, {"raw", no_argument, NULL, 'r'}, {"socket", required_argument, NULL, 's'}, @@ -326,6 +328,7 @@ int main(int argc, char **argv) { "Usage: swaymsg [options] [message]\n" "\n" " -h, --help Show help message and quit.\n" + " -m, --monitor Monitor until killed (-t SUBSCRIBE only)\n" " -q, --quiet Be quiet.\n" " -r, --raw Use raw output even if using a tty\n" " -s, --socket Use the specified socket.\n" @@ -337,16 +340,19 @@ int main(int argc, char **argv) { int c; while (1) { int option_index = 0; - c = getopt_long(argc, argv, "hqrs:t:v", long_options, &option_index); + c = getopt_long(argc, argv, "hmqrs:t:v", long_options, &option_index); if (c == -1) { break; } switch (c) { + case 'm': // Monitor + monitor = true; + break; case 'q': // Quiet - quiet = 1; + quiet = true; break; case 'r': // Raw - raw = 1; + raw = true; break; case 's': // Socket socket_path = strdup(optarg); @@ -400,12 +406,20 @@ int main(int argc, char **argv) { type = IPC_GET_CONFIG; } else if (strcasecmp(cmdtype, "send_tick") == 0) { type = IPC_SEND_TICK; + } else if (strcasecmp(cmdtype, "subscribe") == 0) { + type = IPC_SUBSCRIBE; } else { sway_abort("Unknown message type %s", cmdtype); } free(cmdtype); + if (monitor && type != IPC_SUBSCRIBE) { + wlr_log(WLR_ERROR, "Monitor can only be used with -t SUBSCRIBE"); + free(socket_path); + return 1; + } + char *command = NULL; if (optind < argc) { command = join_args(argv + optind, argc - optind); @@ -422,26 +436,56 @@ int main(int argc, char **argv) { json_object *obj = json_tokener_parse(resp); if (obj == NULL) { - fprintf(stderr, "ERROR: Could not parse json response from ipc. This is a bug in sway."); + fprintf(stderr, "ERROR: Could not parse json response from ipc. " + "This is a bug in sway."); printf("%s\n", resp); ret = 1; } else { if (!success(obj, true)) { ret = 1; } - if (raw) { - printf("%s\n", json_object_to_json_string_ext(obj, - JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED)); - } else { - pretty_print(type, obj); + if (type != IPC_SUBSCRIBE || ret != 0) { + if (raw) { + printf("%s\n", json_object_to_json_string_ext(obj, + JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED)); + } else { + pretty_print(type, obj); + } } json_object_put(obj); } } - close(socketfd); - free(command); free(resp); + + if (type == IPC_SUBSCRIBE && ret == 0) { + do { + struct ipc_response *reply = ipc_recv_response(socketfd); + if (!reply) { + break; + } + + json_object *obj = json_tokener_parse(reply->payload); + if (obj == NULL) { + fprintf(stderr, "ERROR: Could not parse json response from ipc" + ". This is a bug in sway."); + ret = 1; + break; + } else { + if (raw) { + printf("%s\n", json_object_to_json_string(obj)); + } else { + printf("%s\n", json_object_to_json_string_ext(obj, + JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED)); + } + json_object_put(obj); + } + + free_ipc_response(reply); + } while (monitor); + } + + close(socketfd); free(socket_path); return ret; } 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] *-h, --help* Show help message and quit. +*-m, --monitor* + Monitor for responses until killed instead of exiting after the first + response. This can only be used with the IPC message type _subscribe_. If + there is a malformed response or an invalid event type was requested, + swaymsg will stop monitoring and exit. + *-q, --quiet* Sends the IPC message but does not print the response from sway. @@ -71,3 +77,8 @@ _swaymsg_ [options...] [message] *send\_tick* Sends a tick event to all subscribed clients. + +*subscribe* + Subscribe to a list of event types. The argument for this type should be + provided in the form of a valid JSON array. If any of the types are invalid + or if an valid JSON array is not provided, this will result in an failure. -- cgit v1.2.3