aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCalvin Lee <cyrus296@gmail.com>2017-04-04 21:20:27 -0600
committerCalvin Lee <cyrus296@gmail.com>2017-04-05 22:07:23 -0600
commit069d37f987c4e323cdb9396f0d80ac83d00566ff (patch)
treeb883a5553107ab24d5346db42062518f9e7bdca9
parent7d43a76b4e765eb8072c09cdec3847e877cf65d7 (diff)
downloadsway-069d37f987c4e323cdb9396f0d80ac83d00566ff.zip
sway-069d37f987c4e323cdb9396f0d80ac83d00566ff.tar.gz
sway-069d37f987c4e323cdb9396f0d80ac83d00566ff.tar.bz2
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.
-rw-r--r--include/sway/commands.h3
-rw-r--r--include/sway/criteria.h3
-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
16 files changed, 116 insertions, 53 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h
index 35a2f92..91f2ae0 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -5,6 +5,9 @@
#include <wlc/wlc.h>
#include "config.h"
+// Container that a called command should act upon. Only valid in command functions.
+extern swayc_t *current_container;
+
/**
* Indicates the result of a command's execution.
*/
diff --git a/include/sway/criteria.h b/include/sway/criteria.h
index 5c71d17..022c48a 100644
--- a/include/sway/criteria.h
+++ b/include/sway/criteria.h
@@ -33,4 +33,7 @@ char *extract_crit_tokens(list_t *tokens, const char *criteria);
// been set with `for_window` commands and have an associated cmdlist.
list_t *criteria_for(swayc_t *cont);
+// Returns a list of all containers that match the given list of tokens.
+list_t *container_for(list_t *tokens);
+
#endif
diff --git a/sway/commands.c b/sway/commands.c
index 971ff50..17c7d71 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -43,6 +43,8 @@ struct cmd_handler {
int sp_index = 0;
+swayc_t *current_container = NULL;
+
// Returns error object, or NULL if check succeeds.
struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val) {
struct cmd_results *error = NULL;
@@ -371,42 +373,37 @@ struct cmd_results *handle_command(char *_exec, enum command_context context) {
char *head = exec;
char *cmdlist;
char *cmd;
- char *criteria __attribute__((unused));
+ list_t *containers = NULL;
head = exec;
do {
// Extract criteria (valid for this command list only).
- criteria = NULL;
if (*head == '[') {
++head;
- criteria = argsep(&head, "]");
+ char *criteria_string = argsep(&head, "]");
if (head) {
++head;
- // TODO handle criteria
+ list_t *tokens = create_list();
+ char *error;
+
+ if ((error = extract_crit_tokens(tokens, criteria_string))) {
+ results = cmd_results_new(CMD_INVALID, criteria_string,
+ "Can't parse criteria string: %s", error);
+ free(error);
+ free(tokens);
+ goto cleanup;
+ }
+ containers = container_for(tokens);
+
+ free(tokens);
} else {
if (!results) {
- results = cmd_results_new(CMD_INVALID, criteria, "Unmatched [");
+ results = cmd_results_new(CMD_INVALID, criteria_string, "Unmatched [");
}
goto cleanup;
}
// Skip leading whitespace
head += strspn(head, whitespace);
-
- // TODO: it will yield unexpected results to execute commands
- // (on any view) that where meant for certain views only.
- if (!results) {
- int len = strlen(criteria) + strlen(head) + 4;
- char *tmp = malloc(len);
- if (tmp) {
- snprintf(tmp, len, "[%s] %s", criteria, head);
- } else {
- sway_log(L_DEBUG, "Unable to allocate criteria string for cmd result");
- }
- results = cmd_results_new(CMD_INVALID, tmp,
- "Can't handle criteria string: Refusing to execute command");
- free(tmp);
- }
- goto cleanup;
}
// Split command list
cmdlist = argsep(&head, ";");
@@ -450,21 +447,43 @@ struct cmd_results *handle_command(char *_exec, enum command_context context) {
free_argv(argc, argv);
goto cleanup;
}
- struct cmd_results *res = handler->handle(argc-1, argv+1);
- if (res->status != CMD_SUCCESS) {
- free_argv(argc, argv);
- if (results) {
- free_cmd_results(results);
+ int i = 0;
+ do {
+ if (!containers) {
+ current_container = get_focused_container(&root_container);
+ } else if (containers->length == 0) {
+ break;
+ } else {
+ current_container = (swayc_t *)containers->items[i];
}
- results = res;
- goto cleanup;
- }
+ sway_log(L_INFO, "Running on container '%s'", current_container->name);
+
+ struct cmd_results *res = handler->handle(argc-1, argv+1);
+ if (res->status != CMD_SUCCESS) {
+ free_argv(argc, argv);
+ if (results) {
+ free_cmd_results(results);
+ }
+ results = res;
+ goto cleanup;
+ }
+ free_cmd_results(res);
+ ++i;
+ } while(containers && i < containers->length);
+
free_argv(argc, argv);
- free_cmd_results(res);
} while(cmdlist);
+
+ if (containers) {
+ list_free(containers);
+ containers = NULL;
+ }
} while(head);
cleanup:
free(exec);
+ if (containers) {
+ free(containers);
+ }
if (!results) {
results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/border.c b/sway/commands/border.c
index 0211e40..c888622 100644
--- a/sway/commands/border.c
+++ b/sway/commands/border.c
@@ -20,7 +20,7 @@ struct cmd_results *cmd_border(int argc, char **argv) {
"Expected 'border <normal|pixel|none|toggle> [<n>]");
}
- swayc_t *view = get_focused_view(&root_container);
+ swayc_t *view = current_container;
enum swayc_border_types border = view->border_type;
int thickness = view->border_thickness;
diff --git a/sway/commands/floating.c b/sway/commands/floating.c
index 113c8b7..ccfde53 100644
--- a/sway/commands/floating.c
+++ b/sway/commands/floating.c
@@ -13,7 +13,7 @@ struct cmd_results *cmd_floating(int argc, char **argv) {
if ((error = checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1))) {
return error;
}
- swayc_t *view = get_focused_container(&root_container);
+ swayc_t *view = current_container;
bool wants_floating;
if (strcasecmp(argv[0], "enable") == 0) {
wants_floating = true;
diff --git a/sway/commands/focus.c b/sway/commands/focus.c
index 12c5d02..defaba2 100644
--- a/sway/commands/focus.c
+++ b/sway/commands/focus.c
@@ -30,6 +30,9 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
}
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ } else if (argc == 0) {
+ set_focused_container(current_container);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
} else if ((error = checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1))) {
return error;
}
diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c
index 321d6f5..bfff82f 100644
--- a/sway/commands/fullscreen.c
+++ b/sway/commands/fullscreen.c
@@ -14,7 +14,7 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) {
if ((error = checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 0))) {
return error;
}
- swayc_t *container = get_focused_view(&root_container);
+ swayc_t *container = current_container;
if(container->type != C_VIEW){
return cmd_results_new(CMD_INVALID, "fullscreen", "Only views can fullscreen");
}
diff --git a/sway/commands/kill.c b/sway/commands/kill.c
index 2e94fb1..742e2b8 100644
--- a/sway/commands/kill.c
+++ b/sway/commands/kill.c
@@ -6,7 +6,7 @@ struct cmd_results *cmd_kill(int argc, char **argv) {
if (config->reading) return cmd_results_new(CMD_FAILURE, "kill", "Can't be used in config file.");
if (!config->active) return cmd_results_new(CMD_FAILURE, "kill", "Can only be used when sway is running.");
- swayc_t *container = get_focused_container(&root_container);
+ swayc_t *container = current_container;
close_views(container);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/layout.c b/sway/commands/layout.c
index 570cd20..40ebd59 100644
--- a/sway/commands/layout.c
+++ b/sway/commands/layout.c
@@ -16,7 +16,7 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) {
return error;
}
- swayc_t *parent = get_focused_container(&root_container);
+ swayc_t *parent = current_container;
if (parent->is_floating) {
return cmd_results_new(CMD_FAILURE, "layout", "Unable to change layout of floating windows");
}
diff --git a/sway/commands/mark.c b/sway/commands/mark.c
index 68a84af..919883b 100644
--- a/sway/commands/mark.c
+++ b/sway/commands/mark.c
@@ -8,11 +8,11 @@
struct cmd_results *cmd_mark(int argc, char **argv) {
struct cmd_results *error = NULL;
if (config->reading) return cmd_results_new(CMD_FAILURE, "mark", "Can't be used in config file.");
- if ((error = checkarg(argc, "floating", EXPECTED_AT_LEAST, 1))) {
+ if ((error = checkarg(argc, "mark", EXPECTED_AT_LEAST, 1))) {
return error;
}
- swayc_t *view = get_focused_container(&root_container);
+ swayc_t *view = current_container;
bool add = false;
bool toggle = false;
diff --git a/sway/commands/move.c b/sway/commands/move.c
index 97e10f1..3c47cfe 100644
--- a/sway/commands/move.c
+++ b/sway/commands/move.c
@@ -20,7 +20,7 @@ struct cmd_results *cmd_move(int argc, char **argv) {
"'move <container|window> to workspace <name>' or "
"'move <container|window|workspace> to output <name|direction>' or "
"'move position mouse'";
- swayc_t *view = get_focused_container(&root_container);
+ swayc_t *view = current_container;
if (argc == 2 || (argc == 3 && strcasecmp(argv[2], "px") == 0 )) {
char *inv;
@@ -125,7 +125,7 @@ struct cmd_results *cmd_move(int argc, char **argv) {
if (view->type != C_CONTAINER && view->type != C_VIEW) {
return cmd_results_new(CMD_FAILURE, "move scratchpad", "Can only move containers and views.");
}
- swayc_t *view = get_focused_container(&root_container);
+ swayc_t *view = current_container;
int i;
for (i = 0; i < scratchpad->length; i++) {
if (scratchpad->items[i] == view) {
diff --git a/sway/commands/resize.c b/sway/commands/resize.c
index 61af080..ef52bb0 100644
--- a/sway/commands/resize.c
+++ b/sway/commands/resize.c
@@ -19,7 +19,7 @@ enum resize_dim_types {
};
static bool set_size_floating(int new_dimension, bool use_width) {
- swayc_t *view = get_focused_float(swayc_active_workspace());
+ swayc_t *view = current_container;
if (view) {
if (use_width) {
int current_width = view->width;
@@ -50,7 +50,7 @@ static bool set_size_floating(int new_dimension, bool use_width) {
}
static bool resize_floating(int amount, bool use_width) {
- swayc_t *view = get_focused_float(swayc_active_workspace());
+ swayc_t *view = current_container;
if (view) {
if (use_width) {
@@ -64,7 +64,7 @@ static bool resize_floating(int amount, bool use_width) {
}
static bool resize_tiled(int amount, bool use_width) {
- swayc_t *container = get_focused_view(swayc_active_workspace());
+ swayc_t *container = current_container;
swayc_t *parent = container->parent;
int idx_focused = 0;
bool use_major = false;
@@ -199,7 +199,7 @@ static bool resize_tiled(int amount, bool use_width) {
static bool set_size_tiled(int amount, bool use_width) {
int desired;
- swayc_t *focused = get_focused_view(swayc_active_workspace());
+ swayc_t *focused = current_container;
if (use_width) {
desired = amount - focused->width;
@@ -211,7 +211,7 @@ static bool set_size_tiled(int amount, bool use_width) {
}
static bool set_size(int dimension, bool use_width) {
- swayc_t *focused = get_focused_view_include_floating(swayc_active_workspace());
+ swayc_t *focused = current_container;
if (focused) {
if (focused->is_floating) {
@@ -225,7 +225,7 @@ static bool set_size(int dimension, bool use_width) {
}
static bool resize(int dimension, bool use_width, enum resize_dim_types dim_type) {
- swayc_t *focused = get_focused_view_include_floating(swayc_active_workspace());
+ swayc_t *focused = current_container;
// translate "10 ppt" (10%) to appropriate # of pixels in case we need it
float ppt_dim = (float)dimension / 100;
diff --git a/sway/commands/split.c b/sway/commands/split.c
index e7da93d..e3045a4 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) {
if ((error = checkarg(argc, name, EXPECTED_EQUAL_TO, 0))) {
return error;
}
- swayc_t *focused = get_focused_container(&root_container);
+ swayc_t *focused = current_container;
// Case of floating window, don't split
if (focused->is_floating) {
@@ -66,7 +66,7 @@ struct cmd_results *cmd_split(int argc, char **argv) {
} else if (strcasecmp(argv[0], "h") == 0 || strcasecmp(argv[0], "horizontal") == 0) {
_do_split(argc - 1, argv + 1, L_HORIZ);
} else if (strcasecmp(argv[0], "t") == 0 || strcasecmp(argv[0], "toggle") == 0) {
- swayc_t *focused = get_focused_container(&root_container);
+ swayc_t *focused = current_container;
if (focused->parent->layout == L_VERT) {
_do_split(argc - 1, argv + 1, L_HORIZ);
} else {
@@ -89,7 +89,7 @@ struct cmd_results *cmd_splith(int argc, char **argv) {
}
struct cmd_results *cmd_splitt(int argc, char **argv) {
- swayc_t *focused = get_focused_container(&root_container);
+ swayc_t *focused = current_container;
if (focused->parent->layout == L_VERT) {
return _do_split(argc, argv, L_HORIZ);
} else {
diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c
index 34a2ae4..ac21326 100644
--- a/sway/commands/unmark.c
+++ b/sway/commands/unmark.c
@@ -5,7 +5,7 @@
#include "stringop.h"
struct cmd_results *cmd_unmark(int argc, char **argv) {
- swayc_t *view = get_focused_container(&root_container);
+ swayc_t *view = current_container;
if (view->marks) {
if (argc) {
diff --git a/sway/criteria.c b/sway/criteria.c
index 3ffc48f..bd99461 100644
--- a/sway/criteria.c
+++ b/sway/criteria.c
@@ -245,7 +245,7 @@ ect_cleanup:
return error;
}
-int regex_cmp(const char *item, const regex_t *regex) {
+static int regex_cmp(const char *item, const regex_t *regex) {
return regexec(regex, item, 0, NULL, 0);
}
@@ -272,7 +272,10 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) {
break;
case CRIT_CON_MARK:
if (crit->regex && cont->marks && (list_seq_find(cont->marks, (int (*)(const void *, const void *))regex_cmp, crit->regex) != -1)) {
- ++matches;
+ // Make sure it isn't matching the NUL string
+ if ((strcmp(crit->raw, "") == 0) == (list_seq_find(cont->marks, (int (*)(const void *, const void *))strcmp, "") != -1)) {
+ ++matches;
+ }
}
break;
case CRIT_ID:
@@ -285,7 +288,7 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) {
case CRIT_INSTANCE:
if (!cont->instance) {
// ignore
- } else if (strcmp(crit->raw, "focused") == 0) {
+ } else if (crit_is_focused(crit->raw)) {
swayc_t *focused = get_focused_view(&root_container);
if (focused->instance && strcmp(cont->instance, focused->instance) == 0) {
matches++;
@@ -373,3 +376,21 @@ list_t *criteria_for(swayc_t *cont) {
}
return matches;
}
+
+struct list_tokens {
+ list_t *list;
+ list_t *tokens;
+};
+
+static void container_match_add(swayc_t *container, struct list_tokens *list_tokens) {
+ if (criteria_test(container, list_tokens->tokens)) {
+ list_add(list_tokens->list, container);
+ }
+}
+list_t *container_for(list_t *tokens) {
+ struct list_tokens list_tokens = (struct list_tokens){create_list(), tokens};
+
+ container_map(&root_container, (void (*)(swayc_t *, void *))container_match_add, &list_tokens);
+
+ return list_tokens.list;
+}
diff --git a/sway/sway.5.txt b/sway/sway.5.txt
index 3cccdfd..d76951b 100644
--- a/sway/sway.5.txt
+++ b/sway/sway.5.txt
@@ -316,7 +316,7 @@ The default colors are:
If smart_gaps are _on_ then gaps will only be enabled if a workspace has more
than one child container.
-**mark** <--add|--replace> <--toggle> <identifier>::
+**mark** \<--add|--replace> \<--toggle> <identifier>::
Marks are arbitrary labels that can be used to identify certain windows and
then jump to them at a later time. By default, the **mark** command sets
_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
are used by some commands filter which views to execute actions on. All attributes
must match for the criteria string to match.
+Criteria may be used with either the **for_window** or **assign** commands to
+specify operations to perform on new views. A criteria may also be used to
+perform specific commands (ones that normally act upon one window) on all views
+that match that criteria. For example:
+
+Focus on a window with the mark "IRC":
+ [con_mark="IRC"] focus
+
+Kill all windows with the title "Emacs":
+ [class="Emacs"] kill
+
+Mark all Firefox windows with "Browser":
+ [class="Firefox"] mark Browser
+
Currently supported attributes:
**class**::