diff options
Diffstat (limited to 'sway/criteria.c')
-rw-r--r-- | sway/criteria.c | 156 |
1 files changed, 75 insertions, 81 deletions
diff --git a/sway/criteria.c b/sway/criteria.c index e8978ebe..22e9a49b 100644 --- a/sway/criteria.c +++ b/sway/criteria.c | |||
@@ -4,13 +4,15 @@ | |||
4 | #include <stdbool.h> | 4 | #include <stdbool.h> |
5 | #include <pcre.h> | 5 | #include <pcre.h> |
6 | #include "sway/criteria.h" | 6 | #include "sway/criteria.h" |
7 | #include "sway/container.h" | 7 | #include "sway/tree/container.h" |
8 | #include "sway/config.h" | 8 | #include "sway/config.h" |
9 | #include "sway/tree/view.h" | ||
9 | #include "stringop.h" | 10 | #include "stringop.h" |
10 | #include "list.h" | 11 | #include "list.h" |
11 | #include "log.h" | 12 | #include "log.h" |
12 | 13 | ||
13 | enum criteria_type { // *must* keep in sync with criteria_strings[] | 14 | enum criteria_type { // *must* keep in sync with criteria_strings[] |
15 | CRIT_APP_ID, | ||
14 | CRIT_CLASS, | 16 | CRIT_CLASS, |
15 | CRIT_CON_ID, | 17 | CRIT_CON_ID, |
16 | CRIT_CON_MARK, | 18 | CRIT_CON_MARK, |
@@ -27,6 +29,7 @@ enum criteria_type { // *must* keep in sync with criteria_strings[] | |||
27 | }; | 29 | }; |
28 | 30 | ||
29 | static const char * const criteria_strings[CRIT_LAST] = { | 31 | static const char * const criteria_strings[CRIT_LAST] = { |
32 | [CRIT_APP_ID] = "app_id", | ||
30 | [CRIT_CLASS] = "class", | 33 | [CRIT_CLASS] = "class", |
31 | [CRIT_CON_ID] = "con_id", | 34 | [CRIT_CON_ID] = "con_id", |
32 | [CRIT_CON_MARK] = "con_mark", | 35 | [CRIT_CON_MARK] = "con_mark", |
@@ -100,8 +103,9 @@ static int countchr(char *str, char c) { | |||
100 | // of buf. | 103 | // of buf. |
101 | // | 104 | // |
102 | // Returns error string or NULL if successful. | 105 | // Returns error string or NULL if successful. |
103 | static char *crit_tokens(int *argc, char ***buf, const char * const criteria_str) { | 106 | static char *crit_tokens(int *argc, char ***buf, |
104 | sway_log(L_DEBUG, "Parsing criteria: '%s'", criteria_str); | 107 | const char * const criteria_str) { |
108 | wlr_log(L_DEBUG, "Parsing criteria: '%s'", criteria_str); | ||
105 | char *base = criteria_from(criteria_str); | 109 | char *base = criteria_from(criteria_str); |
106 | char *head = base; | 110 | char *head = base; |
107 | char *namep = head; // start of criteria name | 111 | char *namep = head; // start of criteria name |
@@ -247,13 +251,13 @@ char *extract_crit_tokens(list_t *tokens, const char * const criteria) { | |||
247 | free_crit_token(token); | 251 | free_crit_token(token); |
248 | goto ect_cleanup; | 252 | goto ect_cleanup; |
249 | } else if (token->type == CRIT_URGENT || crit_is_focused(value)) { | 253 | } else if (token->type == CRIT_URGENT || crit_is_focused(value)) { |
250 | sway_log(L_DEBUG, "%s -> \"%s\"", name, value); | 254 | wlr_log(L_DEBUG, "%s -> \"%s\"", name, value); |
251 | list_add(tokens, token); | 255 | list_add(tokens, token); |
252 | } else if((error = generate_regex(&token->regex, value))) { | 256 | } else if((error = generate_regex(&token->regex, value))) { |
253 | free_crit_token(token); | 257 | free_crit_token(token); |
254 | goto ect_cleanup; | 258 | goto ect_cleanup; |
255 | } else { | 259 | } else { |
256 | sway_log(L_DEBUG, "%s -> /%s/", name, value); | 260 | wlr_log(L_DEBUG, "%s -> /%s/", name, value); |
257 | list_add(tokens, token); | 261 | list_add(tokens, token); |
258 | } | 262 | } |
259 | } | 263 | } |
@@ -268,8 +272,8 @@ static int regex_cmp(const char *item, const pcre *regex) { | |||
268 | } | 272 | } |
269 | 273 | ||
270 | // test a single view if it matches list of criteria tokens (all of them). | 274 | // test a single view if it matches list of criteria tokens (all of them). |
271 | static bool criteria_test(swayc_t *cont, list_t *tokens) { | 275 | static bool criteria_test(struct sway_container *cont, list_t *tokens) { |
272 | if (cont->type != C_VIEW) { | 276 | if (cont->type != C_CONTAINER && cont->type != C_VIEW) { |
273 | return false; | 277 | return false; |
274 | } | 278 | } |
275 | int matches = 0; | 279 | int matches = 0; |
@@ -277,94 +281,85 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) { | |||
277 | struct crit_token *crit = tokens->items[i]; | 281 | struct crit_token *crit = tokens->items[i]; |
278 | switch (crit->type) { | 282 | switch (crit->type) { |
279 | case CRIT_CLASS: | 283 | case CRIT_CLASS: |
280 | if (!cont->class) { | 284 | { |
281 | // ignore | 285 | const char *class = view_get_class(cont->sway_view); |
282 | } else if (crit_is_focused(crit->raw)) { | 286 | if (!class) { |
283 | swayc_t *focused = get_focused_view(&root_container); | 287 | break; |
284 | if (focused->class && strcmp(cont->class, focused->class) == 0) { | 288 | } |
289 | if (crit->regex && regex_cmp(class, crit->regex) == 0) { | ||
285 | matches++; | 290 | matches++; |
286 | } | 291 | } |
287 | } else if (crit->regex && regex_cmp(cont->class, crit->regex) == 0) { | 292 | break; |
288 | matches++; | ||
289 | } | 293 | } |
290 | break; | 294 | case CRIT_CON_ID: |
291 | case CRIT_CON_ID: { | 295 | { |
292 | char *endptr; | 296 | char *endptr; |
293 | size_t crit_id = strtoul(crit->raw, &endptr, 10); | 297 | size_t crit_id = strtoul(crit->raw, &endptr, 10); |
294 | 298 | ||
295 | if (*endptr == 0 && cont->id == crit_id) { | 299 | if (*endptr == 0 && cont->id == crit_id) { |
296 | ++matches; | ||
297 | } | ||
298 | break; | ||
299 | } | ||
300 | case CRIT_CON_MARK: | ||
301 | if (crit->regex && cont->marks && (list_seq_find(cont->marks, (int (*)(const void *, const void *))regex_cmp, crit->regex) != -1)) { | ||
302 | // Make sure it isn't matching the NUL string | ||
303 | if ((strcmp(crit->raw, "") == 0) == (list_seq_find(cont->marks, (int (*)(const void *, const void *))strcmp, "") != -1)) { | ||
304 | ++matches; | 300 | ++matches; |
305 | } | 301 | } |
302 | break; | ||
306 | } | 303 | } |
304 | case CRIT_CON_MARK: | ||
305 | // TODO | ||
307 | break; | 306 | break; |
308 | case CRIT_FLOATING: | 307 | case CRIT_FLOATING: |
309 | if (cont->is_floating) { | 308 | // TODO |
310 | matches++; | ||
311 | } | ||
312 | break; | 309 | break; |
313 | case CRIT_ID: | 310 | case CRIT_ID: |
314 | if (!cont->app_id) { | 311 | // TODO |
315 | // ignore | ||
316 | } else if (crit->regex && regex_cmp(cont->app_id, crit->regex) == 0) { | ||
317 | matches++; | ||
318 | } | ||
319 | break; | 312 | break; |
313 | case CRIT_APP_ID: | ||
314 | { | ||
315 | const char *app_id = view_get_app_id(cont->sway_view); | ||
316 | if (!app_id) { | ||
317 | break; | ||
318 | } | ||
319 | |||
320 | if (crit->regex && regex_cmp(app_id, crit->regex) == 0) { | ||
321 | matches++; | ||
322 | } | ||
323 | break; | ||
324 | } | ||
320 | case CRIT_INSTANCE: | 325 | case CRIT_INSTANCE: |
321 | if (!cont->instance) { | 326 | { |
322 | // ignore | 327 | const char *instance = view_get_instance(cont->sway_view); |
323 | } else if (crit_is_focused(crit->raw)) { | 328 | if (!instance) { |
324 | swayc_t *focused = get_focused_view(&root_container); | 329 | break; |
325 | if (focused->instance && strcmp(cont->instance, focused->instance) == 0) { | 330 | } |
331 | |||
332 | if (crit->regex && regex_cmp(instance, crit->regex) == 0) { | ||
326 | matches++; | 333 | matches++; |
327 | } | 334 | } |
328 | } else if (crit->regex && regex_cmp(cont->instance, crit->regex) == 0) { | 335 | break; |
329 | matches++; | ||
330 | } | 336 | } |
331 | break; | ||
332 | case CRIT_TILING: | 337 | case CRIT_TILING: |
333 | if (!cont->is_floating) { | 338 | // TODO |
334 | matches++; | ||
335 | } | ||
336 | break; | 339 | break; |
337 | case CRIT_TITLE: | 340 | case CRIT_TITLE: |
338 | if (!cont->name) { | 341 | { |
339 | // ignore | 342 | const char *title = view_get_title(cont->sway_view); |
340 | } else if (crit_is_focused(crit->raw)) { | 343 | if (!title) { |
341 | swayc_t *focused = get_focused_view(&root_container); | 344 | break; |
342 | if (focused->name && strcmp(cont->name, focused->name) == 0) { | 345 | } |
346 | |||
347 | if (crit->regex && regex_cmp(title, crit->regex) == 0) { | ||
343 | matches++; | 348 | matches++; |
344 | } | 349 | } |
345 | } else if (crit->regex && regex_cmp(cont->name, crit->regex) == 0) { | 350 | break; |
346 | matches++; | ||
347 | } | 351 | } |
348 | break; | 352 | case CRIT_URGENT: |
349 | case CRIT_URGENT: // "latest" or "oldest" | 353 | // TODO "latest" or "oldest" |
350 | break; | 354 | break; |
351 | case CRIT_WINDOW_ROLE: | 355 | case CRIT_WINDOW_ROLE: |
356 | // TODO | ||
352 | break; | 357 | break; |
353 | case CRIT_WINDOW_TYPE: | 358 | case CRIT_WINDOW_TYPE: |
354 | // TODO wlc indeed exposes this information | 359 | // TODO |
355 | break; | 360 | break; |
356 | case CRIT_WORKSPACE: ; | 361 | case CRIT_WORKSPACE: |
357 | swayc_t *cont_ws = swayc_parent_by_type(cont, C_WORKSPACE); | 362 | // TODO |
358 | if (!cont_ws || !cont_ws->name) { | ||
359 | // ignore | ||
360 | } else if (crit_is_focused(crit->raw)) { | ||
361 | swayc_t *focused_ws = swayc_active_workspace(); | ||
362 | if (focused_ws->name && strcmp(cont_ws->name, focused_ws->name) == 0) { | ||
363 | matches++; | ||
364 | } | ||
365 | } else if (crit->regex && regex_cmp(cont_ws->name, crit->regex) == 0) { | ||
366 | matches++; | ||
367 | } | ||
368 | break; | 363 | break; |
369 | default: | 364 | default: |
370 | sway_abort("Invalid criteria type (%i)", crit->type); | 365 | sway_abort("Invalid criteria type (%i)", crit->type); |
@@ -403,7 +398,7 @@ void free_criteria(struct criteria *crit) { | |||
403 | free(crit); | 398 | free(crit); |
404 | } | 399 | } |
405 | 400 | ||
406 | bool criteria_any(swayc_t *cont, list_t *criteria) { | 401 | bool criteria_any(struct sway_container *cont, list_t *criteria) { |
407 | for (int i = 0; i < criteria->length; i++) { | 402 | for (int i = 0; i < criteria->length; i++) { |
408 | struct criteria *bc = criteria->items[i]; | 403 | struct criteria *bc = criteria->items[i]; |
409 | if (criteria_test(cont, bc->tokens)) { | 404 | if (criteria_test(cont, bc->tokens)) { |
@@ -413,7 +408,7 @@ bool criteria_any(swayc_t *cont, list_t *criteria) { | |||
413 | return false; | 408 | return false; |
414 | } | 409 | } |
415 | 410 | ||
416 | list_t *criteria_for(swayc_t *cont) { | 411 | list_t *criteria_for(struct sway_container *cont) { |
417 | list_t *criteria = config->criteria, *matches = create_list(); | 412 | list_t *criteria = config->criteria, *matches = create_list(); |
418 | for (int i = 0; i < criteria->length; i++) { | 413 | for (int i = 0; i < criteria->length; i++) { |
419 | struct criteria *bc = criteria->items[i]; | 414 | struct criteria *bc = criteria->items[i]; |
@@ -429,23 +424,22 @@ struct list_tokens { | |||
429 | list_t *tokens; | 424 | list_t *tokens; |
430 | }; | 425 | }; |
431 | 426 | ||
432 | static void container_match_add(swayc_t *container, struct list_tokens *list_tokens) { | 427 | static void container_match_add(struct sway_container *container, |
428 | struct list_tokens *list_tokens) { | ||
433 | if (criteria_test(container, list_tokens->tokens)) { | 429 | if (criteria_test(container, list_tokens->tokens)) { |
434 | list_add(list_tokens->list, container); | 430 | list_add(list_tokens->list, container); |
435 | } | 431 | } |
436 | } | 432 | } |
437 | 433 | ||
438 | list_t *container_for(list_t *tokens) { | 434 | list_t *container_for_crit_tokens(list_t *tokens) { |
439 | struct list_tokens list_tokens = (struct list_tokens){create_list(), tokens}; | 435 | struct list_tokens list_tokens = |
436 | (struct list_tokens){create_list(), tokens}; | ||
440 | 437 | ||
441 | container_map(&root_container, (void (*)(swayc_t *, void *))container_match_add, &list_tokens); | 438 | container_for_each_descendant_dfs(&root_container, |
442 | 439 | (void (*)(struct sway_container *, void *))container_match_add, | |
443 | for (int i = 0; i < scratchpad->length; ++i) { | 440 | &list_tokens); |
444 | swayc_t *c = scratchpad->items[i]; | ||
445 | if (criteria_test(c, tokens)) { | ||
446 | list_add(list_tokens.list, c); | ||
447 | } | ||
448 | } | ||
449 | 441 | ||
442 | // TODO look in the scratchpad | ||
443 | |||
450 | return list_tokens.list; | 444 | return list_tokens.list; |
451 | } | 445 | } |