aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sway/commands.h6
-rw-r--r--include/swaynag/swaynag.h1
-rw-r--r--sway/commands.c68
-rw-r--r--sway/commands/bind.c21
-rw-r--r--sway/ipc-server.c11
-rw-r--r--sway/main.c13
-rw-r--r--sway/tree/view.c9
-rw-r--r--swaynag/config.c10
-rw-r--r--swaynag/swaynag.1.scd9
-rw-r--r--swaynag/swaynag.c7
10 files changed, 92 insertions, 63 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h
index eb446eae..c3913c79 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -56,7 +56,7 @@ struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers,
56 * all matching containers. Otherwise, it'll run on the `con` container. If 56 * all matching containers. Otherwise, it'll run on the `con` container. If
57 * `con` is NULL then it'll run on the currently focused container. 57 * `con` is NULL then it'll run on the currently focused container.
58 */ 58 */
59struct cmd_results *execute_command(char *command, struct sway_seat *seat, 59list_t *execute_command(char *command, struct sway_seat *seat,
60 struct sway_container *con); 60 struct sway_container *con);
61/** 61/**
62 * Parse and handles a command during config file loading. 62 * Parse and handles a command during config file loading.
@@ -82,11 +82,11 @@ struct cmd_results *cmd_results_new(enum cmd_status status, const char* input, c
82 */ 82 */
83void free_cmd_results(struct cmd_results *results); 83void free_cmd_results(struct cmd_results *results);
84/** 84/**
85 * Serializes cmd_results to a JSON string. 85 * Serializes a list of cmd_results to a JSON string.
86 * 86 *
87 * Free the JSON string later on. 87 * Free the JSON string later on.
88 */ 88 */
89char *cmd_results_to_json(struct cmd_results *results); 89char *cmd_results_to_json(list_t *res_list);
90 90
91struct cmd_results *add_color(const char *name, 91struct cmd_results *add_color(const char *name,
92 char *buffer, const char *color); 92 char *buffer, const char *color);
diff --git a/include/swaynag/swaynag.h b/include/swaynag/swaynag.h
index a32d1503..0fd1eb50 100644
--- a/include/swaynag/swaynag.h
+++ b/include/swaynag/swaynag.h
@@ -44,6 +44,7 @@ struct swaynag_button {
44 int y; 44 int y;
45 int width; 45 int width;
46 int height; 46 int height;
47 bool terminal;
47}; 48};
48 49
49struct swaynag_details { 50struct swaynag_details {
diff --git a/sway/commands.c b/sway/commands.c
index bffc18f6..1203f63a 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -215,12 +215,9 @@ static void set_config_node(struct sway_node *node) {
215 } 215 }
216} 216}
217 217
218struct cmd_results *execute_command(char *_exec, struct sway_seat *seat, 218list_t *execute_command(char *_exec, struct sway_seat *seat,
219 struct sway_container *con) { 219 struct sway_container *con) {
220 // Even though this function will process multiple commands we will only 220 list_t *res_list = create_list();
221 // return the last error, if any (for now). (Since we have access to an
222 // error string we could e.g. concatenate all errors there.)
223 struct cmd_results *results = NULL;
224 char *exec = strdup(_exec); 221 char *exec = strdup(_exec);
225 char *head = exec; 222 char *head = exec;
226 char *cmdlist; 223 char *cmdlist;
@@ -254,8 +251,8 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat,
254 char *error = NULL; 251 char *error = NULL;
255 struct criteria *criteria = criteria_parse(head, &error); 252 struct criteria *criteria = criteria_parse(head, &error);
256 if (!criteria) { 253 if (!criteria) {
257 results = cmd_results_new(CMD_INVALID, head, 254 list_add(res_list, cmd_results_new(CMD_INVALID, head,
258 "%s", error); 255 "%s", error));
259 free(error); 256 free(error);
260 goto cleanup; 257 goto cleanup;
261 } 258 }
@@ -291,10 +288,8 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat,
291 } 288 }
292 struct cmd_handler *handler = find_handler(argv[0], NULL, 0); 289 struct cmd_handler *handler = find_handler(argv[0], NULL, 0);
293 if (!handler) { 290 if (!handler) {
294 if (results) { 291 list_add(res_list, cmd_results_new(CMD_INVALID, cmd,
295 free_cmd_results(results); 292 "Unknown/invalid command"));
296 }
297 results = cmd_results_new(CMD_INVALID, cmd, "Unknown/invalid command");
298 free_argv(argc, argv); 293 free_argv(argc, argv);
299 goto cleanup; 294 goto cleanup;
300 } 295 }
@@ -308,29 +303,21 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat,
308 if (!config->handler_context.using_criteria) { 303 if (!config->handler_context.using_criteria) {
309 set_config_node(node); 304 set_config_node(node);
310 struct cmd_results *res = handler->handle(argc-1, argv+1); 305 struct cmd_results *res = handler->handle(argc-1, argv+1);
311 if (res->status != CMD_SUCCESS) { 306 list_add(res_list, res);
307 if (res->status == CMD_INVALID) {
312 free_argv(argc, argv); 308 free_argv(argc, argv);
313 if (results) {
314 free_cmd_results(results);
315 }
316 results = res;
317 goto cleanup; 309 goto cleanup;
318 } 310 }
319 free_cmd_results(res);
320 } else { 311 } else {
321 for (int i = 0; i < views->length; ++i) { 312 for (int i = 0; i < views->length; ++i) {
322 struct sway_view *view = views->items[i]; 313 struct sway_view *view = views->items[i];
323 set_config_node(&view->container->node); 314 set_config_node(&view->container->node);
324 struct cmd_results *res = handler->handle(argc-1, argv+1); 315 struct cmd_results *res = handler->handle(argc-1, argv+1);
325 if (res->status != CMD_SUCCESS) { 316 list_add(res_list, res);
317 if (res->status == CMD_INVALID) {
326 free_argv(argc, argv); 318 free_argv(argc, argv);
327 if (results) {
328 free_cmd_results(results);
329 }
330 results = res;
331 goto cleanup; 319 goto cleanup;
332 } 320 }
333 free_cmd_results(res);
334 } 321 }
335 } 322 }
336 free_argv(argc, argv); 323 free_argv(argc, argv);
@@ -339,10 +326,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat,
339cleanup: 326cleanup:
340 free(exec); 327 free(exec);
341 list_free(views); 328 list_free(views);
342 if (!results) { 329 return res_list;
343 results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
344 }
345 return results;
346} 330}
347 331
348// this is like execute_command above, except: 332// this is like execute_command above, except:
@@ -420,6 +404,7 @@ struct cmd_results *config_command(char *exec) {
420 // Strip quotes and unescape the string 404 // Strip quotes and unescape the string
421 for (int i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { 405 for (int i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) {
422 if (handler->handle != cmd_exec && handler->handle != cmd_exec_always 406 if (handler->handle != cmd_exec && handler->handle != cmd_exec_always
407 && handler->handle != cmd_mode
423 && handler->handle != cmd_bindsym 408 && handler->handle != cmd_bindsym
424 && handler->handle != cmd_bindcode 409 && handler->handle != cmd_bindcode
425 && handler->handle != cmd_set 410 && handler->handle != cmd_set
@@ -574,20 +559,25 @@ void free_cmd_results(struct cmd_results *results) {
574 free(results); 559 free(results);
575} 560}
576 561
577char *cmd_results_to_json(struct cmd_results *results) { 562char *cmd_results_to_json(list_t *res_list) {
578 json_object *result_array = json_object_new_array(); 563 json_object *result_array = json_object_new_array();
579 json_object *root = json_object_new_object(); 564 for (int i = 0; i < res_list->length; ++i) {
580 json_object_object_add(root, "success", 565 struct cmd_results *results = res_list->items[i];
581 json_object_new_boolean(results->status == CMD_SUCCESS)); 566 json_object *root = json_object_new_object();
582 if (results->input) { 567 json_object_object_add(root, "success",
583 json_object_object_add( 568 json_object_new_boolean(results->status == CMD_SUCCESS));
584 root, "input", json_object_new_string(results->input)); 569 if (results->error) {
585 } 570 json_object_object_add(root, "parse_error",
586 if (results->error) { 571 json_object_new_boolean(results->status == CMD_INVALID));
587 json_object_object_add( 572 json_object_object_add(
588 root, "error", json_object_new_string(results->error)); 573 root, "error", json_object_new_string(results->error));
574 }
575 if (results->input) {
576 json_object_object_add(
577 root, "input", json_object_new_string(results->input));
578 }
579 json_object_array_add(result_array, root);
589 } 580 }
590 json_object_array_add(result_array, root);
591 const char *json = json_object_to_json_string(result_array); 581 const char *json = json_object_to_json_string(result_array);
592 char *res = strdup(json); 582 char *res = strdup(json);
593 json_object_put(result_array); 583 json_object_put(result_array);
diff --git a/sway/commands/bind.c b/sway/commands/bind.c
index 08acbe7a..34881b0f 100644
--- a/sway/commands/bind.c
+++ b/sway/commands/bind.c
@@ -289,13 +289,20 @@ void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding)
289 wlr_log(WLR_DEBUG, "running command for binding: %s", binding->command); 289 wlr_log(WLR_DEBUG, "running command for binding: %s", binding->command);
290 290
291 config->handler_context.seat = seat; 291 config->handler_context.seat = seat;
292 struct cmd_results *results = execute_command(binding->command, NULL, NULL); 292 list_t *res_list = execute_command(binding->command, NULL, NULL);
293 if (results->status == CMD_SUCCESS) { 293 bool success = true;
294 while (res_list->length) {
295 struct cmd_results *results = res_list->items[0];
296 if (results->status != CMD_SUCCESS) {
297 wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)",
298 binding->command, results->error);
299 success = false;
300 }
301 free_cmd_results(results);
302 list_del(res_list, 0);
303 }
304 list_free(res_list);
305 if (success) {
294 ipc_event_binding(binding); 306 ipc_event_binding(binding);
295 } else {
296 wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)",
297 binding->command, results->error);
298 } 307 }
299
300 free_cmd_results(results);
301} 308}
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index aa0f0fad..95433d97 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -597,13 +597,18 @@ void ipc_client_handle_command(struct ipc_client *client) {
597 switch (client->current_command) { 597 switch (client->current_command) {
598 case IPC_COMMAND: 598 case IPC_COMMAND:
599 { 599 {
600 struct cmd_results *results = execute_command(buf, NULL, NULL); 600 list_t *res_list = execute_command(buf, NULL, NULL);
601 transaction_commit_dirty(); 601 transaction_commit_dirty();
602 char *json = cmd_results_to_json(results); 602 char *json = cmd_results_to_json(res_list);
603 int length = strlen(json); 603 int length = strlen(json);
604 client_valid = ipc_send_reply(client, json, (uint32_t)length); 604 client_valid = ipc_send_reply(client, json, (uint32_t)length);
605 free(json); 605 free(json);
606 free_cmd_results(results); 606 while (res_list->length) {
607 struct cmd_results *results = res_list->items[0];
608 free_cmd_results(results);
609 list_del(res_list, 0);
610 }
611 list_free(res_list);
607 goto exit_cleanup; 612 goto exit_cleanup;
608 } 613 }
609 614
diff --git a/sway/main.c b/sway/main.c
index a21970e2..a74183fe 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -392,11 +392,16 @@ int main(int argc, char **argv) {
392 wlr_log(WLR_DEBUG, "Running deferred commands"); 392 wlr_log(WLR_DEBUG, "Running deferred commands");
393 while (config->cmd_queue->length) { 393 while (config->cmd_queue->length) {
394 char *line = config->cmd_queue->items[0]; 394 char *line = config->cmd_queue->items[0];
395 struct cmd_results *res = execute_command(line, NULL, NULL); 395 list_t *res_list = execute_command(line, NULL, NULL);
396 if (res->status != CMD_SUCCESS) { 396 while (res_list->length) {
397 wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error); 397 struct cmd_results *res = res_list->items[0];
398 if (res->status != CMD_SUCCESS) {
399 wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error);
400 }
401 free_cmd_results(res);
402 list_del(res_list, 0);
398 } 403 }
399 free_cmd_results(res); 404 list_free(res_list);
400 free(line); 405 free(line);
401 list_del(config->cmd_queue, 0); 406 list_del(config->cmd_queue, 0);
402 } 407 }
diff --git a/sway/tree/view.c b/sway/tree/view.c
index f7af841c..0edefc8e 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -437,9 +437,14 @@ void view_execute_criteria(struct sway_view *view) {
437 wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", 437 wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'",
438 criteria->raw, view, criteria->cmdlist); 438 criteria->raw, view, criteria->cmdlist);
439 list_add(view->executed_criteria, criteria); 439 list_add(view->executed_criteria, criteria);
440 struct cmd_results *res = execute_command( 440 list_t *res_list = execute_command(
441 criteria->cmdlist, NULL, view->container); 441 criteria->cmdlist, NULL, view->container);
442 free_cmd_results(res); 442 while (res_list->length) {
443 struct cmd_results *res = res_list->items[0];
444 free_cmd_results(res);
445 list_del(res_list, 0);
446 }
447 list_free(res_list);
443 } 448 }
444 list_free(criterias); 449 list_free(criterias);
445} 450}
diff --git a/swaynag/config.c b/swaynag/config.c
index 63808ce4..e724aa0c 100644
--- a/swaynag/config.c
+++ b/swaynag/config.c
@@ -52,6 +52,7 @@ int swaynag_parse_options(int argc, char **argv, struct swaynag *swaynag,
52 52
53 static struct option opts[] = { 53 static struct option opts[] = {
54 {"button", required_argument, NULL, 'b'}, 54 {"button", required_argument, NULL, 'b'},
55 {"button-no-terminal", required_argument, NULL, 'B'},
55 {"config", required_argument, NULL, 'c'}, 56 {"config", required_argument, NULL, 'c'},
56 {"debug", no_argument, NULL, 'd'}, 57 {"debug", no_argument, NULL, 'd'},
57 {"edge", required_argument, NULL, 'e'}, 58 {"edge", required_argument, NULL, 'e'},
@@ -86,7 +87,10 @@ int swaynag_parse_options(int argc, char **argv, struct swaynag *swaynag,
86 "Usage: swaynag [options...]\n" 87 "Usage: swaynag [options...]\n"
87 "\n" 88 "\n"
88 " -b, --button <text> <action> Create a button with text that " 89 " -b, --button <text> <action> Create a button with text that "
89 "executes action when pressed. Multiple buttons can be defined.\n" 90 "executes action in a terminal when pressed. Multiple buttons can "
91 "be defined.\n"
92 " -B, --button-no-terminal <text> <action> Like --button, but does"
93 "not run the action in a terminal.\n"
90 " -c, --config <path> Path to config file.\n" 94 " -c, --config <path> Path to config file.\n"
91 " -d, --debug Enable debugging.\n" 95 " -d, --debug Enable debugging.\n"
92 " -e, --edge top|bottom Set the edge to use.\n" 96 " -e, --edge top|bottom Set the edge to use.\n"
@@ -117,12 +121,13 @@ int swaynag_parse_options(int argc, char **argv, struct swaynag *swaynag,
117 121
118 optind = 1; 122 optind = 1;
119 while (1) { 123 while (1) {
120 int c = getopt_long(argc, argv, "b:c:de:f:hlL:m:o:s:t:v", opts, NULL); 124 int c = getopt_long(argc, argv, "b:B:c:de:f:hlL:m:o:s:t:v", opts, NULL);
121 if (c == -1) { 125 if (c == -1) {
122 break; 126 break;
123 } 127 }
124 switch (c) { 128 switch (c) {
125 case 'b': // Button 129 case 'b': // Button
130 case 'B': // Button (No Terminal)
126 if (swaynag) { 131 if (swaynag) {
127 if (optind >= argc) { 132 if (optind >= argc) {
128 fprintf(stderr, "Missing action for button %s\n", optarg); 133 fprintf(stderr, "Missing action for button %s\n", optarg);
@@ -133,6 +138,7 @@ int swaynag_parse_options(int argc, char **argv, struct swaynag *swaynag,
133 button->text = strdup(optarg); 138 button->text = strdup(optarg);
134 button->type = SWAYNAG_ACTION_COMMAND; 139 button->type = SWAYNAG_ACTION_COMMAND;
135 button->action = strdup(argv[optind]); 140 button->action = strdup(argv[optind]);
141 button->terminal = c == 'b';
136 list_add(swaynag->buttons, button); 142 list_add(swaynag->buttons, button);
137 } 143 }
138 optind++; 144 optind++;
diff --git a/swaynag/swaynag.1.scd b/swaynag/swaynag.1.scd
index bb69e47d..b25568a0 100644
--- a/swaynag/swaynag.1.scd
+++ b/swaynag/swaynag.1.scd
@@ -12,7 +12,14 @@ _swaynag_ [options...]
12 12
13*-b, --button* <text> <action> 13*-b, --button* <text> <action>
14 Create a button with the text _text_ that executes _action_ when pressed. 14 Create a button with the text _text_ that executes _action_ when pressed.
15 Multiple buttons can be defined by providing the flag multiple times. 15 If the environment variable `TERMINAL` is set, _action_ will be run inside
16 the terminal. Otherwise, it will fallback to running directly. Multiple
17 buttons can be defined by providing the flag multiple times.
18
19*-B, --button-no-terminal* <text> <action>
20 Create a button with the text _text_ that executes _action_ when pressed.
21 _action_ will be run directly instead of in a terminal. Multiple buttons
22 can be defined by providing the flag multiple times.
16 23
17*-c, --config* <path> 24*-c, --config* <path>
18 The config file to use. By default, the following paths are checked: 25 The config file to use. By default, the following paths are checked:
diff --git a/swaynag/swaynag.c b/swaynag/swaynag.c
index 74e127b6..a2a0b412 100644
--- a/swaynag/swaynag.c
+++ b/swaynag/swaynag.c
@@ -49,14 +49,17 @@ static void swaynag_button_execute(struct swaynag *swaynag,
49 if (fork() == 0) { 49 if (fork() == 0) {
50 // Child of the child. Will be reparented to the init process 50 // Child of the child. Will be reparented to the init process
51 char *terminal = getenv("TERMINAL"); 51 char *terminal = getenv("TERMINAL");
52 if (terminal && strlen(terminal)) { 52 if (button->terminal && terminal && strlen(terminal)) {
53 wlr_log(WLR_DEBUG, "Found $TERMINAL: %s", terminal); 53 wlr_log(WLR_DEBUG, "Found $TERMINAL: %s", terminal);
54 if (!terminal_execute(terminal, button->action)) { 54 if (!terminal_execute(terminal, button->action)) {
55 swaynag_destroy(swaynag); 55 swaynag_destroy(swaynag);
56 exit(EXIT_FAILURE); 56 exit(EXIT_FAILURE);
57 } 57 }
58 } else { 58 } else {
59 wlr_log(WLR_DEBUG, "$TERMINAL not found. Running directly"); 59 if (button->terminal) {
60 wlr_log(WLR_DEBUG,
61 "$TERMINAL not found. Running directly");
62 }
60 execl("/bin/sh", "/bin/sh", "-c", button->action, NULL); 63 execl("/bin/sh", "/bin/sh", "-c", button->action, NULL);
61 } 64 }
62 } 65 }