diff --git a/include/sway/criteria.h b/include/sway/criteria.h index ae546821c4..8ba8c9989d 100644 --- a/include/sway/criteria.h +++ b/include/sway/criteria.h @@ -53,6 +53,9 @@ struct criteria { char urgent; // 'l' for latest or 'o' for oldest struct pattern *workspace; pid_t pid; + struct pattern *sandbox_engine; + struct pattern *sandbox_app_id; + struct pattern *sandbox_instance_id; }; bool criteria_is_empty(struct criteria *criteria); diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index f603222128..88e568aebd 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -33,6 +33,9 @@ enum sway_view_prop { VIEW_PROP_X11_WINDOW_ID, VIEW_PROP_X11_PARENT_ID, #endif + VIEW_PROP_SANDBOX_ENGINE, + VIEW_PROP_SANDBOX_APP_ID, + VIEW_PROP_SANDBOX_INSTANCE_ID, }; enum sway_view_tearing_mode { @@ -221,6 +224,12 @@ const char *view_get_window_role(struct sway_view *view); uint32_t view_get_window_type(struct sway_view *view); +const char *view_get_sandbox_engine(struct sway_view *view); + +const char *view_get_sandbox_app_id(struct sway_view *view); + +const char *view_get_sandbox_instance_id(struct sway_view *view); + const char *view_get_shell(struct sway_view *view); void view_get_constraints(struct sway_view *view, double *min_width, diff --git a/sway/criteria.c b/sway/criteria.c index 2b7290c0ec..0aefa00800 100644 --- a/sway/criteria.c +++ b/sway/criteria.c @@ -34,7 +34,10 @@ bool criteria_is_empty(struct criteria *criteria) { && !criteria->tiling && !criteria->urgent && !criteria->workspace - && !criteria->pid; + && !criteria->pid + && !criteria->sandbox_engine + && !criteria->sandbox_app_id + && !criteria->sandbox_instance_id; } // The error pointer is used for parsing functions, and saves having to pass it @@ -98,6 +101,9 @@ void criteria_destroy(struct criteria *criteria) { #endif pattern_destroy(criteria->con_mark); pattern_destroy(criteria->workspace); + pattern_destroy(criteria->sandbox_engine); + pattern_destroy(criteria->sandbox_app_id); + pattern_destroy(criteria->sandbox_instance_id); free(criteria->target); free(criteria->cmdlist); free(criteria->raw); @@ -248,6 +254,66 @@ static bool criteria_matches_view(struct criteria *criteria, } } + if (criteria->sandbox_engine) { + const char *sandbox_engine = view_get_sandbox_engine(view); + if (!sandbox_engine) { + return false; + } + + switch (criteria->sandbox_engine->match_type) { + case PATTERN_FOCUSED: + if (focused && lenient_strcmp(sandbox_engine, view_get_sandbox_engine(focused))) { + return false; + } + break; + case PATTERN_PCRE2: + if (regex_cmp(sandbox_engine, criteria->sandbox_engine->regex) < 0) { + return false; + } + break; + } + } + + if (criteria->sandbox_app_id) { + const char *sandbox_app_id = view_get_sandbox_app_id(view); + if (!sandbox_app_id) { + return false; + } + + switch (criteria->sandbox_app_id->match_type) { + case PATTERN_FOCUSED: + if (focused && lenient_strcmp(sandbox_app_id, view_get_sandbox_app_id(focused))) { + return false; + } + break; + case PATTERN_PCRE2: + if (regex_cmp(sandbox_app_id, criteria->sandbox_app_id->regex) < 0) { + return false; + } + break; + } + } + + if (criteria->sandbox_instance_id) { + const char *sandbox_instance_id = view_get_sandbox_instance_id(view); + if (!sandbox_instance_id) { + return false; + } + + switch (criteria->sandbox_instance_id->match_type) { + case PATTERN_FOCUSED: + if (focused && lenient_strcmp(sandbox_instance_id, view_get_sandbox_instance_id(focused))) { + return false; + } + break; + case PATTERN_PCRE2: + if (regex_cmp(sandbox_instance_id, criteria->sandbox_instance_id->regex) < 0) { + return false; + } + break; + } + } + if (!criteria_matches_container(criteria, view->container)) { return false; } @@ -475,6 +541,9 @@ enum criteria_token { T_URGENT, T_WORKSPACE, T_PID, + T_SANDBOX_ENGINE, + T_SANDBOX_APP_ID, + T_SANDBOX_INSTANCE_ID, T_INVALID, }; @@ -514,6 +583,12 @@ static enum criteria_token token_from_name(char *name) { return T_FLOATING; } else if (strcmp(name, "pid") == 0) { return T_PID; + } else if (strcmp(name, "sandbox_engine") == 0) { + return T_SANDBOX_ENGINE; + } else if (strcmp(name, "sandbox_app_id") == 0) { + return T_SANDBOX_APP_ID; + } else if (strcmp(name, "sandbox_instance_id") == 0) { + return T_SANDBOX_INSTANCE_ID; } return T_INVALID; } @@ -617,6 +692,15 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) { error = strdup("The value for 'pid' should be numeric"); } break; + case T_SANDBOX_ENGINE: + pattern_create(&criteria->sandbox_engine, value); + break; + case T_SANDBOX_APP_ID: + pattern_create(&criteria->sandbox_app_id, value); + break; + case T_SANDBOX_INSTANCE_ID: + pattern_create(&criteria->sandbox_instance_id, value); + break; case T_INVALID: break; } diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 3aed4ec7eb..800837da01 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include "log.h" @@ -12,6 +13,7 @@ #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "sway/output.h" +#include "sway/server.h" #include "sway/tree/arrange.h" #include "sway/tree/container.h" #include "sway/tree/view.h" @@ -139,6 +141,16 @@ static struct sway_xdg_shell_view *xdg_shell_view_from_view( return (struct sway_xdg_shell_view *)view; } +static const struct wlr_security_context_v1_state *security_context_from_view( + struct sway_view *view) { + const struct wl_client *client = + wl_resource_get_client(view->surface->resource); + const struct wlr_security_context_v1_state *security_context = + wlr_security_context_manager_v1_lookup_client( + server.security_context_manager_v1, client); + return security_context; +} + static void get_constraints(struct sway_view *view, double *min_width, double *max_width, double *min_height, double *max_height) { struct wlr_xdg_toplevel_state *state = @@ -159,6 +171,21 @@ static const char *get_string_prop(struct sway_view *view, return view->wlr_xdg_toplevel->title; case VIEW_PROP_APP_ID: return view->wlr_xdg_toplevel->app_id; + case VIEW_PROP_SANDBOX_ENGINE: { + const struct wlr_security_context_v1_state *security_context = + security_context_from_view(view); + return security_context ? security_context->sandbox_engine : NULL; + } + case VIEW_PROP_SANDBOX_APP_ID: { + const struct wlr_security_context_v1_state *security_context = + security_context_from_view(view); + return security_context ? security_context->app_id : NULL; + } + case VIEW_PROP_SANDBOX_INSTANCE_ID: { + const struct wlr_security_context_v1_state *security_context = + security_context_from_view(view); + return security_context ? security_context->instance_id : NULL; + } default: return NULL; } diff --git a/sway/ipc-json.c b/sway/ipc-json.c index fc1df2ac64..142512eb2b 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -602,6 +602,18 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object json_object_object_add(object, "inhibit_idle", json_object_new_boolean(view_inhibit_idle(c->view))); + const char *sandbox_engine = view_get_sandbox_engine(c->view); + json_object_object_add(object, "sandbox_engine", + sandbox_engine ? json_object_new_string(sandbox_engine) : NULL); + + const char *sandbox_app_id = view_get_sandbox_app_id(c->view); + json_object_object_add(object, "sandbox_app_id", + sandbox_app_id ? json_object_new_string(sandbox_app_id) : NULL); + + const char *sandbox_instance_id = view_get_sandbox_instance_id(c->view); + json_object_object_add(object, "sandbox_instance_id", + sandbox_instance_id ? json_object_new_string(sandbox_instance_id) : NULL); + json_object *idle_inhibitors = json_object_new_object(); struct sway_idle_inhibitor_v1 *user_inhibitor = diff --git a/sway/sway-ipc.7.scd b/sway/sway-ipc.7.scd index fe6bb92e23..f39e351809 100644 --- a/sway/sway-ipc.7.scd +++ b/sway/sway-ipc.7.scd @@ -403,6 +403,16 @@ node and will have the following properties: : (Only views) An object containing the state of the _application_ and _user_ idle inhibitors. _application_ can be _enabled_ or _none_. _user_ can be _focus_, _fullscreen_, _open_, _visible_ or _none_. +|- sandbox_engine +: string +: (Only views) The associated sandbox engine (or _null_) +|- sandbox_app_id +: string +: (Only views) The app ID provided by the associated sandbox engine (or _null_) +|- sandbox_instance_id +: string +: (Only views) The instance ID provided by the associated sandbox engine (or + _null_) |- window : integer : (Only xwayland views) The X11 window ID for the xwayland view diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 5e4df0dc76..11468d777f 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -372,12 +372,29 @@ set|plus|minus|toggle *title_format* Sets the format of window titles. The following placeholders may be used: - %title - The title supplied by the window ++ - %app_id - The wayland app ID (applicable to wayland windows only) ++ - %class - The X11 classname (applicable to xwayland windows only) ++ - %instance - The X11 instance (applicable to xwayland windows only) ++ - %shell - The protocol the window is using (typically xwayland or - xdg_shell) + *%title* + The title supplied by the window + + *%app_id* + The wayland app ID (applicable to wayland windows only) + + *%class* + The X11 classname (applicable to xwayland windows only) + + *%instance* + The X11 instance (applicable to xwayland windows only) + + *%shell* + The protocol the window is using (typically xwayland or xdg_shell) + + *%sandbox_engine* + The associated sandbox engine + + *%sandbox_app_id* + The app ID provided by the associated sandbox engine + + *%sandbox_instance_id* + The instance ID provided by the associated sandbox engine This command is typically used with *for_window* criteria. For example: @@ -1058,6 +1075,22 @@ The following attributes may be matched with: expression. If the value is \_\_focused\_\_, then all the views on the currently focused workspace matches. +*sandbox_engine* + Compare against the associated sandbox engine. Can be a regular expression. + If the value is \_\_focused\_\_, then the sandbox engine must be the same as + that of the currently focused window. + +*sandbox_app_id* + Compare against the app ID provided by the associated sandbox engine. Can be + a regular expression. If the value is \_\_focused\_\_, then the sandbox app + ID must be the same as that of the currently focused window. + +*sandbox_instance_id* + Compare against the instance ID provided by the associated sandbox engine. + Can be a regular expression. If the value is \_\_focused\_\_, then the + sandbox instance ID must be the same as that of the currently focused + window. + # SEE ALSO *sway*(1) *sway-input*(5) *sway-output*(5) *sway-bar*(5) *sway-ipc*(7) diff --git a/sway/tree/container.c b/sway/tree/container.c index 0288beacb2..6ff4036fad 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -716,6 +716,15 @@ size_t parse_title_format(struct sway_container *container, char *buffer) { } else if (has_prefix(next, "%shell")) { len += append_prop(buffer, view_get_shell(container->view)); format += strlen("%shell"); + } else if (has_prefix(next, "%sandbox_engine")) { + len += append_prop(buffer, view_get_sandbox_engine(container->view)); + format += strlen("%sandbox_engine"); + } else if (has_prefix(next, "%sandbox_app_id")) { + len += append_prop(buffer, view_get_sandbox_app_id(container->view)); + format += strlen("%sandbox_app_id"); + } else if (has_prefix(next, "%sandbox_instance_id")) { + len += append_prop(buffer, view_get_sandbox_instance_id(container->view)); + format += strlen("%sandbox_instance_id"); } else { lenient_strcat(buffer, "%"); ++format; diff --git a/sway/tree/view.c b/sway/tree/view.c index 492095b93b..cc30ae4ddf 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -154,6 +154,27 @@ uint32_t view_get_window_type(struct sway_view *view) { return 0; } +const char *view_get_sandbox_engine(struct sway_view *view) { + if (view->impl->get_string_prop) { + return view->impl->get_string_prop(view, VIEW_PROP_SANDBOX_ENGINE); + } + return NULL; +} + +const char *view_get_sandbox_app_id(struct sway_view *view) { + if (view->impl->get_string_prop) { + return view->impl->get_string_prop(view, VIEW_PROP_SANDBOX_APP_ID); + } + return NULL; +} + +const char *view_get_sandbox_instance_id(struct sway_view *view) { + if (view->impl->get_string_prop) { + return view->impl->get_string_prop(view, VIEW_PROP_SANDBOX_INSTANCE_ID); + } + return NULL; +} + const char *view_get_shell(struct sway_view *view) { switch(view->type) { case SWAY_VIEW_XDG_SHELL: diff --git a/swaymsg/main.c b/swaymsg/main.c index 5c57171e7c..0ef6eb8a51 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -330,6 +330,9 @@ static void pretty_print_tree(json_object *obj, int indent) { const char *instance = json_object_get_string(json_object_object_get(window_props_obj, "instance")); const char *class = json_object_get_string(json_object_object_get(window_props_obj, "class")); int x11_id = json_object_get_int(json_object_object_get(obj, "window")); + const char *sandbox_engine = json_object_get_string(json_object_object_get(obj, "sandbox_engine")); + const char *sandbox_app_id = json_object_get_string(json_object_object_get(obj, "sandbox_app_id")); + const char *sandbox_instance_id = json_object_get_string(json_object_object_get(obj, "sandbox_instance_id")); printf(" (%s, pid: %d", shell, pid); if (app_id != NULL) { @@ -344,6 +347,15 @@ static void pretty_print_tree(json_object *obj, int indent) { if (x11_id != 0) { printf(", X11 window: 0x%X", x11_id); } + if (sandbox_engine != NULL) { + printf(", sandbox_engine: \"%s\"", sandbox_engine); + } + if (sandbox_app_id != NULL) { + printf(", sandbox_app_id: \"%s\"", sandbox_app_id); + } + if (sandbox_instance_id != NULL) { + printf(", sandbox_instance_id: \"%s\"", sandbox_instance_id); + } printf(")"); }