diff options
Diffstat (limited to 'sway/criteria.c')
-rw-r--r-- | sway/criteria.c | 89 |
1 files changed, 57 insertions, 32 deletions
diff --git a/sway/criteria.c b/sway/criteria.c index bc0523ce..ee6d4d1c 100644 --- a/sway/criteria.c +++ b/sway/criteria.c | |||
@@ -2,7 +2,7 @@ | |||
2 | #include <stdlib.h> | 2 | #include <stdlib.h> |
3 | #include <stdio.h> | 3 | #include <stdio.h> |
4 | #include <stdbool.h> | 4 | #include <stdbool.h> |
5 | #include <regex.h> | 5 | #include <pcre.h> |
6 | #include "sway/criteria.h" | 6 | #include "sway/criteria.h" |
7 | #include "sway/container.h" | 7 | #include "sway/container.h" |
8 | #include "sway/config.h" | 8 | #include "sway/config.h" |
@@ -12,6 +12,7 @@ | |||
12 | 12 | ||
13 | enum criteria_type { // *must* keep in sync with criteria_strings[] | 13 | enum criteria_type { // *must* keep in sync with criteria_strings[] |
14 | CRIT_CLASS, | 14 | CRIT_CLASS, |
15 | CRIT_CON_MARK, | ||
15 | CRIT_ID, | 16 | CRIT_ID, |
16 | CRIT_INSTANCE, | 17 | CRIT_INSTANCE, |
17 | CRIT_TITLE, | 18 | CRIT_TITLE, |
@@ -22,16 +23,16 @@ enum criteria_type { // *must* keep in sync with criteria_strings[] | |||
22 | CRIT_LAST | 23 | CRIT_LAST |
23 | }; | 24 | }; |
24 | 25 | ||
25 | // this *must* match the ordering in criteria_type enum | 26 | static const char * const criteria_strings[CRIT_LAST] = { |
26 | static const char * const criteria_strings[] = { | 27 | [CRIT_CLASS] = "class", |
27 | "class", | 28 | [CRIT_CON_MARK] = "con_mark", |
28 | "id", | 29 | [CRIT_ID] = "id", |
29 | "instance", | 30 | [CRIT_INSTANCE] = "instance", |
30 | "title", | 31 | [CRIT_TITLE] = "title", |
31 | "urgent", // either "latest" or "oldest" ... | 32 | [CRIT_URGENT] = "urgent", // either "latest" or "oldest" ... |
32 | "window_role", | 33 | [CRIT_WINDOW_ROLE] = "window_role", |
33 | "window_type", | 34 | [CRIT_WINDOW_TYPE] = "window_type", |
34 | "workspace" | 35 | [CRIT_WORKSPACE] = "workspace" |
35 | }; | 36 | }; |
36 | 37 | ||
37 | /** | 38 | /** |
@@ -40,18 +41,13 @@ static const char * const criteria_strings[] = { | |||
40 | */ | 41 | */ |
41 | struct crit_token { | 42 | struct crit_token { |
42 | enum criteria_type type; | 43 | enum criteria_type type; |
43 | regex_t *regex; | 44 | pcre *regex; |
44 | char *raw; | 45 | char *raw; |
45 | }; | 46 | }; |
46 | 47 | ||
47 | static void free_crit_token(struct crit_token *crit) { | 48 | static void free_crit_token(struct crit_token *crit) { |
48 | if (crit->regex) { | 49 | pcre_free(crit->regex); |
49 | regfree(crit->regex); | 50 | free(crit->raw); |
50 | free(crit->regex); | ||
51 | } | ||
52 | if (crit->raw) { | ||
53 | free(crit->raw); | ||
54 | } | ||
55 | free(crit); | 51 | free(crit); |
56 | } | 52 | } |
57 | 53 | ||
@@ -188,18 +184,17 @@ static char *parse_criteria_name(enum criteria_type *type, char *name) { | |||
188 | } | 184 | } |
189 | 185 | ||
190 | // Returns error string on failure or NULL otherwise. | 186 | // Returns error string on failure or NULL otherwise. |
191 | static char *generate_regex(regex_t **regex, char *value) { | 187 | static char *generate_regex(pcre **regex, char *value) { |
192 | *regex = calloc(1, sizeof(regex_t)); | 188 | const char *reg_err; |
193 | int err = regcomp(*regex, value, REG_NOSUB); | 189 | int offset; |
194 | if (err != 0) { | 190 | |
195 | char *reg_err = malloc(64); | 191 | *regex = pcre_compile(value, PCRE_UTF8 | PCRE_UCP, ®_err, &offset, NULL); |
196 | regerror(err, *regex, reg_err, 64); | ||
197 | 192 | ||
193 | if (!*regex) { | ||
198 | const char *fmt = "Regex compilation (for '%s') failed: %s"; | 194 | const char *fmt = "Regex compilation (for '%s') failed: %s"; |
199 | int len = strlen(fmt) + strlen(value) + strlen(reg_err) - 3; | 195 | int len = strlen(fmt) + strlen(value) + strlen(reg_err) - 3; |
200 | char *error = malloc(len); | 196 | char *error = malloc(len); |
201 | snprintf(error, len, fmt, value, reg_err); | 197 | snprintf(error, len, fmt, value, reg_err); |
202 | free(reg_err); | ||
203 | return error; | 198 | return error; |
204 | } | 199 | } |
205 | return NULL; | 200 | return NULL; |
@@ -243,6 +238,10 @@ ect_cleanup: | |||
243 | return error; | 238 | return error; |
244 | } | 239 | } |
245 | 240 | ||
241 | static int regex_cmp(const char *item, const pcre *regex) { | ||
242 | return pcre_exec(regex, NULL, item, strlen(item), 0, 0, NULL, 0); | ||
243 | } | ||
244 | |||
246 | // test a single view if it matches list of criteria tokens (all of them). | 245 | // test a single view if it matches list of criteria tokens (all of them). |
247 | static bool criteria_test(swayc_t *cont, list_t *tokens) { | 246 | static bool criteria_test(swayc_t *cont, list_t *tokens) { |
248 | if (cont->type != C_VIEW) { | 247 | if (cont->type != C_VIEW) { |
@@ -260,26 +259,34 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) { | |||
260 | if (focused->class && strcmp(cont->class, focused->class) == 0) { | 259 | if (focused->class && strcmp(cont->class, focused->class) == 0) { |
261 | matches++; | 260 | matches++; |
262 | } | 261 | } |
263 | } else if (crit->regex && regexec(crit->regex, cont->class, 0, NULL, 0) == 0) { | 262 | } else if (crit->regex && regex_cmp(cont->class, crit->regex) == 0) { |
264 | matches++; | 263 | matches++; |
265 | } | 264 | } |
266 | break; | 265 | break; |
266 | case CRIT_CON_MARK: | ||
267 | if (crit->regex && cont->marks && (list_seq_find(cont->marks, (int (*)(const void *, const void *))regex_cmp, crit->regex) != -1)) { | ||
268 | // Make sure it isn't matching the NUL string | ||
269 | if ((strcmp(crit->raw, "") == 0) == (list_seq_find(cont->marks, (int (*)(const void *, const void *))strcmp, "") != -1)) { | ||
270 | ++matches; | ||
271 | } | ||
272 | } | ||
273 | break; | ||
267 | case CRIT_ID: | 274 | case CRIT_ID: |
268 | if (!cont->app_id) { | 275 | if (!cont->app_id) { |
269 | // ignore | 276 | // ignore |
270 | } else if (crit->regex && regexec(crit->regex, cont->app_id, 0, NULL, 0) == 0) { | 277 | } else if (crit->regex && regex_cmp(cont->app_id, crit->regex) == 0) { |
271 | matches++; | 278 | matches++; |
272 | } | 279 | } |
273 | break; | 280 | break; |
274 | case CRIT_INSTANCE: | 281 | case CRIT_INSTANCE: |
275 | if (!cont->instance) { | 282 | if (!cont->instance) { |
276 | // ignore | 283 | // ignore |
277 | } else if (strcmp(crit->raw, "focused") == 0) { | 284 | } else if (crit_is_focused(crit->raw)) { |
278 | swayc_t *focused = get_focused_view(&root_container); | 285 | swayc_t *focused = get_focused_view(&root_container); |
279 | if (focused->instance && strcmp(cont->instance, focused->instance) == 0) { | 286 | if (focused->instance && strcmp(cont->instance, focused->instance) == 0) { |
280 | matches++; | 287 | matches++; |
281 | } | 288 | } |
282 | } else if (crit->regex && regexec(crit->regex, cont->instance, 0, NULL, 0) == 0) { | 289 | } else if (crit->regex && regex_cmp(cont->instance, crit->regex) == 0) { |
283 | matches++; | 290 | matches++; |
284 | } | 291 | } |
285 | break; | 292 | break; |
@@ -291,7 +298,7 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) { | |||
291 | if (focused->name && strcmp(cont->name, focused->name) == 0) { | 298 | if (focused->name && strcmp(cont->name, focused->name) == 0) { |
292 | matches++; | 299 | matches++; |
293 | } | 300 | } |
294 | } else if (crit->regex && regexec(crit->regex, cont->name, 0, NULL, 0) == 0) { | 301 | } else if (crit->regex && regex_cmp(cont->name, crit->regex) == 0) { |
295 | matches++; | 302 | matches++; |
296 | } | 303 | } |
297 | break; | 304 | break; |
@@ -311,7 +318,7 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) { | |||
311 | if (focused_ws->name && strcmp(cont_ws->name, focused_ws->name) == 0) { | 318 | if (focused_ws->name && strcmp(cont_ws->name, focused_ws->name) == 0) { |
312 | matches++; | 319 | matches++; |
313 | } | 320 | } |
314 | } else if (crit->regex && regexec(crit->regex, cont_ws->name, 0, NULL, 0) == 0) { | 321 | } else if (crit->regex && regex_cmp(cont_ws->name, crit->regex) == 0) { |
315 | matches++; | 322 | matches++; |
316 | } | 323 | } |
317 | break; | 324 | break; |
@@ -362,3 +369,21 @@ list_t *criteria_for(swayc_t *cont) { | |||
362 | } | 369 | } |
363 | return matches; | 370 | return matches; |
364 | } | 371 | } |
372 | |||
373 | struct list_tokens { | ||
374 | list_t *list; | ||
375 | list_t *tokens; | ||
376 | }; | ||
377 | |||
378 | static void container_match_add(swayc_t *container, struct list_tokens *list_tokens) { | ||
379 | if (criteria_test(container, list_tokens->tokens)) { | ||
380 | list_add(list_tokens->list, container); | ||
381 | } | ||
382 | } | ||
383 | list_t *container_for(list_t *tokens) { | ||
384 | struct list_tokens list_tokens = (struct list_tokens){create_list(), tokens}; | ||
385 | |||
386 | container_map(&root_container, (void (*)(swayc_t *, void *))container_match_add, &list_tokens); | ||
387 | |||
388 | return list_tokens.list; | ||
389 | } | ||