criteria: Allow re-execution of criteria

Currently, criteria are executed only once. This limits their usefulness
for reacting to properties of windows that change over time, for example
existance and state of idle or keyboard shortcuts inhibitors (for which
criteria are to be implemented in a separate change).

This change keeps the principal behaviour of not re-executing criteria
while their matching state has not changed. But as soon as a criterion
no longer matches, it will be removed from the list of already executed
criteria. This allows its action to be re-executed once the criterion
once again matches the view.

Since function criteria_for_view() returns a list of all currently
matching criteria, this can be trivially implemented and is even
slightly more efficient than before: Instead of checking each matching
criterion against the list of already executed criteria and potentially
executing and adding it, we just make the list returned by
criteria_for_view() the new list of executed criteria. Then we walk
through it and execute every criterion not already in the old list of
exectued criteria. Adding the criterion to the list becomes redundant.
The old list is freed at the end.

With this approach we implicitly forget about any criteria we may have
executed in the past which no longer match the view right now.

As an additional simplification, function view_has_executed_criteria()
is replaced by list_find() since it does the same thing.

Since execution behaviour was not documented explicitly before, we add a
note to sway(5) on how it is behaving now.

Signed-off-by: Michael Weiser <michael.weiser@gmx.de>
This commit is contained in:
Michael Weiser 2020-03-18 21:19:03 +01:00
parent 726d187d3c
commit d318262712
2 changed files with 18 additions and 17 deletions

View file

@ -841,6 +841,14 @@ Kill all windows with the title "Emacs":
[class="Emacs"] kill
```
Criteria are applied on state changes of a view. These currently are mapping
(i.e. opening of a window), adding or removing marks and setting title, app_id,
class, role or window type.
Criteria will be executed once when first applied or when the view changes its
attributes to match. They will be re-executed only after the view did not match
a least once.
You may like to use swaymsg -t get_tree for finding the values of these
properties in practice for your applications.

View file

@ -414,29 +414,22 @@ static void view_handle_surface_new_subsurface(struct wl_listener *listener,
view_subsurface_create(view, subsurface);
}
static bool view_has_executed_criteria(struct sway_view *view,
struct criteria *criteria) {
for (int i = 0; i < view->executed_criteria->length; ++i) {
struct criteria *item = view->executed_criteria->items[i];
if (item == criteria) {
return true;
}
}
return false;
}
void view_execute_criteria(struct sway_view *view) {
list_t *criterias = criteria_for_view(view, CT_COMMAND);
for (int i = 0; i < criterias->length; i++) {
struct criteria *criteria = criterias->items[i];
// replacing list of executed criteria removes those that do no longer
// match the view, opening them up for re-execution once they match
// again
list_t *previously_executed = view->executed_criteria;
view->executed_criteria = criteria_for_view(view, CT_COMMAND);
for (int i = 0; i < view->executed_criteria->length; i++) {
struct criteria *criteria = view->executed_criteria->items[i];
sway_log(SWAY_DEBUG, "Checking criteria %s", criteria->raw);
if (view_has_executed_criteria(view, criteria)) {
if (list_find(previously_executed, criteria) >= 0) {
sway_log(SWAY_DEBUG, "Criteria already executed");
continue;
}
sway_log(SWAY_DEBUG, "for_window '%s' matches view %p, cmd: '%s'",
criteria->raw, view, criteria->cmdlist);
list_add(view->executed_criteria, criteria);
list_t *res_list = execute_command(
criteria->cmdlist, NULL, view->container);
while (res_list->length) {
@ -446,7 +439,7 @@ void view_execute_criteria(struct sway_view *view) {
}
list_free(res_list);
}
list_free(criterias);
list_free(previously_executed);
}
static void view_populate_pid(struct sway_view *view) {