aboutsummaryrefslogtreecommitdiffstats
path: root/sway
diff options
context:
space:
mode:
authorLibravatar Calvin Lee <cyrus296@gmail.com>2017-04-04 21:20:27 -0600
committerLibravatar Calvin Lee <cyrus296@gmail.com>2017-04-05 22:07:23 -0600
commit069d37f987c4e323cdb9396f0d80ac83d00566ff (patch)
treeb883a5553107ab24d5346db42062518f9e7bdca9 /sway
parentMerge pull request #1145 from 4e554c4c/marks (diff)
downloadsway-069d37f987c4e323cdb9396f0d80ac83d00566ff.tar.gz
sway-069d37f987c4e323cdb9396f0d80ac83d00566ff.tar.zst
sway-069d37f987c4e323cdb9396f0d80ac83d00566ff.zip
Improve criteria handling
This commit changes how commands decide what container to act on. Commands get the current container though `current_container`, a global defined in sway/commands.c. If a criteria is given before a command, then the following command will be run once for every container the criteria matches with a reference to the matching container in 'current_container'. Commands should use this instead of `get_focused_container()` from now on. This commit also fixes a few (minor) mistakes made in implementing marks such as non-escaped arrows in sway(5) and calling the "mark" command "floating" by accident. It also cleans up `criteria.c` in a few places.
Diffstat (limited to 'sway')
-rw-r--r--sway/commands.c79
-rw-r--r--sway/commands/border.c2
-rw-r--r--sway/commands/floating.c2
-rw-r--r--sway/commands/focus.c3
-rw-r--r--sway/commands/fullscreen.c2
-rw-r--r--sway/commands/kill.c2
-rw-r--r--sway/commands/layout.c2
-rw-r--r--sway/commands/mark.c4
-rw-r--r--sway/commands/move.c4
-rw-r--r--sway/commands/resize.c12
-rw-r--r--sway/commands/split.c6
-rw-r--r--sway/commands/unmark.c2
-rw-r--r--sway/criteria.c27
-rw-r--r--sway/sway.5.txt16
14 files changed, 110 insertions, 53 deletions
diff --git a/sway/commands.c b/sway/commands.c
index 971ff505..17c7d717 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -43,6 +43,8 @@ struct cmd_handler {
43 43
44int sp_index = 0; 44int sp_index = 0;
45 45
46swayc_t *current_container = NULL;
47
46// Returns error object, or NULL if check succeeds. 48// Returns error object, or NULL if check succeeds.
47struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val) { 49struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val) {
48 struct cmd_results *error = NULL; 50 struct cmd_results *error = NULL;
@@ -371,42 +373,37 @@ struct cmd_results *handle_command(char *_exec, enum command_context context) {
371 char *head = exec; 373 char *head = exec;
372 char *cmdlist; 374 char *cmdlist;
373 char *cmd; 375 char *cmd;
374 char *criteria __attribute__((unused)); 376 list_t *containers = NULL;
375 377
376 head = exec; 378 head = exec;
377 do { 379 do {
378 // Extract criteria (valid for this command list only). 380 // Extract criteria (valid for this command list only).
379 criteria = NULL;
380 if (*head == '[') { 381 if (*head == '[') {
381 ++head; 382 ++head;
382 criteria = argsep(&head, "]"); 383 char *criteria_string = argsep(&head, "]");
383 if (head) { 384 if (head) {
384 ++head; 385 ++head;
385 // TODO handle criteria 386 list_t *tokens = create_list();
387 char *error;
388
389 if ((error = extract_crit_tokens(tokens, criteria_string))) {
390 results = cmd_results_new(CMD_INVALID, criteria_string,
391 "Can't parse criteria string: %s", error);
392 free(error);
393 free(tokens);
394 goto cleanup;
395 }
396 containers = container_for(tokens);
397
398 free(tokens);
386 } else { 399 } else {
387 if (!results) { 400 if (!results) {
388 results = cmd_results_new(CMD_INVALID, criteria, "Unmatched ["); 401 results = cmd_results_new(CMD_INVALID, criteria_string, "Unmatched [");
389 } 402 }
390 goto cleanup; 403 goto cleanup;
391 } 404 }
392 // Skip leading whitespace 405 // Skip leading whitespace
393 head += strspn(head, whitespace); 406 head += strspn(head, whitespace);
394
395 // TODO: it will yield unexpected results to execute commands
396 // (on any view) that where meant for certain views only.
397 if (!results) {
398 int len = strlen(criteria) + strlen(head) + 4;
399 char *tmp = malloc(len);
400 if (tmp) {
401 snprintf(tmp, len, "[%s] %s", criteria, head);
402 } else {
403 sway_log(L_DEBUG, "Unable to allocate criteria string for cmd result");
404 }
405 results = cmd_results_new(CMD_INVALID, tmp,
406 "Can't handle criteria string: Refusing to execute command");
407 free(tmp);
408 }
409 goto cleanup;
410 } 407 }
411 // Split command list 408 // Split command list
412 cmdlist = argsep(&head, ";"); 409 cmdlist = argsep(&head, ";");
@@ -450,21 +447,43 @@ struct cmd_results *handle_command(char *_exec, enum command_context context) {
450 free_argv(argc, argv); 447 free_argv(argc, argv);
451 goto cleanup; 448 goto cleanup;
452 } 449 }
453 struct cmd_results *res = handler->handle(argc-1, argv+1); 450 int i = 0;
454 if (res->status != CMD_SUCCESS) { 451 do {
455 free_argv(argc, argv); 452 if (!containers) {
456 if (results) { 453 current_container = get_focused_container(&root_container);
457 free_cmd_results(results); 454 } else if (containers->length == 0) {
455 break;
456 } else {
457 current_container = (swayc_t *)containers->items[i];
458 } 458 }
459 results = res; 459 sway_log(L_INFO, "Running on container '%s'", current_container->name);
460 goto cleanup; 460
461 } 461 struct cmd_results *res = handler->handle(argc-1, argv+1);
462 if (res->status != CMD_SUCCESS) {
463 free_argv(argc, argv);
464 if (results) {
465 free_cmd_results(results);
466 }
467 results = res;
468 goto cleanup;
469 }
470 free_cmd_results(res);
471 ++i;
472 } while(containers && i < containers->length);
473
462 free_argv(argc, argv); 474 free_argv(argc, argv);
463 free_cmd_results(res);
464 } while(cmdlist); 475 } while(cmdlist);
476
477 if (containers) {
478 list_free(containers);
479 containers = NULL;
480 }
465 } while(head); 481 } while(head);
466 cleanup: 482 cleanup:
467 free(exec); 483 free(exec);
484 if (containers) {
485 free(containers);
486 }
468 if (!results) { 487 if (!results) {
469 results = cmd_results_new(CMD_SUCCESS, NULL, NULL); 488 results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
470 } 489 }
diff --git a/sway/commands/border.c b/sway/commands/border.c
index 0211e40c..c888622e 100644
--- a/sway/commands/border.c
+++ b/sway/commands/border.c
@@ -20,7 +20,7 @@ struct cmd_results *cmd_border(int argc, char **argv) {
20 "Expected 'border <normal|pixel|none|toggle> [<n>]"); 20 "Expected 'border <normal|pixel|none|toggle> [<n>]");
21 } 21 }
22 22
23 swayc_t *view = get_focused_view(&root_container); 23 swayc_t *view = current_container;
24 enum swayc_border_types border = view->border_type; 24 enum swayc_border_types border = view->border_type;
25 int thickness = view->border_thickness; 25 int thickness = view->border_thickness;
26 26
diff --git a/sway/commands/floating.c b/sway/commands/floating.c
index 113c8b71..ccfde532 100644
--- a/sway/commands/floating.c
+++ b/sway/commands/floating.c
@@ -13,7 +13,7 @@ struct cmd_results *cmd_floating(int argc, char **argv) {
13 if ((error = checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1))) { 13 if ((error = checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1))) {
14 return error; 14 return error;
15 } 15 }
16 swayc_t *view = get_focused_container(&root_container); 16 swayc_t *view = current_container;
17 bool wants_floating; 17 bool wants_floating;
18 if (strcasecmp(argv[0], "enable") == 0) { 18 if (strcasecmp(argv[0], "enable") == 0) {
19 wants_floating = true; 19 wants_floating = true;
diff --git a/sway/commands/focus.c b/sway/commands/focus.c
index 12c5d02c..defaba29 100644
--- a/sway/commands/focus.c
+++ b/sway/commands/focus.c
@@ -30,6 +30,9 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
30 } 30 }
31 } 31 }
32 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 32 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
33 } else if (argc == 0) {
34 set_focused_container(current_container);
35 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
33 } else if ((error = checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1))) { 36 } else if ((error = checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1))) {
34 return error; 37 return error;
35 } 38 }
diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c
index 321d6f59..bfff82f9 100644
--- a/sway/commands/fullscreen.c
+++ b/sway/commands/fullscreen.c
@@ -14,7 +14,7 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) {
14 if ((error = checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 0))) { 14 if ((error = checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 0))) {
15 return error; 15 return error;
16 } 16 }
17 swayc_t *container = get_focused_view(&root_container); 17 swayc_t *container = current_container;
18 if(container->type != C_VIEW){ 18 if(container->type != C_VIEW){
19 return cmd_results_new(CMD_INVALID, "fullscreen", "Only views can fullscreen"); 19 return cmd_results_new(CMD_INVALID, "fullscreen", "Only views can fullscreen");
20 } 20 }
diff --git a/sway/commands/kill.c b/sway/commands/kill.c
index 2e94fb10..742e2b86 100644
--- a/sway/commands/kill.c
+++ b/sway/commands/kill.c
@@ -6,7 +6,7 @@ struct cmd_results *cmd_kill(int argc, char **argv) {
6 if (config->reading) return cmd_results_new(CMD_FAILURE, "kill", "Can't be used in config file."); 6 if (config->reading) return cmd_results_new(CMD_FAILURE, "kill", "Can't be used in config file.");
7 if (!config->active) return cmd_results_new(CMD_FAILURE, "kill", "Can only be used when sway is running."); 7 if (!config->active) return cmd_results_new(CMD_FAILURE, "kill", "Can only be used when sway is running.");
8 8
9 swayc_t *container = get_focused_container(&root_container); 9 swayc_t *container = current_container;
10 close_views(container); 10 close_views(container);
11 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 11 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
12} 12}
diff --git a/sway/commands/layout.c b/sway/commands/layout.c
index 570cd207..40ebd590 100644
--- a/sway/commands/layout.c
+++ b/sway/commands/layout.c
@@ -16,7 +16,7 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
16 if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) { 16 if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) {
17 return error; 17 return error;
18 } 18 }
19 swayc_t *parent = get_focused_container(&root_container); 19 swayc_t *parent = current_container;
20 if (parent->is_floating) { 20 if (parent->is_floating) {
21 return cmd_results_new(CMD_FAILURE, "layout", "Unable to change layout of floating windows"); 21 return cmd_results_new(CMD_FAILURE, "layout", "Unable to change layout of floating windows");
22 } 22 }
diff --git a/sway/commands/mark.c b/sway/commands/mark.c
index 68a84af7..919883b0 100644
--- a/sway/commands/mark.c
+++ b/sway/commands/mark.c
@@ -8,11 +8,11 @@
8struct cmd_results *cmd_mark(int argc, char **argv) { 8struct cmd_results *cmd_mark(int argc, char **argv) {
9 struct cmd_results *error = NULL; 9 struct cmd_results *error = NULL;
10 if (config->reading) return cmd_results_new(CMD_FAILURE, "mark", "Can't be used in config file."); 10 if (config->reading) return cmd_results_new(CMD_FAILURE, "mark", "Can't be used in config file.");
11 if ((error = checkarg(argc, "floating", EXPECTED_AT_LEAST, 1))) { 11 if ((error = checkarg(argc, "mark", EXPECTED_AT_LEAST, 1))) {
12 return error; 12 return error;
13 } 13 }
14 14
15 swayc_t *view = get_focused_container(&root_container); 15 swayc_t *view = current_container;
16 bool add = false; 16 bool add = false;
17 bool toggle = false; 17 bool toggle = false;
18 18
diff --git a/sway/commands/move.c b/sway/commands/move.c
index 97e10f10..3c47cfe7 100644
--- a/sway/commands/move.c
+++ b/sway/commands/move.c
@@ -20,7 +20,7 @@ struct cmd_results *cmd_move(int argc, char **argv) {
20 "'move <container|window> to workspace <name>' or " 20 "'move <container|window> to workspace <name>' or "
21 "'move <container|window|workspace> to output <name|direction>' or " 21 "'move <container|window|workspace> to output <name|direction>' or "
22 "'move position mouse'"; 22 "'move position mouse'";
23 swayc_t *view = get_focused_container(&root_container); 23 swayc_t *view = current_container;
24 24
25 if (argc == 2 || (argc == 3 && strcasecmp(argv[2], "px") == 0 )) { 25 if (argc == 2 || (argc == 3 && strcasecmp(argv[2], "px") == 0 )) {
26 char *inv; 26 char *inv;
@@ -125,7 +125,7 @@ struct cmd_results *cmd_move(int argc, char **argv) {
125 if (view->type != C_CONTAINER && view->type != C_VIEW) { 125 if (view->type != C_CONTAINER && view->type != C_VIEW) {
126 return cmd_results_new(CMD_FAILURE, "move scratchpad", "Can only move containers and views."); 126 return cmd_results_new(CMD_FAILURE, "move scratchpad", "Can only move containers and views.");
127 } 127 }
128 swayc_t *view = get_focused_container(&root_container); 128 swayc_t *view = current_container;
129 int i; 129 int i;
130 for (i = 0; i < scratchpad->length; i++) { 130 for (i = 0; i < scratchpad->length; i++) {
131 if (scratchpad->items[i] == view) { 131 if (scratchpad->items[i] == view) {
diff --git a/sway/commands/resize.c b/sway/commands/resize.c
index 61af080c..ef52bb07 100644
--- a/sway/commands/resize.c
+++ b/sway/commands/resize.c
@@ -19,7 +19,7 @@ enum resize_dim_types {
19}; 19};
20 20
21static bool set_size_floating(int new_dimension, bool use_width) { 21static bool set_size_floating(int new_dimension, bool use_width) {
22 swayc_t *view = get_focused_float(swayc_active_workspace()); 22 swayc_t *view = current_container;
23 if (view) { 23 if (view) {
24 if (use_width) { 24 if (use_width) {
25 int current_width = view->width; 25 int current_width = view->width;
@@ -50,7 +50,7 @@ static bool set_size_floating(int new_dimension, bool use_width) {
50} 50}
51 51
52static bool resize_floating(int amount, bool use_width) { 52static bool resize_floating(int amount, bool use_width) {
53 swayc_t *view = get_focused_float(swayc_active_workspace()); 53 swayc_t *view = current_container;
54 54
55 if (view) { 55 if (view) {
56 if (use_width) { 56 if (use_width) {
@@ -64,7 +64,7 @@ static bool resize_floating(int amount, bool use_width) {
64} 64}
65 65
66static bool resize_tiled(int amount, bool use_width) { 66static bool resize_tiled(int amount, bool use_width) {
67 swayc_t *container = get_focused_view(swayc_active_workspace()); 67 swayc_t *container = current_container;
68 swayc_t *parent = container->parent; 68 swayc_t *parent = container->parent;
69 int idx_focused = 0; 69 int idx_focused = 0;
70 bool use_major = false; 70 bool use_major = false;
@@ -199,7 +199,7 @@ static bool resize_tiled(int amount, bool use_width) {
199 199
200static bool set_size_tiled(int amount, bool use_width) { 200static bool set_size_tiled(int amount, bool use_width) {
201 int desired; 201 int desired;
202 swayc_t *focused = get_focused_view(swayc_active_workspace()); 202 swayc_t *focused = current_container;
203 203
204 if (use_width) { 204 if (use_width) {
205 desired = amount - focused->width; 205 desired = amount - focused->width;
@@ -211,7 +211,7 @@ static bool set_size_tiled(int amount, bool use_width) {
211} 211}
212 212
213static bool set_size(int dimension, bool use_width) { 213static bool set_size(int dimension, bool use_width) {
214 swayc_t *focused = get_focused_view_include_floating(swayc_active_workspace()); 214 swayc_t *focused = current_container;
215 215
216 if (focused) { 216 if (focused) {
217 if (focused->is_floating) { 217 if (focused->is_floating) {
@@ -225,7 +225,7 @@ static bool set_size(int dimension, bool use_width) {
225} 225}
226 226
227static bool resize(int dimension, bool use_width, enum resize_dim_types dim_type) { 227static bool resize(int dimension, bool use_width, enum resize_dim_types dim_type) {
228 swayc_t *focused = get_focused_view_include_floating(swayc_active_workspace()); 228 swayc_t *focused = current_container;
229 229
230 // translate "10 ppt" (10%) to appropriate # of pixels in case we need it 230 // translate "10 ppt" (10%) to appropriate # of pixels in case we need it
231 float ppt_dim = (float)dimension / 100; 231 float ppt_dim = (float)dimension / 100;
diff --git a/sway/commands/split.c b/sway/commands/split.c
index e7da93d7..e3045a4f 100644
--- a/sway/commands/split.c
+++ b/sway/commands/split.c
@@ -17,7 +17,7 @@ static struct cmd_results *_do_split(int argc, char **argv, int layout) {
17 if ((error = checkarg(argc, name, EXPECTED_EQUAL_TO, 0))) { 17 if ((error = checkarg(argc, name, EXPECTED_EQUAL_TO, 0))) {
18 return error; 18 return error;
19 } 19 }
20 swayc_t *focused = get_focused_container(&root_container); 20 swayc_t *focused = current_container;
21 21
22 // Case of floating window, don't split 22 // Case of floating window, don't split
23 if (focused->is_floating) { 23 if (focused->is_floating) {
@@ -66,7 +66,7 @@ struct cmd_results *cmd_split(int argc, char **argv) {
66 } else if (strcasecmp(argv[0], "h") == 0 || strcasecmp(argv[0], "horizontal") == 0) { 66 } else if (strcasecmp(argv[0], "h") == 0 || strcasecmp(argv[0], "horizontal") == 0) {
67 _do_split(argc - 1, argv + 1, L_HORIZ); 67 _do_split(argc - 1, argv + 1, L_HORIZ);
68 } else if (strcasecmp(argv[0], "t") == 0 || strcasecmp(argv[0], "toggle") == 0) { 68 } else if (strcasecmp(argv[0], "t") == 0 || strcasecmp(argv[0], "toggle") == 0) {
69 swayc_t *focused = get_focused_container(&root_container); 69 swayc_t *focused = current_container;
70 if (focused->parent->layout == L_VERT) { 70 if (focused->parent->layout == L_VERT) {
71 _do_split(argc - 1, argv + 1, L_HORIZ); 71 _do_split(argc - 1, argv + 1, L_HORIZ);
72 } else { 72 } else {
@@ -89,7 +89,7 @@ struct cmd_results *cmd_splith(int argc, char **argv) {
89} 89}
90 90
91struct cmd_results *cmd_splitt(int argc, char **argv) { 91struct cmd_results *cmd_splitt(int argc, char **argv) {
92 swayc_t *focused = get_focused_container(&root_container); 92 swayc_t *focused = current_container;
93 if (focused->parent->layout == L_VERT) { 93 if (focused->parent->layout == L_VERT) {
94 return _do_split(argc, argv, L_HORIZ); 94 return _do_split(argc, argv, L_HORIZ);
95 } else { 95 } else {
diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c
index 34a2ae44..ac213261 100644
--- a/sway/commands/unmark.c
+++ b/sway/commands/unmark.c
@@ -5,7 +5,7 @@
5#include "stringop.h" 5#include "stringop.h"
6 6
7struct cmd_results *cmd_unmark(int argc, char **argv) { 7struct cmd_results *cmd_unmark(int argc, char **argv) {
8 swayc_t *view = get_focused_container(&root_container); 8 swayc_t *view = current_container;
9 9
10 if (view->marks) { 10 if (view->marks) {
11 if (argc) { 11 if (argc) {
diff --git a/sway/criteria.c b/sway/criteria.c
index 3ffc48f0..bd99461d 100644
--- a/sway/criteria.c
+++ b/sway/criteria.c
@@ -245,7 +245,7 @@ ect_cleanup:
245 return error; 245 return error;
246} 246}
247 247
248int regex_cmp(const char *item, const regex_t *regex) { 248static int regex_cmp(const char *item, const regex_t *regex) {
249 return regexec(regex, item, 0, NULL, 0); 249 return regexec(regex, item, 0, NULL, 0);
250} 250}
251 251
@@ -272,7 +272,10 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) {
272 break; 272 break;
273 case CRIT_CON_MARK: 273 case CRIT_CON_MARK:
274 if (crit->regex && cont->marks && (list_seq_find(cont->marks, (int (*)(const void *, const void *))regex_cmp, crit->regex) != -1)) { 274 if (crit->regex && cont->marks && (list_seq_find(cont->marks, (int (*)(const void *, const void *))regex_cmp, crit->regex) != -1)) {
275 ++matches; 275 // Make sure it isn't matching the NUL string
276 if ((strcmp(crit->raw, "") == 0) == (list_seq_find(cont->marks, (int (*)(const void *, const void *))strcmp, "") != -1)) {
277 ++matches;
278 }
276 } 279 }
277 break; 280 break;
278 case CRIT_ID: 281 case CRIT_ID:
@@ -285,7 +288,7 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) {
285 case CRIT_INSTANCE: 288 case CRIT_INSTANCE:
286 if (!cont->instance) { 289 if (!cont->instance) {
287 // ignore 290 // ignore
288 } else if (strcmp(crit->raw, "focused") == 0) { 291 } else if (crit_is_focused(crit->raw)) {
289 swayc_t *focused = get_focused_view(&root_container); 292 swayc_t *focused = get_focused_view(&root_container);
290 if (focused->instance && strcmp(cont->instance, focused->instance) == 0) { 293 if (focused->instance && strcmp(cont->instance, focused->instance) == 0) {
291 matches++; 294 matches++;
@@ -373,3 +376,21 @@ list_t *criteria_for(swayc_t *cont) {
373 } 376 }
374 return matches; 377 return matches;
375} 378}
379
380struct list_tokens {
381 list_t *list;
382 list_t *tokens;
383};
384
385static void container_match_add(swayc_t *container, struct list_tokens *list_tokens) {
386 if (criteria_test(container, list_tokens->tokens)) {
387 list_add(list_tokens->list, container);
388 }
389}
390list_t *container_for(list_t *tokens) {
391 struct list_tokens list_tokens = (struct list_tokens){create_list(), tokens};
392
393 container_map(&root_container, (void (*)(swayc_t *, void *))container_match_add, &list_tokens);
394
395 return list_tokens.list;
396}
diff --git a/sway/sway.5.txt b/sway/sway.5.txt
index 3cccdfd5..d76951b5 100644
--- a/sway/sway.5.txt
+++ b/sway/sway.5.txt
@@ -316,7 +316,7 @@ The default colors are:
316 If smart_gaps are _on_ then gaps will only be enabled if a workspace has more 316 If smart_gaps are _on_ then gaps will only be enabled if a workspace has more
317 than one child container. 317 than one child container.
318 318
319**mark** <--add|--replace> <--toggle> <identifier>:: 319**mark** \<--add|--replace> \<--toggle> <identifier>::
320 Marks are arbitrary labels that can be used to identify certain windows and 320 Marks are arbitrary labels that can be used to identify certain windows and
321 then jump to them at a later time. By default, the **mark** command sets 321 then jump to them at a later time. By default, the **mark** command sets
322 _identifier_ as the only mark on a window. By specifying _--add_, mark will 322 _identifier_ as the only mark on a window. By specifying _--add_, mark will
@@ -426,6 +426,20 @@ The string contains one or more (space separated) attribute/value pairs and they
426are used by some commands filter which views to execute actions on. All attributes 426are used by some commands filter which views to execute actions on. All attributes
427must match for the criteria string to match. 427must match for the criteria string to match.
428 428
429Criteria may be used with either the **for_window** or **assign** commands to
430specify operations to perform on new views. A criteria may also be used to
431perform specific commands (ones that normally act upon one window) on all views
432that match that criteria. For example:
433
434Focus on a window with the mark "IRC":
435 [con_mark="IRC"] focus
436
437Kill all windows with the title "Emacs":
438 [class="Emacs"] kill
439
440Mark all Firefox windows with "Browser":
441 [class="Firefox"] mark Browser
442
429Currently supported attributes: 443Currently supported attributes:
430 444
431**class**:: 445**class**::