criteria: fix __focused__ when no focus or unset

This fixes the behavior of `__focused__` when there is no focused view
to match i3's behavior of successfully matching no views instead of
returning an error of a missing value. It also applies the same logic
when a token is not applicable (or unset) for a view such as `app_id`
for a focused xwayland view or `class` for a focused xdg-shell view.

This adds an `autofail` boolean to `struct criteria`. If it is set to
`true`, then `criteria_matches_view` will immediately bail out as a
no match. If `autofail` is set, the criteria will also not be
considered empty by `criteria_is_empty`.

To set this new `autofail` property, `get_focused_prop` will now take
in a boolean pointer of the same name. If `__focused__` is supported
for the token and there is no focused view or the focused view does not
have a value for the token, then the boolean will be set to true. In
`parse_token`, the boolean value will be checked and if set to true,
then `criteria->autofail` will be set to true and `parse_token` will
bail successfully. Tokens will still be parsed to make sure the whole
criteria is syntactically valid, which is also why
`&criteria->autofail` is not passed to `get_focused_prop` and a local
boolean is declared in `parse_token`.
This commit is contained in:
Brian Ashworth 2019-03-23 03:49:29 -04:00 committed by emersion
parent 8cd7f0171a
commit 7d2076cbff
2 changed files with 49 additions and 21 deletions

View File

@ -20,6 +20,7 @@ struct criteria {
char *cmdlist;
char *target; // workspace or output name for `assign` criteria
bool autofail; // __focused__ while no focus or n/a for focused view
pcre *title;
pcre *shell;
pcre *app_id;

View File

@ -16,7 +16,8 @@
#include "config.h"
bool criteria_is_empty(struct criteria *criteria) {
return !criteria->title
return !criteria->autofail
&& !criteria->title
&& !criteria->shell
&& !criteria->app_id
&& !criteria->con_mark
@ -98,6 +99,10 @@ static void find_urgent_iterator(struct sway_container *con, void *data) {
static bool criteria_matches_view(struct criteria *criteria,
struct sway_view *view) {
if (criteria->autofail) {
return false;
}
if (criteria->title) {
const char *title = view_get_title(view);
if (!title || regex_cmp(title, criteria->title) != 0) {
@ -366,50 +371,66 @@ static enum criteria_token token_from_name(char *name) {
* using criteria via IPC. Using __focused__ in config is not useful because
* criteria is only executed once per view.
*/
static char *get_focused_prop(enum criteria_token token) {
static char *get_focused_prop(enum criteria_token token, bool *autofail) {
struct sway_seat *seat = input_manager_current_seat();
struct sway_container *focus = seat_get_focused_container(seat);
if (!focus || !focus->view) {
return NULL;
}
struct sway_view *view = focus->view;
struct sway_view *view = focus ? focus->view : NULL;
const char *value = NULL;
switch (token) {
case T_APP_ID:
value = view_get_app_id(view);
*autofail = true;
if (view) {
value = view_get_app_id(view);
}
break;
case T_SHELL:
value = view_get_shell(view);
*autofail = true;
if (view) {
value = view_get_shell(view);
}
break;
case T_TITLE:
value = view_get_title(view);
*autofail = true;
if (view) {
value = view_get_title(view);
}
break;
case T_WORKSPACE:
if (focus->workspace) {
*autofail = true;
if (focus && focus->workspace) {
value = focus->workspace->name;
}
break;
case T_CON_ID:
if (view->container == NULL) {
return NULL;
*autofail = true;
if (view && view->container) {
size_t id = view->container->node.id;
size_t id_size = snprintf(NULL, 0, "%zu", id) + 1;
char *id_str = malloc(id_size);
snprintf(id_str, id_size, "%zu", id);
value = id_str;
}
size_t id = view->container->node.id;
size_t id_size = snprintf(NULL, 0, "%zu", id) + 1;
char *id_str = malloc(id_size);
snprintf(id_str, id_size, "%zu", id);
value = id_str;
break;
#if HAVE_XWAYLAND
case T_CLASS:
value = view_get_class(view);
*autofail = true;
if (view) {
value = view_get_class(view);
}
break;
case T_INSTANCE:
value = view_get_instance(view);
*autofail = true;
if (view) {
value = view_get_instance(view);
}
break;
case T_WINDOW_ROLE:
value = view_get_window_role(view);
*autofail = true;
if (view) {
value = view_get_window_role(view);
}
break;
case T_WINDOW_TYPE: // These do not support __focused__
case T_ID:
@ -419,6 +440,7 @@ static char *get_focused_prop(enum criteria_token token) {
case T_TILING:
case T_URGENT:
case T_INVALID:
*autofail = false;
break;
}
if (value) {
@ -439,7 +461,12 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
char *effective_value = NULL;
if (value && strcmp(value, "__focused__") == 0) {
effective_value = get_focused_prop(token);
bool autofail = false;
effective_value = get_focused_prop(token, &autofail);
if (!effective_value && autofail) {
criteria->autofail = true;
return true;
}
} else if (value) {
effective_value = strdup(value);
}