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
This commit is contained in:
Daniel De Graaf 2020-08-05 15:26:22 -04:00
parent 2704e07c49
commit 80f4fce972
8 changed files with 36 additions and 21 deletions

View file

@ -36,6 +36,7 @@ struct criteria {
struct pattern *app_id; struct pattern *app_id;
struct pattern *con_mark; struct pattern *con_mark;
struct pattern *cli_label; struct pattern *cli_label;
char *trigger; // event that triggered this criteria match
uint32_t con_id; // internal ID uint32_t con_id; // internal ID
#if HAVE_XWAYLAND #if HAVE_XWAYLAND
struct pattern *class; struct pattern *class;
@ -73,11 +74,11 @@ struct criteria *criteria_parse(char *raw, char **error);
* *
* Criteria types can be bitwise ORed. * 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. * 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 #endif

View file

@ -355,7 +355,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 * Run any criteria that match the view and haven't been run on this view
* before. * 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. * Returns true if there's a possibility the view may be rendered on screen.

View file

@ -240,7 +240,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
goto cleanup; goto cleanup;
} }
list_free(containers); list_free(containers);
containers = criteria_get_containers(criteria); containers = criteria_get_containers(criteria, "command");
head += strlen(criteria->raw); head += strlen(criteria->raw);
criteria_destroy(criteria); criteria_destroy(criteria);
using_criteria = true; using_criteria = true;

View file

@ -61,7 +61,7 @@ struct cmd_results *cmd_mark(int argc, char **argv) {
free(mark); free(mark);
container_update_marks_textures(container); container_update_marks_textures(container);
if (container->view) { if (container->view) {
view_execute_criteria(container->view); view_execute_criteria(container->view, "mark");
} }
return cmd_results_new(CMD_SUCCESS, NULL); return cmd_results_new(CMD_SUCCESS, NULL);

View file

@ -22,6 +22,7 @@ bool criteria_is_empty(struct criteria *criteria) {
&& !criteria->app_id && !criteria->app_id
&& !criteria->con_mark && !criteria->con_mark
&& !criteria->cli_label && !criteria->cli_label
&& !criteria->trigger
&& !criteria->con_id && !criteria->con_id
#if HAVE_XWAYLAND #if HAVE_XWAYLAND
&& !criteria->class && !criteria->class
@ -98,6 +99,7 @@ void criteria_destroy(struct criteria *criteria) {
#endif #endif
pattern_destroy(criteria->con_mark); pattern_destroy(criteria->con_mark);
pattern_destroy(criteria->cli_label); pattern_destroy(criteria->cli_label);
free(criteria->trigger);
free(criteria->workspace); free(criteria->workspace);
free(criteria->cmdlist); free(criteria->cmdlist);
free(criteria->raw); free(criteria->raw);
@ -183,11 +185,15 @@ static bool criteria_matches_container(struct criteria *criteria,
} }
static bool criteria_matches_view(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_seat *seat = input_manager_current_seat();
struct sway_container *focus = seat_get_focused_container(seat); struct sway_container *focus = seat_get_focused_container(seat);
struct sway_view *focused = focus ? focus->view : NULL; struct sway_view *focused = focus ? focus->view : NULL;
if (criteria->trigger && trigger && strcmp(criteria->trigger, trigger)) {
return false;
}
if (criteria->title) { if (criteria->title) {
const char *title = view_get_title(view); const char *title = view_get_title(view);
if (!title) { if (!title) {
@ -408,12 +414,12 @@ static bool criteria_matches_view(struct criteria *criteria,
return true; 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 *criterias = config->criteria;
list_t *matches = create_list(); list_t *matches = create_list();
for (int i = 0; i < criterias->length; ++i) { for (int i = 0; i < criterias->length; ++i) {
struct criteria *criteria = criterias->items[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); list_add(matches, criteria);
} }
} }
@ -423,13 +429,14 @@ list_t *criteria_for_view(struct sway_view *view, enum criteria_type types) {
struct match_data { struct match_data {
struct criteria *criteria; struct criteria *criteria;
list_t *matches; list_t *matches;
const char* trigger;
}; };
static void criteria_get_containers_iterator(struct sway_container *container, static void criteria_get_containers_iterator(struct sway_container *container,
void *data) { void *data) {
struct match_data *match_data = data; struct match_data *match_data = data;
if (container->view) { 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); list_add(match_data->matches, container);
} }
} else if (has_container_criteria(match_data->criteria)) { } else if (has_container_criteria(match_data->criteria)) {
@ -439,11 +446,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(); list_t *matches = create_list();
struct match_data data = { struct match_data data = {
.criteria = criteria, .criteria = criteria,
.matches = matches, .matches = matches,
.trigger = trigger,
}; };
root_for_each_container(criteria_get_containers_iterator, &data); root_for_each_container(criteria_get_containers_iterator, &data);
return matches; return matches;
@ -495,6 +503,7 @@ enum criteria_token {
T_URGENT, T_URGENT,
T_WORKSPACE, T_WORKSPACE,
T_PID, T_PID,
T_TRIGGER,
T_INVALID, T_INVALID,
}; };
@ -504,6 +513,8 @@ static enum criteria_token token_from_name(char *name) {
return T_APP_ID; return T_APP_ID;
} else if (strcmp(name, "con_id") == 0) { } else if (strcmp(name, "con_id") == 0) {
return T_CON_ID; return T_CON_ID;
} else if (strcmp(name, "trigger") == 0) {
return T_TRIGGER;
} else if (strcmp(name, "con_mark") == 0) { } else if (strcmp(name, "con_mark") == 0) {
return T_CON_MARK; return T_CON_MARK;
} else if (strcmp(name, "cli_label") == 0) { } else if (strcmp(name, "cli_label") == 0) {
@ -581,6 +592,9 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
} }
} }
break; break;
case T_TRIGGER:
criteria->trigger = strdup(value);
break;
case T_CON_MARK: case T_CON_MARK:
pattern_create(&criteria->con_mark, value); pattern_create(&criteria->con_mark, value);
break; break;

View file

@ -309,14 +309,14 @@ static void handle_set_title(struct wl_listener *listener, void *data) {
wl_container_of(listener, xdg_shell_view, set_title); wl_container_of(listener, xdg_shell_view, set_title);
struct sway_view *view = &xdg_shell_view->view; struct sway_view *view = &xdg_shell_view->view;
view_update_title(view, false); 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) { static void handle_set_app_id(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_view *xdg_shell_view = struct sway_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, set_app_id); wl_container_of(listener, xdg_shell_view, set_app_id);
struct sway_view *view = &xdg_shell_view->view; 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) { static void handle_new_popup(struct wl_listener *listener, void *data) {

View file

@ -640,7 +640,7 @@ static void handle_set_title(struct wl_listener *listener, void *data) {
return; return;
} }
view_update_title(view, false); 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) { static void handle_set_class(struct wl_listener *listener, void *data) {
@ -651,7 +651,7 @@ static void handle_set_class(struct wl_listener *listener, void *data) {
if (!xsurface->mapped) { if (!xsurface->mapped) {
return; return;
} }
view_execute_criteria(view); view_execute_criteria(view, "class");
} }
static void handle_set_role(struct wl_listener *listener, void *data) { static void handle_set_role(struct wl_listener *listener, void *data) {
@ -662,7 +662,7 @@ static void handle_set_role(struct wl_listener *listener, void *data) {
if (!xsurface->mapped) { if (!xsurface->mapped) {
return; return;
} }
view_execute_criteria(view); view_execute_criteria(view, "window_role");
} }
static void handle_set_window_type(struct wl_listener *listener, void *data) { static void handle_set_window_type(struct wl_listener *listener, void *data) {
@ -673,7 +673,7 @@ static void handle_set_window_type(struct wl_listener *listener, void *data) {
if (!xsurface->mapped) { if (!xsurface->mapped) {
return; return;
} }
view_execute_criteria(view); view_execute_criteria(view, "window_type");
} }
static void handle_set_hints(struct wl_listener *listener, void *data) { static void handle_set_hints(struct wl_listener *listener, void *data) {

View file

@ -506,8 +506,8 @@ static bool view_has_executed_criteria(struct sway_view *view,
return false; return false;
} }
void view_execute_criteria(struct sway_view *view) { void view_execute_criteria(struct sway_view *view, const char* trigger) {
list_t *criterias = criteria_for_view(view, CT_COMMAND); list_t *criterias = criteria_for_view(view, CT_COMMAND, trigger);
for (int i = 0; i < criterias->length; i++) { for (int i = 0; i < criterias->length; i++) {
struct criteria *criteria = criterias->items[i]; struct criteria *criteria = criterias->items[i];
sway_log(SWAY_DEBUG, "Checking criteria %s", criteria->raw); sway_log(SWAY_DEBUG, "Checking criteria %s", criteria->raw);
@ -554,7 +554,7 @@ static struct sway_workspace *select_workspace(struct sway_view *view) {
// Check if there's any `assign` criteria for the view // Check if there's any `assign` criteria for the view
list_t *criterias = criteria_for_view(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; struct sway_workspace *ws = NULL;
for (int i = 0; i < criterias->length; ++i) { for (int i = 0; i < criterias->length; ++i) {
struct criteria *criteria = criterias->items[i]; struct criteria *criteria = criterias->items[i];
@ -639,7 +639,7 @@ static bool should_focus(struct sway_view *view) {
} }
// Check no_focus criteria // 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; size_t len = criterias->length;
list_free(criterias); list_free(criterias);
return len == 0; return len == 0;
@ -836,7 +836,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
} }
} }
view_execute_criteria(view); view_execute_criteria(view, "map");
bool set_focus = should_focus(view); bool set_focus = should_focus(view);