query: fix three-state-parameter parsing, simplify match logic

Fixes: #2288.
This commit is contained in:
Andrew J. Hesford 2024-10-31 09:59:22 -04:00
parent 2b877d2293
commit 14aad38a2c
3 changed files with 74 additions and 92 deletions

View file

@ -419,7 +419,7 @@ Actions that execute other actions. Used in keyboard/mouse bindings.
*tiled_region* *tiled_region*
Whether the client is tiled (snapped) to the indicated Whether the client is tiled (snapped) to the indicated
region. region. The indicated region may be a glob.
*decoration* [full|border|none] *decoration* [full|border|none]
Whether the client has full server-side decorations, Whether the client has full server-side decorations,

View file

@ -71,6 +71,7 @@ view_query_create(void)
{ {
struct view_query *query = znew(*query); struct view_query *query = znew(*query);
query->window_type = -1; query->window_type = -1;
query->maximized = VIEW_AXIS_INVALID;
return query; return query;
} }
@ -88,144 +89,122 @@ view_query_free(struct view_query *query)
zfree(query); zfree(query);
} }
static enum three_state static bool
bool_to_tristate(bool b) query_tristate_match(enum three_state desired, bool actual)
{
return b ? LAB_STATE_ENABLED : LAB_STATE_DISABLED;
}
static enum three_state
match_tristate(enum three_state desired, bool actual, enum three_state old_match)
{ {
switch (desired) { switch (desired) {
case LAB_STATE_ENABLED: case LAB_STATE_ENABLED:
return bool_to_tristate(actual); return actual;
case LAB_STATE_DISABLED: case LAB_STATE_DISABLED:
return bool_to_tristate(!actual); return !actual;
default: default:
return old_match; return true;
} }
} }
static bool
query_str_match(const char *condition, const char *value)
{
if (!condition) {
return true;
}
return value && match_glob(condition, value);
}
bool bool
view_matches_query(struct view *view, struct view_query *query) view_matches_query(struct view *view, struct view_query *query)
{ {
enum three_state match = LAB_STATE_UNSPECIFIED; if (!query_str_match(query->identifier, view_get_string_prop(view, "app_id"))) {
return false;
if (query->identifier) {
const char *identifier = view_get_string_prop(view, "app_id");
if (!(identifier && match_glob(query->identifier, identifier))) {
return false;
}
} }
if (query->title) { if (!query_str_match(query->title, view_get_string_prop(view, "title"))) {
const char *title = view_get_string_prop(view, "title"); return false;
if (!(title && match_glob(query->title, title))) {
return false;
}
} }
if (query->window_type >= 0) { if (query->window_type >= 0 && !view_contains_window_type(view, query->window_type)) {
if (!view_contains_window_type(view, query->window_type)) { return false;
return false;
}
} }
if (query->sandbox_engine) { if (query->sandbox_engine || query->sandbox_app_id) {
const struct wlr_security_context_v1_state *security_context = const struct wlr_security_context_v1_state *ctx =
security_context_from_view(view); security_context_from_view(view);
if (!(security_context && security_context->sandbox_engine &&
match_glob(query->sandbox_engine, security_context->sandbox_engine))) { if (!ctx) {
return false;
}
if (!query_str_match(query->sandbox_engine, ctx->sandbox_engine)) {
return false;
}
if (!query_str_match(query->sandbox_app_id, ctx->app_id)) {
return false; return false;
} }
} }
if (query->sandbox_app_id) { if (!query_tristate_match(query->shaded, view->shaded)) {
const struct wlr_security_context_v1_state *security_context =
security_context_from_view(view);
if (!(security_context && security_context->app_id &&
match_glob(query->sandbox_app_id, security_context->app_id))) {
return false;
}
}
match = match_tristate(query->shaded, view->shaded, match);
if (match == LAB_STATE_DISABLED) {
return false; return false;
} }
if (query->maximized != VIEW_AXIS_INVALID) { if (query->maximized != VIEW_AXIS_INVALID && view->maximized != query->maximized) {
match = bool_to_tristate(view->maximized == query->maximized);
if (match == LAB_STATE_DISABLED) {
return false;
}
}
match = match_tristate(query->iconified, view->minimized, match);
if (match == LAB_STATE_DISABLED) {
return false; return false;
} }
match = match_tristate(query->focused, view->server->active_view == view, match); if (!query_tristate_match(query->iconified, view->minimized)) {
if (match == LAB_STATE_DISABLED) {
return false; return false;
} }
match = match_tristate(query->omnipresent, view->visible_on_all_workspaces, match); if (!query_tristate_match(query->focused, view->server->active_view == view)) {
if (match == LAB_STATE_DISABLED) {
return false; return false;
} }
if (query->tiled != VIEW_EDGE_INVALID) { if (!query_tristate_match(query->omnipresent, view->visible_on_all_workspaces)) {
match = bool_to_tristate(query->tiled == view->tiled); return false;
if (match == LAB_STATE_DISABLED) {
return false;
}
} }
if (query->tiled_region) { if (query->tiled != VIEW_EDGE_INVALID && query->tiled != view->tiled) {
match = bool_to_tristate(view->tiled_region && return false;
!strcasecmp(query->tiled_region, view->tiled_region->name)); }
if (match == LAB_STATE_DISABLED) {
return false; const char *tiled_region =
} view->tiled_region ? view->tiled_region->name : NULL;
if (!query_str_match(query->tiled_region, tiled_region)) {
return false;
} }
if (query->desktop) { if (query->desktop) {
const char *view_workspace = view->workspace->name;
struct workspace *current = view->server->workspaces.current;
if (!strcasecmp(query->desktop, "other")) { if (!strcasecmp(query->desktop, "other")) {
struct workspace *current = view->server->workspaces.current; /* "other" means the view is NOT on the current desktop */
match = bool_to_tristate(strcasecmp(view->workspace->name, current->name)); if (!strcasecmp(view_workspace, current->name)) {
return false;
}
} else { } else {
// TODO: perhaps allow wrapping for "left" and "right" workspaces // TODO: perhaps wrap "left" and "right" workspaces
struct workspace *target = struct workspace *target =
workspaces_find(view->server->workspaces.current, workspaces_find(current, query->desktop, /* wrap */ false);
query->desktop, false); if (!target || strcasecmp(view_workspace, target->name)) {
match = bool_to_tristate(target && return false;
!strcasecmp(view->workspace->name, target->name)); }
}
if (match == LAB_STATE_DISABLED) {
return false;
} }
} }
enum ssd_mode decoration = view_get_ssd_mode(view); enum ssd_mode decor = view_get_ssd_mode(view);
if (query->decoration != LAB_SSD_MODE_INVALID) { if (query->decoration != LAB_SSD_MODE_INVALID && query->decoration != decor) {
match = bool_to_tristate(query->decoration == decoration); return false;
if (match == LAB_STATE_DISABLED) {
return false;
}
} }
if (query->monitor) { if (query->monitor) {
struct output *target = output_from_name(view->server, query->monitor); struct output *target = output_from_name(view->server, query->monitor);
match = bool_to_tristate(target == view->output); if (target != view->output) {
if (match == LAB_STATE_DISABLED) {
return false; return false;
} }
} }
return match == LAB_STATE_ENABLED; return true;
} }
static bool static bool

View file

@ -30,16 +30,19 @@ other_instances_exist(struct view *self, struct view_query *query)
static bool static bool
view_matches_criteria(struct window_rule *rule, struct view *view) view_matches_criteria(struct window_rule *rule, struct view *view)
{ {
struct view_query query = {0}; struct view_query query = {
query.identifier = rule->identifier; .identifier = rule->identifier,
query.title = rule->title; .title = rule->title,
query.window_type = rule->window_type; .window_type = rule->window_type,
query.sandbox_engine = rule->sandbox_engine; .sandbox_engine = rule->sandbox_engine,
query.sandbox_app_id = rule->sandbox_app_id; .sandbox_app_id = rule->sandbox_app_id,
.maximized = VIEW_AXIS_INVALID,
};
if (rule->match_once && other_instances_exist(view, &query)) { if (rule->match_once && other_instances_exist(view, &query)) {
return false; return false;
} }
return view_matches_query(view, &query); return view_matches_query(view, &query);
} }