From 9c30140b0a14f803a357bff3e1869bca31189891 Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Wed, 5 Aug 2020 15:26:22 -0400 Subject: [PATCH] Add trigger information to criteria This allows writing commands like "for_window [trigger="map",workspace="1"]" that only execute if the criteria matches during the initial mapping of the window. Currently implemented trigger names: - command: explicit invocation by a command, not very useful - map: initial window creation - mark, title, app_id, class, window_role, window_type: the given property changed --- include/sway/criteria.h | 5 +++-- include/sway/tree/view.h | 2 +- sway/commands.c | 2 +- sway/commands/mark.c | 2 +- sway/criteria.c | 24 +++++++++++++++++++----- sway/desktop/xdg_shell.c | 4 ++-- sway/desktop/xwayland.c | 8 ++++---- sway/tree/view.c | 10 +++++----- 8 files changed, 36 insertions(+), 21 deletions(-) diff --git a/include/sway/criteria.h b/include/sway/criteria.h index ad8610cd7..79386a0d7 100644 --- a/include/sway/criteria.h +++ b/include/sway/criteria.h @@ -34,6 +34,7 @@ struct criteria { struct pattern *shell; struct pattern *app_id; struct pattern *con_mark; + char *trigger; // event that triggered this criteria match uint32_t con_id; // internal ID #if HAVE_XWAYLAND struct pattern *class; @@ -71,11 +72,11 @@ struct criteria *criteria_parse(char *raw, char **error); * * Criteria types can be bitwise ORed. */ -list_t *criteria_for_view(struct sway_view *view, enum criteria_type types); +list_t *criteria_for_view(struct sway_view *view, enum criteria_type types, const char* trigger); /** * Compile a list of containers matching the given criteria. */ -list_t *criteria_get_containers(struct criteria *criteria); +list_t *criteria_get_containers(struct criteria *criteria, const char* trigger); #endif diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 6cfabf3b7..92b81a1ba 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -341,7 +341,7 @@ void view_update_title(struct sway_view *view, bool force); * Run any criteria that match the view and haven't been run on this view * before. */ -void view_execute_criteria(struct sway_view *view); +void view_execute_criteria(struct sway_view *view, const char* trigger); /** * Returns true if there's a possibility the view may be rendered on screen. diff --git a/sway/commands.c b/sway/commands.c index fe1e98b53..d4bfd5b47 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -236,7 +236,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat, goto cleanup; } list_free(containers); - containers = criteria_get_containers(criteria); + containers = criteria_get_containers(criteria, "command"); head += strlen(criteria->raw); criteria_destroy(criteria); config->handler_context.using_criteria = true; diff --git a/sway/commands/mark.c b/sway/commands/mark.c index aa5f185c8..bc68586dc 100644 --- a/sway/commands/mark.c +++ b/sway/commands/mark.c @@ -61,7 +61,7 @@ struct cmd_results *cmd_mark(int argc, char **argv) { free(mark); container_update_marks_textures(container); if (container->view) { - view_execute_criteria(container->view); + view_execute_criteria(container->view, "mark"); } return cmd_results_new(CMD_SUCCESS, NULL); diff --git a/sway/criteria.c b/sway/criteria.c index 02b04fc89..813b8fe69 100644 --- a/sway/criteria.c +++ b/sway/criteria.c @@ -20,6 +20,7 @@ bool criteria_is_empty(struct criteria *criteria) { && !criteria->shell && !criteria->app_id && !criteria->con_mark + && !criteria->trigger && !criteria->con_id #if HAVE_XWAYLAND && !criteria->class @@ -93,6 +94,7 @@ void criteria_destroy(struct criteria *criteria) { pattern_destroy(criteria->window_role); #endif pattern_destroy(criteria->con_mark); + free(criteria->trigger); free(criteria->workspace); free(criteria->cmdlist); free(criteria->raw); @@ -175,11 +177,15 @@ static bool criteria_matches_container(struct criteria *criteria, } static bool criteria_matches_view(struct criteria *criteria, - struct sway_view *view) { + struct sway_view *view, const char* trigger) { struct sway_seat *seat = input_manager_current_seat(); struct sway_container *focus = seat_get_focused_container(seat); struct sway_view *focused = focus ? focus->view : NULL; + if (criteria->trigger && trigger && strcmp(criteria->trigger, trigger)) { + return false; + } + if (criteria->title) { const char *title = view_get_title(view); if (!title) { @@ -380,12 +386,12 @@ static bool criteria_matches_view(struct criteria *criteria, return true; } -list_t *criteria_for_view(struct sway_view *view, enum criteria_type types) { +list_t *criteria_for_view(struct sway_view *view, enum criteria_type types, const char* trigger) { list_t *criterias = config->criteria; list_t *matches = create_list(); for (int i = 0; i < criterias->length; ++i) { struct criteria *criteria = criterias->items[i]; - if ((criteria->type & types) && criteria_matches_view(criteria, view)) { + if ((criteria->type & types) && criteria_matches_view(criteria, view, trigger)) { list_add(matches, criteria); } } @@ -395,13 +401,14 @@ list_t *criteria_for_view(struct sway_view *view, enum criteria_type types) { struct match_data { struct criteria *criteria; list_t *matches; + const char* trigger; }; static void criteria_get_containers_iterator(struct sway_container *container, void *data) { struct match_data *match_data = data; if (container->view) { - if (criteria_matches_view(match_data->criteria, container->view)) { + if (criteria_matches_view(match_data->criteria, container->view, match_data->trigger)) { list_add(match_data->matches, container); } } else if (has_container_criteria(match_data->criteria)) { @@ -411,11 +418,12 @@ static void criteria_get_containers_iterator(struct sway_container *container, } } -list_t *criteria_get_containers(struct criteria *criteria) { +list_t *criteria_get_containers(struct criteria *criteria, const char* trigger) { list_t *matches = create_list(); struct match_data data = { .criteria = criteria, .matches = matches, + .trigger = trigger, }; root_for_each_container(criteria_get_containers_iterator, &data); return matches; @@ -466,6 +474,7 @@ enum criteria_token { T_URGENT, T_WORKSPACE, T_PID, + T_TRIGGER, T_INVALID, }; @@ -475,6 +484,8 @@ static enum criteria_token token_from_name(char *name) { return T_APP_ID; } else if (strcmp(name, "con_id") == 0) { return T_CON_ID; + } else if (strcmp(name, "trigger") == 0) { + return T_TRIGGER; } else if (strcmp(name, "con_mark") == 0) { return T_CON_MARK; #if HAVE_XWAYLAND @@ -550,6 +561,9 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) { } } break; + case T_TRIGGER: + criteria->trigger = strdup(value); + break; case T_CON_MARK: pattern_create(&criteria->con_mark, value); break; diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 03f372416..fc89c48eb 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -317,14 +317,14 @@ static void handle_set_title(struct wl_listener *listener, void *data) { wl_container_of(listener, xdg_shell_view, set_title); struct sway_view *view = &xdg_shell_view->view; view_update_title(view, false); - view_execute_criteria(view); + view_execute_criteria(view, "title"); } static void handle_set_app_id(struct wl_listener *listener, void *data) { struct sway_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, set_app_id); struct sway_view *view = &xdg_shell_view->view; - view_execute_criteria(view); + view_execute_criteria(view, "app_id"); } static void handle_new_popup(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index db21dc785..c92be3b71 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -582,7 +582,7 @@ static void handle_set_title(struct wl_listener *listener, void *data) { return; } view_update_title(view, false); - view_execute_criteria(view); + view_execute_criteria(view, "title"); } static void handle_set_class(struct wl_listener *listener, void *data) { @@ -593,7 +593,7 @@ static void handle_set_class(struct wl_listener *listener, void *data) { if (!xsurface->mapped) { return; } - view_execute_criteria(view); + view_execute_criteria(view, "class"); } static void handle_set_role(struct wl_listener *listener, void *data) { @@ -604,7 +604,7 @@ static void handle_set_role(struct wl_listener *listener, void *data) { if (!xsurface->mapped) { return; } - view_execute_criteria(view); + view_execute_criteria(view, "window_role"); } static void handle_set_window_type(struct wl_listener *listener, void *data) { @@ -615,7 +615,7 @@ static void handle_set_window_type(struct wl_listener *listener, void *data) { if (!xsurface->mapped) { return; } - view_execute_criteria(view); + view_execute_criteria(view, "window_type"); } static void handle_set_hints(struct wl_listener *listener, void *data) { diff --git a/sway/tree/view.c b/sway/tree/view.c index 7bba29234..4debcae23 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -483,8 +483,8 @@ static bool view_has_executed_criteria(struct sway_view *view, return false; } -void view_execute_criteria(struct sway_view *view) { - list_t *criterias = criteria_for_view(view, CT_COMMAND); +void view_execute_criteria(struct sway_view *view, const char* trigger) { + list_t *criterias = criteria_for_view(view, CT_COMMAND, trigger); for (int i = 0; i < criterias->length; i++) { struct criteria *criteria = criterias->items[i]; sway_log(SWAY_DEBUG, "Checking criteria %s", criteria->raw); @@ -531,7 +531,7 @@ static struct sway_workspace *select_workspace(struct sway_view *view) { // Check if there's any `assign` criteria for the view list_t *criterias = criteria_for_view(view, - CT_ASSIGN_WORKSPACE | CT_ASSIGN_WORKSPACE_NUMBER | CT_ASSIGN_OUTPUT); + CT_ASSIGN_WORKSPACE | CT_ASSIGN_WORKSPACE_NUMBER | CT_ASSIGN_OUTPUT, NULL); struct sway_workspace *ws = NULL; for (int i = 0; i < criterias->length; ++i) { struct criteria *criteria = criterias->items[i]; @@ -611,7 +611,7 @@ static bool should_focus(struct sway_view *view) { } // Check no_focus criteria - list_t *criterias = criteria_for_view(view, CT_NO_FOCUS); + list_t *criterias = criteria_for_view(view, CT_NO_FOCUS, NULL); size_t len = criterias->length; list_free(criterias); return len == 0; @@ -781,7 +781,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, } } - view_execute_criteria(view); + view_execute_criteria(view, "map"); if (should_focus(view)) { input_manager_set_focus(&view->container->node);