Fix logical error in criteria matching

When evaluating a __focused__ pattern, sway's logic is to consider the
pattern match to have failed for a given view and attribute if a view is
focused and the value of attribute in question of the focused view is
not that of the view in question. Expected behaviour is that the pattern
matches if there is a focused view and that the values of the attribute
for the focused view and the other view are equal. (See #6753, which is
the case where the `workspace` attribute is matched against.). I.e., if
we write out the function `criteria_matches_view` as a logical formula,
expected behaviour is

    criteria_matches_view(criteria, view) <=>
        forall (attribute, pattern) in criteria,
        (pattern is __focused__ and
            focused view exists and view.attribute == focused.attribute)
        or
        (pattern is not __focused__ and view.attribute =~ pattern)

but it is actually (pay attention to the fourth line)

    criteria_matches_view(criteria, view) <=>
        forall (attribute, pattern) in criteria,
        (pattern is __focused__ and
            (no focused view or view.attribute == focused.attribute))
        or
        (pattern is not __focused__ and view.attribute =~ pattern).

Fix program logic to reflect (the disjunctive form of) the first formula
to be compatible with i3. (In passing, this fixes #6753.)
This commit is contained in:
André Marçais 2026-01-12 15:50:39 +01:00
parent 40aabb80c6
commit 6abe7313fd

View file

@ -204,7 +204,7 @@ static bool criteria_matches_view(struct criteria *criteria,
switch (criteria->title->match_type) {
case PATTERN_FOCUSED:
if (focused && lenient_strcmp(title, view_get_title(focused))) {
if (!focused || lenient_strcmp(title, view_get_title(focused))) {
return false;
}
break;
@ -224,7 +224,7 @@ static bool criteria_matches_view(struct criteria *criteria,
switch (criteria->shell->match_type) {
case PATTERN_FOCUSED:
if (focused && strcmp(shell, view_get_shell(focused))) {
if (!focused || strcmp(shell, view_get_shell(focused))) {
return false;
}
break;
@ -244,7 +244,7 @@ static bool criteria_matches_view(struct criteria *criteria,
switch (criteria->app_id->match_type) {
case PATTERN_FOCUSED:
if (focused && lenient_strcmp(app_id, view_get_app_id(focused))) {
if (!focused || lenient_strcmp(app_id, view_get_app_id(focused))) {
return false;
}
break;
@ -264,7 +264,7 @@ static bool criteria_matches_view(struct criteria *criteria,
switch (criteria->sandbox_engine->match_type) {
case PATTERN_FOCUSED:
if (focused && lenient_strcmp(sandbox_engine, view_get_sandbox_engine(focused))) {
if (!focused || lenient_strcmp(sandbox_engine, view_get_sandbox_engine(focused))) {
return false;
}
break;
@ -284,7 +284,7 @@ static bool criteria_matches_view(struct criteria *criteria,
switch (criteria->sandbox_app_id->match_type) {
case PATTERN_FOCUSED:
if (focused && lenient_strcmp(sandbox_app_id, view_get_sandbox_app_id(focused))) {
if (!focused || lenient_strcmp(sandbox_app_id, view_get_sandbox_app_id(focused))) {
return false;
}
break;
@ -304,7 +304,7 @@ static bool criteria_matches_view(struct criteria *criteria,
switch (criteria->sandbox_instance_id->match_type) {
case PATTERN_FOCUSED:
if (focused && lenient_strcmp(sandbox_instance_id, view_get_sandbox_instance_id(focused))) {
if (!focused || lenient_strcmp(sandbox_instance_id, view_get_sandbox_instance_id(focused))) {
return false;
}
break;
@ -324,7 +324,7 @@ static bool criteria_matches_view(struct criteria *criteria,
switch (criteria->tag->match_type) {
case PATTERN_FOCUSED:
if (focused && lenient_strcmp(tag, view_get_tag(focused))) {
if (!focused || lenient_strcmp(tag, view_get_tag(focused))) {
return false;
}
break;
@ -356,7 +356,7 @@ static bool criteria_matches_view(struct criteria *criteria,
switch (criteria->class->match_type) {
case PATTERN_FOCUSED:
if (focused && lenient_strcmp(class, view_get_class(focused))) {
if (!focused || lenient_strcmp(class, view_get_class(focused))) {
return false;
}
break;
@ -376,7 +376,7 @@ static bool criteria_matches_view(struct criteria *criteria,
switch (criteria->instance->match_type) {
case PATTERN_FOCUSED:
if (focused && lenient_strcmp(instance, view_get_instance(focused))) {
if (!focused || lenient_strcmp(instance, view_get_instance(focused))) {
return false;
}
break;
@ -396,7 +396,7 @@ static bool criteria_matches_view(struct criteria *criteria,
switch (criteria->window_role->match_type) {
case PATTERN_FOCUSED:
if (focused && lenient_strcmp(window_role, view_get_window_role(focused))) {
if (!focused || lenient_strcmp(window_role, view_get_window_role(focused))) {
return false;
}
break;
@ -454,7 +454,7 @@ static bool criteria_matches_view(struct criteria *criteria,
switch (criteria->workspace->match_type) {
case PATTERN_FOCUSED:
if (focused &&
if (!focused ||
strcmp(ws->name, focused->container->pending.workspace->name)) {
return false;
}