From 3b0c26d149dfe5e05df338692db8255a01f0998d Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Wed, 9 May 2018 14:23:20 +1000 Subject: Overhaul criteria implementation The criteria struct now uses properties for each token type rather than the list_t list of tokens. The reason for this is that different token types have different data types: pcre, string and number to name a few. This solution should be more flexible moving forward. A bonus of this is that criteria is now easier to understand when looking at the struct definition. The criteria parser has been rewritten because the previous one didn't support valueless pairs (eg. [class="foo" floating]). Criteria now has types. Types at the moment are CT_COMMAND, CT_ASSIGN_WORKSPACE and CT_ASSIGN_OUTPUT. i3 uses types as well. Previously the assign command was creating a criteria with 'move to workspace ' as its command, but this caused the window to appear briefly on the focused workspace before being moved to the assigned workspace. It now creates the view directly in the assigned workspace. Each view will only execute a given criteria once. This is achieved by storing a list of executed criteria in the view. This is the same strategy used by i3. Escaping now works properly. Previously you could do things like [class="Fire\"fox"] and the stored value would be 'Fire\"fox', but it should be (and now is) 'Fire"fox'. The public functions in criteria.c are now all prefixed with criteria_. Xwayland views now listen to the set_title, set_class and set_window_type events and criteria will be run when these happen. XDG shell has none of these events so it continues to update the title in handle_commit. Each view type's get_prop function has been split into get_string_prop and get_int_prop because some properties like the X11 window ID and window type are numeric. The following new criteria tokens are now supported: * id (X11 window ID) * instance * tiling * workspace --- include/sway/criteria.h | 73 +++-- include/sway/tree/view.h | 21 +- sway/commands.c | 42 ++- sway/commands/assign.c | 58 ++-- sway/commands/for_window.c | 35 +-- sway/criteria.c | 685 ++++++++++++++++++++------------------------ sway/desktop/wl_shell.c | 4 +- sway/desktop/xdg_shell_v6.c | 4 +- sway/desktop/xwayland.c | 69 ++++- sway/tree/view.c | 97 +++++-- 10 files changed, 581 insertions(+), 507 deletions(-) diff --git a/include/sway/criteria.h b/include/sway/criteria.h index ec256ddb..74da132c 100644 --- a/include/sway/criteria.h +++ b/include/sway/criteria.h @@ -1,42 +1,61 @@ #ifndef _SWAY_CRITERIA_H #define _SWAY_CRITERIA_H -#include "tree/container.h" +#include #include "list.h" +#include "tree/view.h" -/** - * Maps criteria (as a list of criteria tokens) to a command list. - * - * A list of tokens together represent a single criteria string (e.g. - * '[class="abc" title="xyz"]' becomes two criteria tokens). - * - * for_window: Views matching all criteria will have the bound command list - * executed on them. - * - * Set via `for_window `. - */ -struct criteria { - list_t *tokens; // struct crit_token, contains compiled regex. - char *crit_raw; // entire criteria string (for logging) +enum criteria_type { + CT_COMMAND = 1 << 0, + CT_ASSIGN_OUTPUT = 1 << 1, + CT_ASSIGN_WORKSPACE = 1 << 2, +}; +struct criteria { + enum criteria_type type; + char *raw; // entire criteria string (for logging) char *cmdlist; + char *target; // workspace or output name for `assign` criteria + + pcre *title; + pcre *app_id; + pcre *class; + pcre *instance; + pcre *con_mark; + uint32_t con_id; // internal ID + uint32_t id; // X11 window ID + pcre *window_role; + uint32_t window_type; + bool floating; + bool tiling; + char urgent; // 'l' for latest or 'o' for oldest + char *workspace; }; -int criteria_cmp(const void *item, const void *data); -void free_criteria(struct criteria *crit); +bool criteria_is_empty(struct criteria *criteria); -// Pouplate list with crit_tokens extracted from criteria string, returns error -// string or NULL if successful. -char *extract_crit_tokens(list_t *tokens, const char *criteria); +void criteria_destroy(struct criteria *criteria); -// Returns list of criteria that match given container. These criteria have -// been set with `for_window` commands and have an associated cmdlist. -list_t *criteria_for(struct sway_container *cont); +/** + * Generate a criteria struct from a raw criteria string such as + * [class="foo" instance="bar"] (brackets inclusive). + * + * The error argument is expected to be an address of a null pointer. If an + * error is encountered, the function will return NULL and the pointer will be + * changed to point to the error string. This string should be freed afterwards. + */ +struct criteria *criteria_parse(char *raw, char **error); -// Returns a list of all containers that match the given list of tokens. -list_t *container_for_crit_tokens(list_t *tokens); +/** + * Compile a list of criterias matching the given view. + * + * Criteria types can be bitwise ORed. + */ +list_t *criteria_for_view(struct sway_view *view, enum criteria_type types); -// Returns true if any criteria in the given list matches this container -bool criteria_any(struct sway_container *cont, list_t *criteria); +/** + * Compile a list of views matching the given criteria. + */ +list_t *criteria_get_views(struct criteria *criteria); #endif diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 4ecd8c44..144ad038 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -20,11 +20,15 @@ enum sway_view_prop { VIEW_PROP_APP_ID, VIEW_PROP_CLASS, VIEW_PROP_INSTANCE, + VIEW_PROP_WINDOW_TYPE, + VIEW_PROP_WINDOW_ROLE, + VIEW_PROP_X11_WINDOW_ID, }; struct sway_view_impl { - const char *(*get_prop)(struct sway_view *view, + const char *(*get_string_prop)(struct sway_view *view, enum sway_view_prop prop); + uint32_t (*get_int_prop)(struct sway_view *view, enum sway_view_prop prop); void (*configure)(struct sway_view *view, double ox, double oy, int width, int height); void (*set_activated)(struct sway_view *view, bool activated); @@ -52,6 +56,8 @@ struct sway_view { enum sway_container_border border; int border_thickness; + list_t *executed_criteria; + union { struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6; struct wlr_xwayland_surface *wlr_xwayland_surface; @@ -91,6 +97,9 @@ struct sway_xwayland_view { struct wl_listener request_maximize; struct wl_listener request_configure; struct wl_listener request_fullscreen; + struct wl_listener set_title; + struct wl_listener set_class; + struct wl_listener set_window_type; struct wl_listener map; struct wl_listener unmap; struct wl_listener destroy; @@ -165,6 +174,10 @@ const char *view_get_class(struct sway_view *view); const char *view_get_instance(struct sway_view *view); +uint32_t view_get_x11_window_id(struct sway_view *view); + +uint32_t view_get_window_type(struct sway_view *view); + const char *view_get_type(struct sway_view *view); void view_configure(struct sway_view *view, double ox, double oy, int width, @@ -217,4 +230,10 @@ void view_child_destroy(struct sway_view_child *child); */ 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); + #endif diff --git a/sway/commands.c b/sway/commands.c index 2e1cdc2c..811f6cfa 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -12,6 +12,7 @@ #include "sway/security.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" +#include "sway/tree/view.h" #include "stringop.h" #include "log.h" @@ -283,7 +284,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { char *head = exec; char *cmdlist; char *cmd; - list_t *containers = NULL; + list_t *views = NULL; if (seat == NULL) { // passing a NULL seat means we just pick the default seat @@ -300,31 +301,18 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { // Extract criteria (valid for this command list only). bool has_criteria = false; if (*head == '[') { - has_criteria = true; - ++head; - char *criteria_string = argsep(&head, "]"); - if (head) { - ++head; - list_t *tokens = create_list(); - char *error; - - if ((error = extract_crit_tokens(tokens, criteria_string))) { - wlr_log(L_DEBUG, "criteria string parse error: %s", error); - results = cmd_results_new(CMD_INVALID, criteria_string, - "Can't parse criteria string: %s", error); - free(error); - free(tokens); - goto cleanup; - } - containers = container_for_crit_tokens(tokens); - - free(tokens); - } else { - if (!results) { - results = cmd_results_new(CMD_INVALID, criteria_string, "Unmatched ["); - } + char *error = NULL; + struct criteria *criteria = criteria_parse(head, &error); + if (!criteria) { + results = cmd_results_new(CMD_INVALID, head, + "%s", error); + free(error); goto cleanup; } + views = criteria_get_views(criteria); + head += strlen(criteria->raw); + criteria_destroy(criteria); + has_criteria = true; // Skip leading whitespace head += strspn(head, whitespace); } @@ -381,8 +369,9 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { } free_cmd_results(res); } else { - for (int i = 0; i < containers->length; ++i) { - config->handler_context.current_container = containers->items[i]; + for (int i = 0; i < views->length; ++i) { + struct sway_view *view = views->items[i]; + config->handler_context.current_container = view->swayc; struct cmd_results *res = handler->handle(argc-1, argv+1); if (res->status != CMD_SUCCESS) { free_argv(argc, argv); @@ -400,6 +389,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { } while(head); cleanup: free(exec); + free(views); if (!results) { results = cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/assign.c b/sway/commands/assign.c index eb7329aa..9d15e166 100644 --- a/sway/commands/assign.c +++ b/sway/commands/assign.c @@ -5,6 +5,7 @@ #include "sway/criteria.h" #include "list.h" #include "log.h" +#include "stringop.h" struct cmd_results *cmd_assign(int argc, char **argv) { struct cmd_results *error = NULL; @@ -12,46 +13,39 @@ struct cmd_results *cmd_assign(int argc, char **argv) { return error; } - char *criteria = *argv++; + // Create criteria + char *err_str = NULL; + struct criteria *criteria = criteria_parse(argv[0], &err_str); + if (!criteria) { + error = cmd_results_new(CMD_INVALID, "assign", err_str); + free(err_str); + return error; + } + + ++argv; + int target_len = argc - 1; if (strncmp(*argv, "→", strlen("→")) == 0) { if (argc < 3) { return cmd_results_new(CMD_INVALID, "assign", "Missing workspace"); } - argv++; + ++argv; + --target_len; } - char *movecmd = "move container to workspace "; - size_t arglen = strlen(movecmd) + strlen(*argv) + 1; - char *cmdlist = calloc(1, arglen); - if (!cmdlist) { - return cmd_results_new(CMD_FAILURE, "assign", "Unable to allocate command list"); + if (strcmp(*argv, "output") == 0) { + criteria->type = CT_ASSIGN_OUTPUT; + ++argv; + --target_len; + } else { + criteria->type = CT_ASSIGN_WORKSPACE; } - snprintf(cmdlist, arglen, "%s%s", movecmd, *argv); - struct criteria *crit = malloc(sizeof(struct criteria)); - if (!crit) { - free(cmdlist); - return cmd_results_new(CMD_FAILURE, "assign", "Unable to allocate criteria"); - } - crit->crit_raw = strdup(criteria); - crit->cmdlist = cmdlist; - crit->tokens = create_list(); - char *err_str = extract_crit_tokens(crit->tokens, crit->crit_raw); + criteria->target = join_args(argv, target_len); - if (err_str) { - error = cmd_results_new(CMD_INVALID, "assign", err_str); - free(err_str); - free_criteria(crit); - } else if (crit->tokens->length == 0) { - error = cmd_results_new(CMD_INVALID, "assign", "Found no name/value pairs in criteria"); - free_criteria(crit); - } else if (list_seq_find(config->criteria, criteria_cmp, crit) != -1) { - wlr_log(L_DEBUG, "assign: Duplicate, skipping."); - free_criteria(crit); - } else { - wlr_log(L_DEBUG, "assign: '%s' -> '%s' added", crit->crit_raw, crit->cmdlist); - list_add(config->criteria, crit); - } - return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL); + list_add(config->criteria, criteria); + wlr_log(L_DEBUG, "assign: '%s' -> '%s' added", criteria->raw, + criteria->target); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/for_window.c b/sway/commands/for_window.c index dd5461f0..8c425a1d 100644 --- a/sway/commands/for_window.c +++ b/sway/commands/for_window.c @@ -11,31 +11,20 @@ struct cmd_results *cmd_for_window(int argc, char **argv) { if ((error = checkarg(argc, "for_window", EXPECTED_AT_LEAST, 2))) { return error; } - // add command to a criteria/command pair that is run against views when they appear. - char *criteria = argv[0], *cmdlist = join_args(argv + 1, argc - 1); - struct criteria *crit = calloc(sizeof(struct criteria), 1); - if (!crit) { - return cmd_results_new(CMD_FAILURE, "for_window", "Unable to allocate criteria"); - } - crit->crit_raw = strdup(criteria); - crit->cmdlist = cmdlist; - crit->tokens = create_list(); - char *err_str = extract_crit_tokens(crit->tokens, crit->crit_raw); - - if (err_str) { + char *err_str = NULL; + struct criteria *criteria = criteria_parse(argv[0], &err_str); + if (!criteria) { error = cmd_results_new(CMD_INVALID, "for_window", err_str); free(err_str); - free_criteria(crit); - } else if (crit->tokens->length == 0) { - error = cmd_results_new(CMD_INVALID, "for_window", "Found no name/value pairs in criteria"); - free_criteria(crit); - } else if (list_seq_find(config->criteria, criteria_cmp, crit) != -1) { - wlr_log(L_DEBUG, "for_window: Duplicate, skipping."); - free_criteria(crit); - } else { - wlr_log(L_DEBUG, "for_window: '%s' -> '%s' added", crit->crit_raw, crit->cmdlist); - list_add(config->criteria, crit); + return error; } - return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL); + + criteria->type = CT_COMMAND; + criteria->cmdlist = join_args(argv + 1, argc - 1); + + list_add(config->criteria, criteria); + wlr_log(L_DEBUG, "for_window: '%s' -> '%s' added", criteria->raw, criteria->cmdlist); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/criteria.c b/sway/criteria.c index 22e9a49b..6abe24af 100644 --- a/sway/criteria.c +++ b/sway/criteria.c @@ -11,435 +11,382 @@ #include "list.h" #include "log.h" -enum criteria_type { // *must* keep in sync with criteria_strings[] - CRIT_APP_ID, - CRIT_CLASS, - CRIT_CON_ID, - CRIT_CON_MARK, - CRIT_FLOATING, - CRIT_ID, - CRIT_INSTANCE, - CRIT_TILING, - CRIT_TITLE, - CRIT_URGENT, - CRIT_WINDOW_ROLE, - CRIT_WINDOW_TYPE, - CRIT_WORKSPACE, - CRIT_LAST -}; - -static const char * const criteria_strings[CRIT_LAST] = { - [CRIT_APP_ID] = "app_id", - [CRIT_CLASS] = "class", - [CRIT_CON_ID] = "con_id", - [CRIT_CON_MARK] = "con_mark", - [CRIT_FLOATING] = "floating", - [CRIT_ID] = "id", - [CRIT_INSTANCE] = "instance", - [CRIT_TILING] = "tiling", - [CRIT_TITLE] = "title", - [CRIT_URGENT] = "urgent", // either "latest" or "oldest" ... - [CRIT_WINDOW_ROLE] = "window_role", - [CRIT_WINDOW_TYPE] = "window_type", - [CRIT_WORKSPACE] = "workspace" -}; +bool criteria_is_empty(struct criteria *criteria) { + return !criteria->title + && !criteria->app_id + && !criteria->class + && !criteria->instance + && !criteria->con_mark + && !criteria->con_id + && !criteria->id + && !criteria->window_role + && !criteria->window_type + && !criteria->floating + && !criteria->tiling + && !criteria->urgent + && !criteria->workspace; +} -/** - * A single criteria token (ie. value/regex pair), - * e.g. 'class="some class regex"'. - */ -struct crit_token { - enum criteria_type type; - pcre *regex; - char *raw; -}; +void criteria_destroy(struct criteria *criteria) { + pcre_free(criteria->title); + pcre_free(criteria->app_id); + pcre_free(criteria->class); + pcre_free(criteria->instance); + pcre_free(criteria->con_mark); + pcre_free(criteria->window_role); + free(criteria->workspace); + + free(criteria->raw); + free(criteria); +} -static void free_crit_token(struct crit_token *crit) { - pcre_free(crit->regex); - free(crit->raw); - free(crit); +static int regex_cmp(const char *item, const pcre *regex) { + return pcre_exec(regex, NULL, item, strlen(item), 0, 0, NULL, 0); } -static void free_crit_tokens(list_t *crit_tokens) { - for (int i = 0; i < crit_tokens->length; i++) { - free_crit_token(crit_tokens->items[i]); +static bool criteria_matches_view(struct criteria *criteria, + struct sway_view *view) { + if (criteria->title) { + const char *title = view_get_title(view); + if (!title || regex_cmp(title, criteria->title) != 0) { + return false; + } } - list_free(crit_tokens); -} -// Extracts criteria string from its brackets. Returns new (duplicate) -// substring. -static char *criteria_from(const char *arg) { - char *criteria = NULL; - if (*arg == '[') { - criteria = strdup(arg + 1); - } else { - criteria = strdup(arg); + if (criteria->app_id) { + const char *app_id = view_get_app_id(view); + if (!app_id || regex_cmp(app_id, criteria->app_id) != 0) { + return false; + } } - int last = strlen(criteria) - 1; - if (criteria[last] == ']') { - criteria[last] = '\0'; + if (criteria->class) { + const char *class = view_get_class(view); + if (!class || regex_cmp(class, criteria->class) != 0) { + return false; + } } - return criteria; -} -// Return instances of c found in str. -static int countchr(char *str, char c) { - int found = 0; - for (int i = 0; str[i]; i++) { - if (str[i] == c) { - ++found; + if (criteria->instance) { + const char *instance = view_get_instance(view); + if (!instance || regex_cmp(instance, criteria->instance) != 0) { + return false; } } - return found; -} -// criteria_str is e.g. '[class="some class regex" instance="instance name"]'. -// -// Will create array of pointers in buf, where first is duplicate of given -// string (must be freed) and the rest are pointers to names and values in the -// base string (every other, naturally). argc will be populated with the length -// of buf. -// -// Returns error string or NULL if successful. -static char *crit_tokens(int *argc, char ***buf, - const char * const criteria_str) { - wlr_log(L_DEBUG, "Parsing criteria: '%s'", criteria_str); - char *base = criteria_from(criteria_str); - char *head = base; - char *namep = head; // start of criteria name - char *valp = NULL; // start of value - - // We're going to place EOS markers where we need to and fill up an array - // of pointers to the start of each token (either name or value). - int pairs = countchr(base, '='); - int max_tokens = pairs * 2 + 1; // this gives us at least enough slots - - char **argv = *buf = calloc(max_tokens, sizeof(char*)); - argv[0] = base; // this needs to be freed by caller - bool quoted = true; - - *argc = 1; // uneven = name, even = value - while (*head && *argc < max_tokens) { - if (namep != head && *(head - 1) == '\\') { - // escaped character: don't try to parse this - } else if (*head == '=' && namep != head) { - if (*argc % 2 != 1) { - // we're not expecting a name - return strdup("Unable to parse criteria: " - "Found out of place equal sign"); - } else { - // name ends here - char *end = head; // don't want to rewind the head - while (*(end - 1) == ' ') { - --end; - } - *end = '\0'; - if (*(namep) == ' ') { - namep = strrchr(namep, ' ') + 1; - } - argv[*argc] = namep; - *argc += 1; - } - } else if (*head == '"') { - if (*argc % 2 != 0) { - // we're not expecting a value - return strdup("Unable to parse criteria: " - "Found quoted value where it was not expected"); - } else if (!valp) { // value starts here - valp = head + 1; - quoted = true; - } else { - // value ends here - argv[*argc] = valp; - *argc += 1; - *head = '\0'; - valp = NULL; - namep = head + 1; - } - } else if (*argc % 2 == 0 && *head != ' ') { - // parse unquoted values - if (!valp) { - quoted = false; - valp = head; // value starts here - } - } else if (valp && !quoted && *head == ' ') { - // value ends here - argv[*argc] = valp; - *argc += 1; - *head = '\0'; - valp = NULL; - namep = head + 1; + if (criteria->con_mark) { + // TODO + return false; + } + + if (criteria->con_id) { // Internal ID + if (!view->swayc || view->swayc->id != criteria->con_id) { + return false; } - head++; } - // catch last unquoted value if needed - if (valp && !quoted && !*head) { - argv[*argc] = valp; - *argc += 1; + if (criteria->id) { // X11 window ID + uint32_t x11_window_id = view_get_x11_window_id(view); + if (!x11_window_id || x11_window_id != criteria->id) { + return false; + } } - return NULL; + if (criteria->window_role) { + // TODO + } + + if (criteria->window_type) { + uint32_t type = view_get_window_type(view); + if (!type || type != criteria->window_type) { + return false; + } + } + + if (criteria->floating) { + // TODO + return false; + } + + if (criteria->tiling) { + // TODO + } + + if (criteria->urgent) { + // TODO + return false; + } + + if (criteria->workspace) { + if (!view->swayc) { + return false; + } + struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); + if (!ws || strcmp(ws->name, criteria->workspace) != 0) { + return false; + } + } + + return true; } -// Returns error string on failure or NULL otherwise. -static char *parse_criteria_name(enum criteria_type *type, char *name) { - *type = CRIT_LAST; - for (int i = 0; i < CRIT_LAST; i++) { - if (strcmp(criteria_strings[i], name) == 0) { - *type = (enum criteria_type) i; - break; +list_t *criteria_for_view(struct sway_view *view, enum criteria_type types) { + 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)) { + list_add(matches, criteria); } } - if (*type == CRIT_LAST) { - const char *fmt = "Criteria type '%s' is invalid or unsupported."; - int len = strlen(name) + strlen(fmt) - 1; - char *error = malloc(len); - snprintf(error, len, fmt, name); - return error; - } else if (*type == CRIT_URGENT || *type == CRIT_WINDOW_ROLE || - *type == CRIT_WINDOW_TYPE) { - // (we're just being helpful here) - const char *fmt = "\"%s\" criteria currently unsupported, " - "no window will match this"; - int len = strlen(fmt) + strlen(name) - 1; - char *error = malloc(len); - snprintf(error, len, fmt, name); - return error; + return matches; +} + +struct match_data { + struct criteria *criteria; + list_t *matches; +}; + +static void criteria_get_views_iterator(struct sway_container *container, + void *data) { + struct match_data *match_data = data; + if (container->type == C_VIEW) { + if (criteria_matches_view(match_data->criteria, container->sway_view)) { + list_add(match_data->matches, container->sway_view); + } } - return NULL; } +list_t *criteria_get_views(struct criteria *criteria) { + list_t *matches = create_list(); + struct match_data data = { + .criteria = criteria, + .matches = matches, + }; + container_for_each_descendant_dfs(&root_container, + criteria_get_views_iterator, &data); + return matches; +} + +// The error pointer is used for parsing functions, and saves having to pass it +// as an argument in several places. +char *error = NULL; + // Returns error string on failure or NULL otherwise. -static char *generate_regex(pcre **regex, char *value) { +static bool generate_regex(pcre **regex, char *value) { const char *reg_err; int offset; *regex = pcre_compile(value, PCRE_UTF8 | PCRE_UCP, ®_err, &offset, NULL); if (!*regex) { - const char *fmt = "Regex compilation (for '%s') failed: %s"; + const char *fmt = "Regex compilation for '%s' failed: %s"; int len = strlen(fmt) + strlen(value) + strlen(reg_err) - 3; - char *error = malloc(len); + error = malloc(len); snprintf(error, len, fmt, value, reg_err); - return error; + return false; } - return NULL; -} -// Test whether the criterion corresponds to the currently focused window -static bool crit_is_focused(const char *value) { - return !strcmp(value, "focused") || !strcmp(value, "__focused__"); + return true; } -// Populate list with crit_tokens extracted from criteria string, returns error -// string or NULL if successful. -char *extract_crit_tokens(list_t *tokens, const char * const criteria) { - int argc; - char **argv = NULL, *error = NULL; - if ((error = crit_tokens(&argc, &argv, criteria))) { - goto ect_cleanup; +static bool parse_token(struct criteria *criteria, char *name, char *value) { + // Require value, unless token is floating or tiled + if (!value && (strcmp(name, "title") == 0 + || strcmp(name, "app_id") == 0 + || strcmp(name, "class") == 0 + || strcmp(name, "instance") == 0 + || strcmp(name, "con_id") == 0 + || strcmp(name, "con_mark") == 0 + || strcmp(name, "window_role") == 0 + || strcmp(name, "window_type") == 0 + || strcmp(name, "id") == 0 + || strcmp(name, "urgent") == 0 + || strcmp(name, "workspace") == 0)) { + const char *fmt = "Token '%s' requires a value"; + int len = strlen(fmt) + strlen(name) - 1; + error = malloc(len); + snprintf(error, len, fmt, name); + return false; } - for (int i = 1; i + 1 < argc; i += 2) { - char* name = argv[i], *value = argv[i + 1]; - struct crit_token *token = calloc(1, sizeof(struct crit_token)); - token->raw = strdup(value); - - if ((error = parse_criteria_name(&token->type, name))) { - free_crit_token(token); - goto ect_cleanup; - } else if (token->type == CRIT_URGENT || crit_is_focused(value)) { - wlr_log(L_DEBUG, "%s -> \"%s\"", name, value); - list_add(tokens, token); - } else if((error = generate_regex(&token->regex, value))) { - free_crit_token(token); - goto ect_cleanup; + + if (strcmp(name, "title") == 0) { + generate_regex(&criteria->title, value); + } else if (strcmp(name, "app_id") == 0) { + generate_regex(&criteria->app_id, value); + } else if (strcmp(name, "class") == 0) { + generate_regex(&criteria->class, value); + } else if (strcmp(name, "instance") == 0) { + generate_regex(&criteria->instance, value); + } else if (strcmp(name, "con_id") == 0) { + char *endptr; + criteria->con_id = strtoul(value, &endptr, 10); + if (*endptr != 0) { + error = strdup("The value for 'con_id' should be numeric"); + } + } else if (strcmp(name, "con_mark") == 0) { + generate_regex(&criteria->con_mark, value); + } else if (strcmp(name, "window_role") == 0) { + generate_regex(&criteria->window_role, value); + } else if (strcmp(name, "window_type") == 0) { + // TODO: This is a string but will be stored as an enum or integer + } else if (strcmp(name, "id") == 0) { + char *endptr; + criteria->id = strtoul(value, &endptr, 10); + if (*endptr != 0) { + error = strdup("The value for 'id' should be numeric"); + } + } else if (strcmp(name, "floating") == 0) { + criteria->floating = true; + } else if (strcmp(name, "tiling") == 0) { + criteria->tiling = true; + } else if (strcmp(name, "urgent") == 0) { + if (strcmp(value, "latest") == 0) { + criteria->urgent = 'l'; + } else if (strcmp(value, "oldest") == 0) { + criteria->urgent = 'o'; } else { - wlr_log(L_DEBUG, "%s -> /%s/", name, value); - list_add(tokens, token); + error = + strdup("The value for 'urgent' must be 'latest' or 'oldest'"); } + } else if (strcmp(name, "workspace") == 0) { + criteria->workspace = strdup(value); + } else { + const char *fmt = "Token '%s' is not recognized"; + int len = strlen(fmt) + strlen(name) - 1; + error = malloc(len); + snprintf(error, len, fmt, name); } -ect_cleanup: - free(argv[0]); // base string - free(argv); - return error; -} - -static int regex_cmp(const char *item, const pcre *regex) { - return pcre_exec(regex, NULL, item, strlen(item), 0, 0, NULL, 0); -} -// test a single view if it matches list of criteria tokens (all of them). -static bool criteria_test(struct sway_container *cont, list_t *tokens) { - if (cont->type != C_CONTAINER && cont->type != C_VIEW) { + if (error) { return false; } - int matches = 0; - for (int i = 0; i < tokens->length; i++) { - struct crit_token *crit = tokens->items[i]; - switch (crit->type) { - case CRIT_CLASS: - { - const char *class = view_get_class(cont->sway_view); - if (!class) { - break; - } - if (crit->regex && regex_cmp(class, crit->regex) == 0) { - matches++; - } - break; - } - case CRIT_CON_ID: - { - char *endptr; - size_t crit_id = strtoul(crit->raw, &endptr, 10); - - if (*endptr == 0 && cont->id == crit_id) { - ++matches; - } - break; - } - case CRIT_CON_MARK: - // TODO - break; - case CRIT_FLOATING: - // TODO - break; - case CRIT_ID: - // TODO - break; - case CRIT_APP_ID: - { - const char *app_id = view_get_app_id(cont->sway_view); - if (!app_id) { - break; - } - - if (crit->regex && regex_cmp(app_id, crit->regex) == 0) { - matches++; - } - break; - } - case CRIT_INSTANCE: - { - const char *instance = view_get_instance(cont->sway_view); - if (!instance) { - break; - } - - if (crit->regex && regex_cmp(instance, crit->regex) == 0) { - matches++; - } - break; - } - case CRIT_TILING: - // TODO - break; - case CRIT_TITLE: - { - const char *title = view_get_title(cont->sway_view); - if (!title) { - break; - } - if (crit->regex && regex_cmp(title, crit->regex) == 0) { - matches++; - } - break; - } - case CRIT_URGENT: - // TODO "latest" or "oldest" - break; - case CRIT_WINDOW_ROLE: - // TODO - break; - case CRIT_WINDOW_TYPE: - // TODO - break; - case CRIT_WORKSPACE: - // TODO - break; - default: - sway_abort("Invalid criteria type (%i)", crit->type); - break; - } - } - return matches == tokens->length; + return true; } -int criteria_cmp(const void *a, const void *b) { - if (a == b) { - return 0; - } else if (!a) { - return -1; - } else if (!b) { - return 1; +static void skip_spaces(char **head) { + while (**head == ' ') { + ++*head; } - const struct criteria *crit_a = a, *crit_b = b; - int cmp = lenient_strcmp(crit_a->cmdlist, crit_b->cmdlist); - if (cmp != 0) { - return cmp; - } - return lenient_strcmp(crit_a->crit_raw, crit_b->crit_raw); } -void free_criteria(struct criteria *crit) { - if (crit->tokens) { - free_crit_tokens(crit->tokens); - } - if (crit->cmdlist) { - free(crit->cmdlist); +// Remove escaping slashes from value +static void unescape(char *value) { + if (!strchr(value, '\\')) { + return; } - if (crit->crit_raw) { - free(crit->crit_raw); - } - free(crit); -} - -bool criteria_any(struct sway_container *cont, list_t *criteria) { - for (int i = 0; i < criteria->length; i++) { - struct criteria *bc = criteria->items[i]; - if (criteria_test(cont, bc->tokens)) { - return true; + char *copy = calloc(strlen(value) + 1, 1); + char *readhead = value; + char *writehead = copy; + while (*readhead) { + if (*readhead == '\\' && + (*(readhead + 1) == '"' || *(readhead + 1) == '\\')) { + // skip the slash + ++readhead; } + *writehead = *readhead; + ++writehead; + ++readhead; } - return false; + strcpy(value, copy); + free(copy); } -list_t *criteria_for(struct sway_container *cont) { - list_t *criteria = config->criteria, *matches = create_list(); - for (int i = 0; i < criteria->length; i++) { - struct criteria *bc = criteria->items[i]; - if (criteria_test(cont, bc->tokens)) { - list_add(matches, bc); +/** + * Parse a raw criteria string such as [class="foo" instance="bar"] into a + * criteria struct. + * + * If errors are found, NULL will be returned and the error argument will be + * populated with an error string. + */ +struct criteria *criteria_parse(char *raw, char **error_arg) { + free(error); + error = NULL; + + char *head = raw; + skip_spaces(&head); + if (*head != '[') { + *error_arg = strdup("No criteria"); + return NULL; + } + ++head; + + struct criteria *criteria = calloc(sizeof(struct criteria), 1); + char *name = NULL, *value = NULL; + bool in_quotes = false; + + while (*head && *head != ']') { + skip_spaces(&head); + // Parse token name + char *namestart = head; + while ((*head >= 'a' && *head <= 'z') || *head == '_') { + ++head; } + name = calloc(head - namestart + 1, 1); + strncpy(name, namestart, head - namestart); + // Parse token value + skip_spaces(&head); + value = NULL; + if (*head == '=') { + ++head; + skip_spaces(&head); + if (*head == '"') { + in_quotes = true; + ++head; + } + char *valuestart = head; + if (in_quotes) { + while (*head && (*head != '"' || *(head - 1) == '\\')) { + ++head; + } + if (!*head) { + *error_arg = strdup("Quote mismatch in criteria"); + goto cleanup; + } + } else { + while (*head && *head != ' ' && *head != ']') { + ++head; + } + } + value = calloc(head - valuestart + 1, 1); + strncpy(value, valuestart, head - valuestart); + if (in_quotes) { + ++head; + in_quotes = false; + } + unescape(value); + } + wlr_log(L_DEBUG, "Found pair: %s=%s", name, value); + if (!parse_token(criteria, name, value)) { + *error_arg = error; + goto cleanup; + } + skip_spaces(&head); + free(name); + free(value); + name = NULL; + value = NULL; } - return matches; -} - -struct list_tokens { - list_t *list; - list_t *tokens; -}; - -static void container_match_add(struct sway_container *container, - struct list_tokens *list_tokens) { - if (criteria_test(container, list_tokens->tokens)) { - list_add(list_tokens->list, container); + if (*head != ']') { + *error_arg = strdup("No closing brace found in criteria"); + goto cleanup; } -} -list_t *container_for_crit_tokens(list_t *tokens) { - struct list_tokens list_tokens = - (struct list_tokens){create_list(), tokens}; + if (criteria_is_empty(criteria)) { + *error_arg = strdup("Criteria is empty"); + goto cleanup; + } - container_for_each_descendant_dfs(&root_container, - (void (*)(struct sway_container *, void *))container_match_add, - &list_tokens); + ++head; + int len = head - raw; + criteria->raw = calloc(len + 1, 1); + strncpy(criteria->raw, raw, len); + return criteria; - // TODO look in the scratchpad - - return list_tokens.list; +cleanup: + free(name); + free(value); + criteria_destroy(criteria); + return NULL; } diff --git a/sway/desktop/wl_shell.c b/sway/desktop/wl_shell.c index 99e8947b..cb3774f7 100644 --- a/sway/desktop/wl_shell.c +++ b/sway/desktop/wl_shell.c @@ -20,7 +20,7 @@ static struct sway_wl_shell_view *wl_shell_view_from_view( return (struct sway_wl_shell_view *)view; } -static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { +static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) { if (wl_shell_view_from_view(view) == NULL) { return NULL; } @@ -70,7 +70,7 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) { } static const struct sway_view_impl view_impl = { - .get_prop = get_prop, + .get_string_prop = get_string_prop, .configure = configure, .close = _close, .destroy = destroy, diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 8ecb330d..f685ef71 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -80,7 +80,7 @@ static struct sway_xdg_shell_v6_view *xdg_shell_v6_view_from_view( return (struct sway_xdg_shell_v6_view *)view; } -static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { +static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) { if (xdg_shell_v6_view_from_view(view) == NULL) { return NULL; } @@ -158,7 +158,7 @@ static void destroy(struct sway_view *view) { } static const struct sway_view_impl view_impl = { - .get_prop = get_prop, + .get_string_prop = get_string_prop, .configure = configure, .set_activated = set_activated, .set_fullscreen = set_fullscreen, diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 8f935760..554c070e 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -126,7 +126,7 @@ static struct sway_xwayland_view *xwayland_view_from_view( return (struct sway_xwayland_view *)view; } -static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { +static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) { if (xwayland_view_from_view(view) == NULL) { return NULL; } @@ -135,11 +135,27 @@ static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { return view->wlr_xwayland_surface->title; case VIEW_PROP_CLASS: return view->wlr_xwayland_surface->class; + case VIEW_PROP_INSTANCE: + return view->wlr_xwayland_surface->instance; default: return NULL; } } +static uint32_t get_int_prop(struct sway_view *view, enum sway_view_prop prop) { + if (xwayland_view_from_view(view) == NULL) { + return 0; + } + switch (prop) { + case VIEW_PROP_X11_WINDOW_ID: + return view->wlr_xwayland_surface->window_id; + case VIEW_PROP_WINDOW_TYPE: + return *view->wlr_xwayland_surface->window_type; + default: + return 0; + } +} + static void configure(struct sway_view *view, double ox, double oy, int width, int height) { struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view); @@ -200,13 +216,17 @@ static void destroy(struct sway_view *view) { wl_list_remove(&xwayland_view->destroy.link); wl_list_remove(&xwayland_view->request_configure.link); wl_list_remove(&xwayland_view->request_fullscreen.link); + wl_list_remove(&xwayland_view->set_title.link); + wl_list_remove(&xwayland_view->set_class.link); + wl_list_remove(&xwayland_view->set_window_type.link); wl_list_remove(&xwayland_view->map.link); wl_list_remove(&xwayland_view->unmap.link); free(xwayland_view); } static const struct sway_view_impl view_impl = { - .get_prop = get_prop, + .get_string_prop = get_string_prop, + .get_int_prop = get_int_prop, .configure = configure, .set_activated = set_activated, .set_fullscreen = set_fullscreen, @@ -223,7 +243,6 @@ static void handle_commit(struct wl_listener *listener, void *data) { view_update_size(view, xwayland_view->pending_width, xwayland_view->pending_height); view_damage_from(view); - view_update_title(view, false); } static void handle_unmap(struct wl_listener *listener, void *data) { @@ -285,6 +304,40 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) view_set_fullscreen(view, xsurface->fullscreen); } +static void handle_set_title(struct wl_listener *listener, void *data) { + struct sway_xwayland_view *xwayland_view = + wl_container_of(listener, xwayland_view, set_title); + struct sway_view *view = &xwayland_view->view; + struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; + if (!xsurface->mapped) { + return; + } + view_update_title(view, false); + view_execute_criteria(view); +} + +static void handle_set_class(struct wl_listener *listener, void *data) { + struct sway_xwayland_view *xwayland_view = + wl_container_of(listener, xwayland_view, set_class); + struct sway_view *view = &xwayland_view->view; + struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; + if (!xsurface->mapped) { + return; + } + view_execute_criteria(view); +} + +static void handle_set_window_type(struct wl_listener *listener, void *data) { + struct sway_xwayland_view *xwayland_view = + wl_container_of(listener, xwayland_view, set_window_type); + struct sway_view *view = &xwayland_view->view; + struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; + if (!xsurface->mapped) { + return; + } + view_execute_criteria(view); +} + void handle_xwayland_surface(struct wl_listener *listener, void *data) { struct sway_server *server = wl_container_of(listener, server, xwayland_surface); @@ -323,6 +376,16 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { &xwayland_view->request_fullscreen); xwayland_view->request_fullscreen.notify = handle_request_fullscreen; + wl_signal_add(&xsurface->events.set_title, &xwayland_view->set_title); + xwayland_view->set_title.notify = handle_set_title; + + wl_signal_add(&xsurface->events.set_class, &xwayland_view->set_class); + xwayland_view->set_class.notify = handle_set_class; + + wl_signal_add(&xsurface->events.set_window_type, + &xwayland_view->set_window_type); + xwayland_view->set_window_type.notify = handle_set_window_type; + wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap); xwayland_view->unmap.notify = handle_unmap; diff --git a/sway/tree/view.c b/sway/tree/view.c index afd7eade..7d921e0e 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -3,6 +3,7 @@ #include #include #include +#include "list.h" #include "log.h" #include "sway/criteria.h" #include "sway/commands.h" @@ -19,6 +20,7 @@ void view_init(struct sway_view *view, enum sway_view_type type, const struct sway_view_impl *impl) { view->type = type; view->impl = impl; + view->executed_criteria = create_list(); wl_signal_init(&view->events.unmap); } @@ -31,6 +33,8 @@ void view_destroy(struct sway_view *view) { view_unmap(view); } + list_free(view->executed_criteria); + container_destroy(view->swayc); if (view->impl->destroy) { @@ -41,33 +45,47 @@ void view_destroy(struct sway_view *view) { } const char *view_get_title(struct sway_view *view) { - if (view->impl->get_prop) { - return view->impl->get_prop(view, VIEW_PROP_TITLE); + if (view->impl->get_string_prop) { + return view->impl->get_string_prop(view, VIEW_PROP_TITLE); } return NULL; } const char *view_get_app_id(struct sway_view *view) { - if (view->impl->get_prop) { - return view->impl->get_prop(view, VIEW_PROP_APP_ID); + if (view->impl->get_string_prop) { + return view->impl->get_string_prop(view, VIEW_PROP_APP_ID); } return NULL; } const char *view_get_class(struct sway_view *view) { - if (view->impl->get_prop) { - return view->impl->get_prop(view, VIEW_PROP_CLASS); + if (view->impl->get_string_prop) { + return view->impl->get_string_prop(view, VIEW_PROP_CLASS); } return NULL; } const char *view_get_instance(struct sway_view *view) { - if (view->impl->get_prop) { - return view->impl->get_prop(view, VIEW_PROP_INSTANCE); + if (view->impl->get_string_prop) { + return view->impl->get_string_prop(view, VIEW_PROP_INSTANCE); } return NULL; } +uint32_t view_get_x11_window_id(struct sway_view *view) { + if (view->impl->get_int_prop) { + return view->impl->get_int_prop(view, VIEW_PROP_X11_WINDOW_ID); + } + return 0; +} + +uint32_t view_get_window_type(struct sway_view *view) { + if (view->impl->get_int_prop) { + return view->impl->get_int_prop(view, VIEW_PROP_WINDOW_TYPE); + } + return 0; +} + const char *view_get_type(struct sway_view *view) { switch(view->type) { case SWAY_VIEW_WL_SHELL: @@ -282,19 +300,36 @@ static void view_handle_container_reparent(struct wl_listener *listener, } } -static void view_execute_criteria(struct sway_view *view) { - if (!sway_assert(view->swayc, "cannot run criteria for unmapped view")) { +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) { + if (!view->swayc) { return; } struct sway_seat *seat = input_manager_current_seat(input_manager); struct sway_container *prior_workspace = container_parent(view->swayc, C_WORKSPACE); - list_t *criteria = criteria_for(view->swayc); - for (int i = 0; i < criteria->length; i++) { - struct criteria *crit = criteria->items[i]; - wlr_log(L_DEBUG, "for_window '%s' matches new view %p, cmd: '%s'", - crit->crit_raw, view, crit->cmdlist); - struct cmd_results *res = execute_command(crit->cmdlist, NULL); + list_t *criterias = criteria_for_view(view, CT_COMMAND); + for (int i = 0; i < criterias->length; i++) { + struct criteria *criteria = criterias->items[i]; + wlr_log(L_DEBUG, "Checking criteria %s", criteria->raw); + if (view_has_executed_criteria(view, criteria)) { + wlr_log(L_DEBUG, "Criteria already executed"); + continue; + } + wlr_log(L_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", + criteria->raw, view, criteria->cmdlist); + list_add(view->executed_criteria, criteria); + struct cmd_results *res = execute_command(criteria->cmdlist, NULL); if (res->status != CMD_SUCCESS) { wlr_log(L_ERROR, "Command '%s' failed: %s", res->input, res->error); } @@ -303,7 +338,7 @@ static void view_execute_criteria(struct sway_view *view) { // so always refocus in-between command lists seat_set_focus(seat, view->swayc); } - list_free(criteria); + list_free(criterias); seat_set_focus(seat, seat_get_focus_inactive(seat, prior_workspace)); } @@ -313,9 +348,26 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { } struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus_inactive(seat, - &root_container); - struct sway_container *cont = container_view_create(focus, view); + struct sway_container *focus = seat_get_focus(seat); + struct sway_container *cont = NULL; + + // Check if there's any `assign` criteria for the view + list_t *criterias = criteria_for_view(view, + CT_ASSIGN_WORKSPACE | CT_ASSIGN_OUTPUT); + if (criterias->length) { + struct criteria *criteria = criterias->items[0]; + if (criteria->type == CT_ASSIGN_WORKSPACE) { + struct sway_container *workspace = workspace_by_name(criteria->target); + if (!workspace) { + workspace = workspace_create(NULL, criteria->target); + } + focus = seat_get_focus_inactive(seat, workspace); + } else { + // TODO: CT_ASSIGN_OUTPUT + } + } + free(criterias); + cont = container_view_create(focus, view); view->surface = wlr_surface; view->swayc = cont; @@ -333,10 +385,11 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { arrange_children_of(cont->parent); input_manager_set_focus(input_manager, cont); + view_update_title(view, false); + view_execute_criteria(view); + container_damage_whole(cont); view_handle_container_reparent(&view->container_reparent, NULL); - - view_execute_criteria(view); } void view_unmap(struct sway_view *view) { -- cgit v1.2.3 From 0bf0a4fa4049cbabeb797536e549640ec5235454 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Fri, 11 May 2018 10:42:24 +1000 Subject: Don't unescape \\ in criteria --- sway/criteria.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sway/criteria.c b/sway/criteria.c index 6abe24af..7da790e6 100644 --- a/sway/criteria.c +++ b/sway/criteria.c @@ -280,8 +280,7 @@ static void unescape(char *value) { char *readhead = value; char *writehead = copy; while (*readhead) { - if (*readhead == '\\' && - (*(readhead + 1) == '"' || *(readhead + 1) == '\\')) { + if (*readhead == '\\' && *(readhead + 1) == '"') { // skip the slash ++readhead; } -- cgit v1.2.3 From 8595fc5a6f81f00ab62bfea127f8fad5c0b249de Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Fri, 11 May 2018 10:43:10 +1000 Subject: Update criteria documentation --- sway/sway.5.txt | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/sway/sway.5.txt b/sway/sway.5.txt index 03975349..704bb699 100644 --- a/sway/sway.5.txt +++ b/sway/sway.5.txt @@ -485,11 +485,16 @@ Mark all Firefox windows with "Browser": Currently supported attributes: -**class**:: - Compare value against the window class. Can be a regular expression. If value - is _focused_, then the window class must be the same as that of the currently +**app_id**:: + Compare value against the app id. Can be a regular expression. If value is + __focused__, then the app id must be the same as that of the currently focused window. +**class**:: + Compare value against the window class. Can be a regular expression. If + value is __focused__, then the window class must be the same as that of the + currently focused window. + **con_id**:: Compare against the internal container ID, which you can find via IPC. @@ -500,20 +505,38 @@ Currently supported attributes: Matches against floating windows. **id**:: - Compare value against the app id. Can be a regular expression. + Compare value against the X11 window id. Must be numeric. + +**instance**:: + Compare value against the window instance. Can be a regular expression. If + value is __focused__, then the window instance must be the same as that of + the currently focused window. + +**tiling**:: + Matches against tiling windows. **title**:: Compare against the window title. Can be a regular expression. If value is - _focused_ then the window title must be the same as that of the currently + __focused__, then the window title must be the same as that of the currently focused window. -**tiling**:: - Matches against tiling windows. +**urgent**:: + Compares the urgent state of the window. Can be "latest" or "oldest". + +**window_role**:: + Compare against the window role (WM_WINDOW_ROLE). Can be a regular + expression. If value is __focused__, then the window role must be the same + as that of the currently focused window. + +**window_type**:: + Compare against the window type (_NET_WM_WINDOW_TYPE). Possible values are + normal, dialog, utility, toolbar, splash, menu, dropdown_menu, popup_menu, + tooltip and notification. **workspace**:: - Compare against the workspace name for this view. Can be a regular expression. - If the value is _focused_, then all the views on the currently focused workspace - matches. + Compare against the workspace name for this view. Can be a regular + expression. If the value is __focused__, then all the views on the currently + focused workspace matches. See Also -------- -- cgit v1.2.3 From 935bda0f336bb9ca45a7fb96d7ed5f08ef04432f Mon Sep 17 00:00:00 2001 From: Dudemanguy911 Date: Fri, 11 May 2018 01:20:20 +0000 Subject: fix crash on fullscreen toggle --- sway/tree/view.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sway/tree/view.c b/sway/tree/view.c index afd7eade..424c1084 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -163,13 +163,15 @@ void view_set_fullscreen_raw(struct sway_view *view, bool fullscreen) { struct sway_container *focus, *focus_ws; wl_list_for_each(seat, &input_manager->seats, link) { focus = seat_get_focus(seat); - focus_ws = focus; - if (focus_ws->type != C_WORKSPACE) { - focus_ws = container_parent(focus_ws, C_WORKSPACE); - } - seat_set_focus(seat, view->swayc); - if (focus_ws != workspace) { - seat_set_focus(seat, focus); + if (focus) { + focus_ws = focus; + if (focus && focus_ws->type != C_WORKSPACE) { + focus_ws = container_parent(focus_ws, C_WORKSPACE); + } + seat_set_focus(seat, view->swayc); + if (focus_ws != workspace) { + seat_set_focus(seat, focus); + } } } } else { -- cgit v1.2.3 From c2a7d367af8630fbc31b79146af76081c258c8ba Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 11 May 2018 08:39:46 -0400 Subject: Wire up scdoc and rewrite sway(1) --- meson.build | 25 ++++++--------- sway/sway.1.scd | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 16 deletions(-) create mode 100644 sway/sway.1.scd diff --git a/meson.build b/meson.build index f59d29b3..d1693ace 100644 --- a/meson.build +++ b/meson.build @@ -40,7 +40,6 @@ libpam = cc.find_library('pam') math = cc.find_library('m') rt = cc.find_library('rt') git = find_program('git', required: false) -a2x = find_program('a2x', required: false) conf_data = configuration_data() @@ -48,31 +47,25 @@ if gdk_pixbuf.found() conf_data.set('HAVE_GDK_PIXBUF', true) endif -if a2x.found() +scdoc = find_program('scdoc', required: false) + +if scdoc.found() + sh = find_program('sh') mandir = get_option('mandir') man_files = [ - 'sway/sway.1.txt', - 'sway/sway.5.txt', - 'sway/sway-bar.5.txt', - 'sway/sway-input.5.txt', - 'sway/sway-security.7.txt', - 'swaymsg/swaymsg.1.txt', + 'sway/sway.1.scd', ] foreach filename : man_files topic = filename.split('.')[-3].split('/')[-1] section = filename.split('.')[-2] + output = '@0@.@1@'.format(topic, section) custom_target( - 'man-@0@-@1@'.format(topic, section), + output, input: filename, - output: '@BASENAME@', + output: output, command: [ - a2x, - '--no-xmllint', - '--doctype', 'manpage', - '--format', 'manpage', - '--destination-dir', meson.current_build_dir(), - '@INPUT@' + sh, '-c', '@0@ < @INPUT@ > @1@'.format(scdoc.path(), output) ], install: true, install_dir: '@0@/man@1@'.format(mandir, section) diff --git a/sway/sway.1.scd b/sway/sway.1.scd new file mode 100644 index 00000000..02caa048 --- /dev/null +++ b/sway/sway.1.scd @@ -0,0 +1,95 @@ +sway(1) + +# NAME + +sway - SirCmpwn's Wayland window manager + +# SYNOPSIS + +*sway* [options...] [command] + +# OPTIONS + +*-h, --help* + Show help message and quit. + +*-c, --config* + Specifies a config file. + +*-C, --validate* + Check the validity of the config file, then exit. + +*-d, --debug* + Enables full logging, including debug information. + +*-v, --version* + Show the version number and quit. + +*-V, --verbose* + Enables more verbose logging. + +*--get-socketpath* + Gets the IPC socket path and prints it, then exits. + +# DESCRIPTION + +sway was created to fill the need of an i3-like window manager for Wayland. The +upstream i3 developers have no intention of porting i3 to Wayland, and projects +proposed by others ended up as vaporware. Many thanks to the i3 folks for +providing such a great piece of software, so good that your users would rather +write an entirely new window manager from scratch that behaved _exactly_ like i3 +rather than switch to something else. + +You can run sway directly from a tty, or via a Wayland-compatible login manager. + +# CONFIGURATION + +sway searches for a config file in the following locations, in this order: + +- ~/.sway/config +- $XDG\_CONFIG\_HOME/sway/config (suggested location) +- ~/.i3/config +- $XDG\_CONFIG\_HOME/i3/config +- /etc/sway/config +- /etc/i3/config + +If unset, $XDG\_CONFIG\_HOME defalts to *~/.config*. + +An error is raised when no config file is found. The recommended default +configuration is usually installed to */etc/sway/config*; you are encouraged to +copy this to *~/.config/sway/config* and edit it from there. + +For information on the config file format, see *sway*(5). + +# IPC COMMANDS + +Though *swaymsg*(1) is generally preferred, you may run *sway* _command_ to +send _command_ to the running instance of sway. You can also issue commands +with *i3-msg*(1) or even with *i3*(1). + +# ENVIRONMENT + +The following environment variables have an effect on sway: + +_SWAY\_CURSOR\_THEME_ + Specifies the name of the cursor theme to use. + +_SWAY\_CURSOR\_SIZE_ + Specifies the size of the cursor to use. + +_SWAYSOCK_ + Specifies the path to the sway IPC socket. + +_XKB\_DEFAULT\_RULES_, _XKB\_DEFAULT\_MODEL_, _XKB\_DEFAULT\_LAYOUT_, +_XKB\_DEFAULT\_VARIANT_, _XKB\_DEFAULT\_OPTIONS_ + Configures the xkb keyboard settings. See *xkeyboard-config*(7). + +# AUTHORS + +Maintained by Drew DeVault , who is assisted by other open +source contributors. For more information about sway development, see +. + +# SEE ALSO + +*sway*(5) *swaymsg*(1) *swaygrab*(1) *sway-input*(5) *sway-bar*(5) -- cgit v1.2.3 From 432256ad84af0b6ef62ff92fe3248d2ce8ceffd4 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 11 May 2018 20:58:34 -0400 Subject: Add sway(5) --- meson.build | 1 + sway/sway.1.scd | 16 +- sway/sway.1.txt | 109 ----------- sway/sway.5.scd | 578 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sway/sway.5.txt | 544 ---------------------------------------------------- 5 files changed, 587 insertions(+), 661 deletions(-) delete mode 100644 sway/sway.1.txt create mode 100644 sway/sway.5.scd delete mode 100644 sway/sway.5.txt diff --git a/meson.build b/meson.build index d1693ace..38590444 100644 --- a/meson.build +++ b/meson.build @@ -54,6 +54,7 @@ if scdoc.found() mandir = get_option('mandir') man_files = [ 'sway/sway.1.scd', + 'sway/sway.5.scd', ] foreach filename : man_files topic = filename.split('.')[-3].split('/')[-1] diff --git a/sway/sway.1.scd b/sway/sway.1.scd index 02caa048..5b770cce 100644 --- a/sway/sway.1.scd +++ b/sway/sway.1.scd @@ -46,14 +46,14 @@ You can run sway directly from a tty, or via a Wayland-compatible login manager. sway searches for a config file in the following locations, in this order: -- ~/.sway/config -- $XDG\_CONFIG\_HOME/sway/config (suggested location) -- ~/.i3/config -- $XDG\_CONFIG\_HOME/i3/config -- /etc/sway/config -- /etc/i3/config - -If unset, $XDG\_CONFIG\_HOME defalts to *~/.config*. +. ~/.sway/config +. $XDG\_CONFIG\_HOME/sway/config (suggested location) +. ~/.i3/config +. $XDG\_CONFIG\_HOME/i3/config +. /etc/sway/config +. /etc/i3/config + +If unset, $XDG\_CONFIG\_HOME defaults to *~/.config*. An error is raised when no config file is found. The recommended default configuration is usually installed to */etc/sway/config*; you are encouraged to diff --git a/sway/sway.1.txt b/sway/sway.1.txt deleted file mode 100644 index 17fc13da..00000000 --- a/sway/sway.1.txt +++ /dev/null @@ -1,109 +0,0 @@ -///// -vim:set ft=asciidoc ts=4 sw=4 tw=82 noet: -///// -:quotes.~: - -sway (1) -======== - -Name ----- -sway - SirCmpwn's Wayland window manager - -Synopsis --------- -'sway' [options] [command] - -Options -------- - -*-h, --help*:: - Show help message and quit. - -*-c, \--config* :: - Specifies a config file. - -*-C, \--validate*:: - Check the validity of the config file, then exit. - -*-d, --debug*:: - Enables full logging, including debug information. - -*-v, \--version*:: - Show the version number and quit. - -*-V, --verbose*:: - Enables more verbose logging. - -*--get-socketpath*:: - Gets the IPC socket path and prints it, then exits. - -Description ------------ - -sway was created to fill the need of an i3-like window manager for Wayland. The -upstream i3 developers have no intention of porting i3 to Wayland, and projects -proposed by others ended up as vaporware. Many thanks to the i3 folks for -providing such a great piece of software, so good that your users would rather -write an entirely new window manager from scratch that behaved _exactly_ like i3 -rather than switch to something else. - -Launch sway directly from a tty or via your favorite Wayland-compatible login -manager. - -Commands --------- - -If sway is currently running, you may run _sway [command]_ to send _command_ to -the running instance of sway. The same commands you would use in the config file -are valid here (see **sway**(5)). For compatibility reasons, you may also issue -commands with **swaymsg**(1) or **i3-msg**(1) (or even with **i3**(1), probably). - -Configuration -------------- - -The path to a config file can be given via the _-c_ parameter, else -sway searches for it in the following locations: -- ~/.sway/config -- $XDG_CONFIG_HOME/sway/config (suggested location) -- ~/.i3/config -- $XDG_CONFIG_HOME/i3/config (XDG_HOME ) -- /etc/sway/config -- /etc/i3/config - -In /etc/sway/config the standard config file is installed. -An error is raised when no config file is found. - -To write your own configuration, it's suggested that you copy the default config file to -the location of your choosing and start there. - -For information on the config file format, see **sway**(5). - -Environment ------------ - -The following environment variables have an effect on sway: - -*SWAY_CURSOR_THEME*:: - Specifies the name of the cursor theme to use. - -*SWAY_CURSOR_SIZE*:: - Specifies the size of the cursor to use. - -*SWAYSOCK*:: - Specifies the path to the sway IPC socket. - -*XKB_DEFAULT_RULES*, *XKB_DEFAULT_MODEL*, *XKB_DEFAULT_LAYOUT*, *XKB_DEFAULT_VARIANT*, *XKB_DEFAULT_OPTIONS*:: - Configures the xkb keyboard settings. See xkeyboard-config(7). - -Authors -------- - -Maintained by Drew DeVault , who is assisted by other open -source contributors. For more information about sway development, see -. - -See Also --------- - -**sway**(5) **swaymsg**(1) **swaygrab**(1) **sway-input**(5) **sway-bar**(5) diff --git a/sway/sway.5.scd b/sway/sway.5.scd new file mode 100644 index 00000000..75f1bf9d --- /dev/null +++ b/sway/sway.5.scd @@ -0,0 +1,578 @@ +sway(5) + +# NAME + +sway - configuration file and commands + +# DESCRIPTION + +A sway configuration file is a list of sway commands that are executed by sway +on startup. These commands usually consist of setting your preferences and +setting key bindings. An example config is likely present in /etc/sway/config +for you to check out. + +Lines in the configuration file might be extended through multiple lines by +adding a '\\' character at the end of line. e.g.: + +``` +bindsym Shift+XF86AudioRaiseVolume exec \\ + pactl set-sink-volume @DEFAULT_SINK@ -1% +``` + +These commands can be executed in your config file, via *swaymsg*(1), or via +the bindsym command. + +# COMMAND CONVENTIONS + +Commands are split into several arguments using spaces. You can enclose +arguments with quotation marks (*"..."* or *'...'*) to add spaces to a single +argument. You may also run several commands in order by separating each with +*,* or *;*. + +Throughout the documentation, *|* is used to distinguish between arguments for +which you may only select one. *[...]* is used for optional arguments, and +*<...>* for arguments where you are expected to supply some value. + +# COMMANDS + +The following commands may only be used in the configuration file. + +*bar {* *}* + _commands..._ after *{* will be interpreted as bar commands. For + details, see *sway-bar*(5). A newline is required between *{* and the + first command, and *}* must be alone on a line. + +*default\_orientation* horizontal|vertical|auto + Sets the default container layout for tiled containers. + +*include* + Includes another file from _path_. _path_ can be either a full path or a + path relative to the parent config, and expands shell syntax (see + *wordexp*(3) for details). The same include file can only be included once; + subsequent attempts will be ignored. + +*set* + Sets variable $_name_ to _value_. You can use the new variable in the + arguments of future commands. + +*swaybg\_command* + Executes custom bg _command_. Default is _swaybg_. Refer to **output** + below for more information. + +The following commands cannot be used directly in the configuration file. +They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). + +*border* normal|pixel [] + Set border style for focused window. _normal_ includes a border of + thickness _n_ and a title bar. _pixel_ is a border without title bar _n_ + pixels thick. Default is _normal_ with border thickness 2. + +*border* none|toggle + Set border style for focused window to _none_ or _toggle_ between the + available border styles: _normal_, _pixel_, _none_. + +*exit* + Exit sway and end your Wayland session. + +*floating* enable|disable|toggle + Make focused view floating, non-floating, or the opposite of what it is now. + +*focus* up|right|down|left + Moves focus to the next container in the specified direction. + +*focus* child + Moves focus to the last-focused child of the focused container. + +*focus* parent + Moves focus to the parent of the focused container. + +*focus* output up|right|down|left + Moves focus to the next output in the specified direction. + +*focus* output + Moves focus to the named output. + +*focus* mode\_toggle + Moves focus between the floating and tiled layers. + +*fullscreen* + Toggles fullscreen for the focused view. + +*layout* splith|splitv|stacking|tabbed + Sets the layout mode of the focused container. + +*layout* toggle split + Switches the focused container between the splitv and splith layouts. + +*move* left|right|up|down [] + Moves the focused container in the direction specified. If the container, + the optional _px_ argument specifies how many pixels to move the container. + If unspecified, the default is 10 pixels. Pixels are ignored when moving + tiled containers. + +*move* container|window to workspace + Moves the focused container to the specified workspace. + +*move* container|window to workspace prev|next + Moves the focused container to the previous or next workspace on this + output, or if no workspaces remain, the previous or next output. + +*move* container|window to workspace prev\_on\_output|next\_on\_output + Moves the focused container to the previous or next workspace on this + output, wrapping around if already at the first or last workspace. + +*move* container|window|workspace to output + Moves the focused container or workspace to the specified output. + +*move* container|window|workspace to output up|right|down|left + Moves the focused container or workspace to next output in the specified + direction. + +*move* [to] scratchpad + Moves the focused window to the scratchpad. + +*reload* + Reloads the sway config file and applies any changes. + +*resize* shrink|grow width|height [] [px|ppt] + Resizes the currently focused container by _amount_, specified in pixels or + percentage points. If omitted, floating containers are resized in px and + tiled containers by ppt. If omitted, the default _amount_ is 10. + +*resize set* [px] [px] + Sets the width and height of the currently focused container to _width_ + pixels and _height_ pixels. The [px] parameters are optional and have no + effect. This command only accepts a size in pixels. Width and height may be + specified in either order. + +*scratchpad show* + Shows a window from the scratchpad. Repeatedly using this command will + cycle through the windows in the scratchpad. + +*split* vertical|v|horizontal|h|toggle|t + Splits the current container, vertically or horizontally. When _toggle_ is + specified, the current container is split opposite to the parent + container's layout. + +*splith* + Equivalent to *split horizontal* + +*splitv* + Equivalent to *split vertical* + +*splitt* + Equivalent to *split toggle* + +*sticky* enable|disable|toggle + "Sticks" a floating window to the current output so that it shows up on all + workspaces. + +The following commands may be used either in the configuration file or at +runtime. + +*assign* [→] + Assigns views matching _criteria_ (see *CRITERIA* for details) to + _workspace_. The → (U+2192) is optional and cosmetic. This command is + equivalent to: + + for\_window move container to workspace + +*bindsym* + Binds _key combo_ to execute the sway command _command_ when pressed. You + may use XKB key names here (*xev*(1) is a good tool for discovering these). + + Example: + + # Execute firefox when alt, shift, and f are pressed together + bindsym Mod1+Shift+f exec firefox + + *bindcode* is also available for binding with key codes + instead of key names. + +*client.* + Configures the color of window borders and title bars. All 5 colors are + required, with the exception of *client.background*, which requires exactly + one. Colors may be specified in hex, either as _#RRGGBB_ or _#RRGGBBAA_. + + The available classes are: + + *client.background* + Ignored (present for i3 compatability). + + *client.focused* + The window that has focus. + + *client.focused\_inactive* + The most recently focused view within a container which is not focused. + + *client.placeholder* + Ignored (present for i3 compatability). + + *client.unfocused* + A view that does not have focus. + + *client.urgent* + A view with an urgency hint. *Note*: This is not currently implemented. + + The meaning of each color is: + + _border_ + The border around the title bar. + + _background_ + The background of the title bar. + + _text_ + The text color of the title bar. + + _indicator_ + The color used to indicate where a new view will open. In a tiled + container, this would paint the right border of the current view if a + new view would be opened to the right. + + _child\_border_ + The border around the view itself. + +The default colors are: + +[- *class* +:[ _border_ +:[ _background_ +:[ _text_ +:[ _indicator_ +:[ _child\_border_ +|[ *background* +: n/a +: #ffffff +: n/a +: n/a +: n/a +| *focused* +: #4c7899 +: #285577 +: #ffffff +: #2e9ef4 +: #285577 +| *focused\_inactive* +: #333333 +: #5f676a +: #ffffff +: #484e50 +: #5f676a +| *unfocused* +: #333333 +: #222222 +: #888888 +: #292d2e +: #222222 +| *urgent* +: #2f343a +: #900000 +: #ffffff +: #900000 +: #900000 +| *placeholder* +: #000000 +: #0c0c0c +: #ffffff +: #000000 +: #0c0c0c + +*debuglog* on|off|toggle + Enables, disables or toggles debug logging. _toggle_ cannot be used in the + configuration file. + +*default\_border* normal|none|pixel [] + Set default border style for new tiled windows. + +*default\_floating\_border* normal|none|pixel [] + Set default border style for new floating windows. This only applies to + windows that are spawned in floating mode, not windows that become floating + afterwards. + +*exec* + Executes _shell command_ with sh. + +*exec\_always* + Like exec, but the shell command will be executed _again_ after *reload*. + +*floating\_maximum\_size* x + Specifies the maximum size of floating windows. -1 x -1 removes the upper + limit. + +*floating\_minimum\_size* x + Specifies the minimum size of floating windows. The default is 75 x 50. + +*floating\_modifier* [normal|inverse] + When the _modifier_ key is held down, you may hold left click to move + windows, and right click to resize them. If _inverse_ is specified, left + click is used for resizing and right click for moving. + +*floating\_scroll* up|right|down|left [command] + Sets a command to be executed when the mouse wheel is scrolled in the + specified direction while holding the floating modifier. Resets the + command, when given no arguments. + +*focus\_follows\_mouse* yes|no + If set to _yes_, moving your mouse over a window will focus that window. + +*font* + Sets font for use in title bars in Pango format. + +*for\_window* + Whenever a window that matches _criteria_ appears, run list of commands. + See *CRITERIA* for more details. + +*gaps* edge\_gaps on|off|toggle + When _on_, gaps will be added between windows and workspace edges if the + inner gap is nonzero. When _off_, gaps will only be added between views. + _toggle_ cannot be used in the configuration file. + +*gaps* + Sets _amount_ pixels of gap between windows and around each workspace. + +*gaps* inner|outer + Sets default _amount_ pixels of _inner_ or _outer_ gap, where the former + affects spacing between views and the latter affects the space around each + workspace. + +*gaps* inner|outer all|workspace|current set|plus|minus + Changes the gaps for the _inner_ or _outer_ gap. _all_ changes the gaps for + all views or workspace, _workspace_ changes gaps for all views in current + workspace (or current workspace), and _current_ changes gaps for the current + view or workspace. + +*hide\_edge\_borders* none|vertical|horizontal|both|smart + Hides window borders adjacent to the screen edges. Default is _none_. + +*input* *{* *}* + _commands..._ after *{* will be interpreted as input commands applying to + the specified input device. For details, see *sway-input*(5). A newline is + required between *{* and the first command, and *}* must be alone on a + line. + + \* may be used in lieu of a specific device name to configure all input + devices. A list of input device names may be obtained via *swaymsg -t + get\_inputs*. + +*seat* *{* *}* + _commands..._ after *{* will be interpreted as seat commands applying to + the specified seat. For details, see *sway-input*(5). A newline is required + between *{* and the first command, and *}* must be alone on a line. + +*seat* cursor move|set + Move specified seat's cursor relative to current position or wrap to + absolute coordinates (with respect to the global coordinate space). + Specifying either value as 0 will not update that coordinate. + +*seat* cursor press|release left|right|1|2|3... + Simulate pressing (or releasing) the specified mouse button on the + specified seat. + +*kill* + Kills (closes) the currently focused container and all of its children. + +*smart\_gaps* on|off + If smart\_gaps are _on_ gaps will only be enabled if a workspace has more + than one child. + +*mark* --add|--replace [--toggle] + Marks are arbitrary labels that can be used to identify certain windows and + then jump to them at a later time. By default, *mark* sets _identifier_ as + the only mark on a window. _--add_ will instead add _identifier_ to the + list of current marks. If _--toggle_ is specified mark will remove + _identifier_ if it is already marked. + +*mode* + Switches to the specified mode. The default mode _default_. + +*mode* *{* *}* + _commands..._ after *{* will be added to the specified mode. A newline is + required between *{* and the first command, and *}* must be alone on a + line. Only *bindsym* and *bindcode* commands are permitted in mode blocks. + +*mouse\_warping* output|none + If _output_ is specified, the mouse will be moved to new outputs as you + move focus between them. + +*no\_focus* + Prevents windows matching from being focused automatically when + they're created. This has no effect on the first window in a workspace. + +*output* mode|resolution|res [@[Hz]] + Configures the specified output to use the given mode. Modes are a + combination of width and height (in pixels) and a refresh rate that your + display can be configured to use. For a list of available modes for each + output, use *swaymsg -t get\_outputs*. + + Examples: + + output HDMI-A-1 mode 1920x1080 + + output HDMI-A-1 mode 1920x1080@60Hz + +*output* position|pos + Places the specified output at the specific position in the global + coordinate space. + +*output* scale + Scales the specified output by the specified scale _factor_. An integer is + recommended, but fractional values are also supported. If a fractional + value are specified, be warned that it is not possible to faithfully + represent the contents of your windows - they will be rendered at the next + highest integral scale factor and downscaled. You may be better served by + setting an integral scale factor and adjusting the font size of your + applications to taste. + +*output* background|bg + Sets the wallpaper for the given output to the specified file, using the + given scaling mode (one of "stretch", "fill", "fit", "center", "tile"). + +**output** background|bg solid\_color + Sets the background of the given output to the specified color. _color_ + should be specified as _#RRGGBB_. Alpha is not supported. + +**output** transform + Sets the background transform to the given value. Can be one of "90", "180", + "270" for rotation; or "flipped", "flipped-90", "flipped-180", "flipped-270" + to apply a rotation and flip, or "normal" to apply no transform. + +*output* disable|enable + Enables or disables the specified output (all outputs are enabled by + default). + +*NOTES FOR THE OUTPUT COMMANDS* + +You may combine output commands into one, like so: + + output HDMI-A-1 mode 1920x1080 pos 1920,0 bg ~/wallpaper.png stretch + +You can get a list of output names with *swaymsg -t get\_outputs*. You may also +match any output by using the output name "\*". Be sure to add this output +config after the others, or it will be matched instead of the others. + +*show\_marks* on|off + If *show\_marks* is on, marks will be displayed in the window borders. + Any mark that starts with an underscore will not be drawn even if the + option is on. The default is _on_. + +*opacity* + Set the opacity of the window between 0 (completely transparent) and 1 + (completely opaque). + +*unmark* [] + *unmark* will remove _identifier_ from the list of current marks on a + window. If _identifier_ is omitted, all marks are removed. + +*workspace* [number] + Switches to the specified workspace. The string "number" is optional and is + used to sort workspaces. + +*workspace* prev|next + Switches to the next workspace on the current output or on the next output + if currently on the last workspace. + +*workspace* prev\_on\_output|next\_on\_output + Switches to the next workspace on the current output. + +*workspace* output + Specifies that workspace _name_ should be shown on the specified _output_. + +*workspace\_auto\_back\_and\_forth* yes|no + When _yes_, repeating a workspace switch command will switch back to the + prior workspace. For example, if you are currently on workspace 1, + switch to workspace 2, then invoke the "workspace 2" command again, you + will be returned to workspace 1. Default is _no_. + +*workspace\_layout* default|stacking|tabbed + Specifies the initial layout for new workspaces. + +# CRITERIA + +A criteria is a string in the form of, for example: + +``` +[class="[Rr]egex.*" title="some title"] +``` + +The string contains one or more (space separated) attribute/value pairs. They +are used by some commands to choose which views to execute actions on. All +attributes must match for the criteria to match. + +Criteria may be used with either the *for\_window* or *assign* commands to +specify operations to perform on new views. A criteria may also be used to +perform specific commands (ones that normally act upon one window) on all views +that match that criteria. For example: + +Focus on a window with the mark "IRC": + +``` +[con_mark="IRC"] focus +``` + +Kill all windows with the title "Emacs": + +``` +[class="Emacs"] kill +``` + +Mark all Firefox windows with "Browser": + +``` +[class="Firefox"] mark Browser +``` + +The following attributes may be matched with: + +*app\_id* + Compare value against the app id. Can be a regular expression. If value is + \_\_focused\_\_, then the app id must be the same as that of the currently + focused window. + +*class* + Compare value against the window class. Can be a regular expression. If + value is \_\_focused\_\_, then the window class must be the same as that of + the currently focused window. + +*con\_id* + Compare against the internal container ID, which you can find via IPC. + +*con\_mark* + Compare against the window marks. Can be a regular expression. + +*floating* + Matches floating windows. + +*id* + Compare value against the X11 window ID. Must be numeric. + +*instance* + Compare value against the window instance. Can be a regular expression. If + value is \_\_focused\_\_, then the window instance must be the same as that + of the currently focused window. + +*tiling* + Matches tiling windows. + +*title* + Compare against the window title. Can be a regular expression. If value is + \_\_focused\_\_, then the window title must be the same as that of the + currently focused window. + +*urgent* + Compares the urgent state of the window. Can be "latest" or "oldest". + +*window\_role* + Compare against the window role (WM\_WINDOW\_ROLE). Can be a regular + expression. If value is \_\_focused\_\_, then the window role must be the + same as that of the currently focused window. + +*window\_type* + Compare against the window type (\_NET\_WM\_WINDOW\_TYPE). Possible values + are normal, dialog, utility, toolbar, splash, menu, dropdown\_menu, + popup\_menu, tooltip and notification. + +*workspace* + Compare against the workspace name for this view. Can be a regular + expression. If the value is \_\_focused\_\_, then all the views on the + currently focused workspace matches. diff --git a/sway/sway.5.txt b/sway/sway.5.txt deleted file mode 100644 index 704bb699..00000000 --- a/sway/sway.5.txt +++ /dev/null @@ -1,544 +0,0 @@ -///// -vim:set ts=4 sw=4 tw=82 noet: -///// -sway (5) -======== - -Name ----- -sway - configuration file and commands - -Description ------------ - -A sway configuration file is a list of sway commands that are executed by sway -on startup. These commands usually consist of setting your preferences and -setting key bindings. An example config is likely present in /etc/sway/config -for you to check out. - -Lines in the configuration file might be extended through multiple lines by -adding a '\' character at the end of line. e.g.: - - bindsym Shift+XF86AudioRaiseVolume exec pactl set-sink-volume \ - $(pactl list sinks | grep -B 1 RUNNING | sed '1q;d' | sed 's/[^0-9]\+//g') +5% - -These commands can be executed in your config file, via **swaymsg**(1), or via -the bindsym command. - -Commands --------- - -The following commands may only be used in the configuration file. - -**bar** :: - Append _{_ to this command, the following lines will be commands that - configure **swaybar**, and _}_ on its own line to close the block. - + - See **sway-bar**(5) for details. - -**default_orientation** :: - Sets the default container layout for tiled containers. - -**set** :: - Sets variable $name to _value_. You can use the new variable in the arguments - of future commands. - -**swaybg_command** :: - Executes custom bg command, default is _swaybg_. - -The following commands cannot be used directly in the configuration file. -They are expected to be used with **bindsym** or at runtime through **swaymsg**(1). - -**border** []:: - Set border style for focused window. _normal_ includes a border of thickness - _n_ and a title bar. _pixel_ is a border without title bar _n_ pixels thick. - Default is _normal_ with border thickness 2. - -**border** :: - Set border style for focused window to _none_ or _toggle_ between the - available border styles: _normal_, _pixel_, _none_. - -**exit**:: - Exit sway and end your Wayland session. - -**floating** :: - Make focused view floating, non-floating, or the opposite of what it is now. - -**focus** :: - Direction may be one of _up_, _down_, _left_, _right_, _next_, _prev_, - _parent_, or _child_. The directional focus commands will move the focus - in that direction. The _next_ and _prev_ directions will focus the next, - respectively previous, element in the current container. The parent - focus command will change the focus to the parent of the currently - focused container, which is useful, for example, to open a sibling of - the parent container, or to move the entire container around. - -**focus** output :: - Direction may be one of _up_, _down_, _left_, _right_. The directional focus - commands will move the focus to the output in that direction. When name is - given, the focus is changed to the output with that name. - -**focus** mode_toggle:: - Toggles focus between floating view and tiled view. - -**fullscreen**:: - Toggles fullscreen status for the focused view. - -**layout** :: - Sets the layout mode of the focused container. _mode_ can be one of _splith_, - _splitv_, _toggle split_, _stacking_, _tabbed_. - -**layout** auto :: - Sets layout to one of the auto modes, i.e. one of _left_, _right_, _top_, - or _bottom_. - -**layout** auto :: - Cycles between available auto layouts. - -**layout** auto [master|ncol] [inc|set] :: - Modify the number of master elements, respectively slave columns, in the - focused container. can be a positive or negative integer. These commands - only have an effect if the focused container uses one of the "auto" layouts. - -**layout** toggle split:: - Cycles between available split layouts. - -**move** <[px]>:: - Moves the focused container _left_, _right_, _up_, or _down_. If the window - is floating it moves it _px_ in that direction, defaulting to 10. Tiled - containers are moved the same regardless of the _px_ argument. - -**move** :: - Moving to _prev_ or _next_ swaps the container with its sibling in the same - container. Move _first_ exchanges the focused element in an auto layout with - the first element, i.e. promotes the focused element to master position. - -**move** to workspace :: - Moves the focused container to the workspace identified by _name_. - _name_ may be a special workspace name. See **workspace**. - -**move** to output :: - Moves the focused container or workspace to the output identified by _name_ or - _direction_. _direction_ may be one of _up_, _down_, _left_, _right_. - -**move** [to] scratchpad:: - Moves the focused window to the scratchpad. - -**reload**:: - Reloads the sway config file without restarting sway. - -**resize** [] [px|ppt]:: - Resizes the currently focused container or view by _amount_. _amount_ is - optional: the default value is 10 (either px or ppt depending on the view type). - The [px|ppt] parameter is optional. _px_ specifies that _amount_ refers to pixels; - _ppt_ specifies that _amount_ refers to percentage points of the current - size. Floating views use px by default (but can use ppt if specified); tiled - views use ppt by default (but can use px if specified). - -**resize set** [px] [px]:: - Sets the width and height of the currently focused container to _width_ pixels - and _height_ pixels. The [px] parameters are optional and have no effect. This - command only accepts a size in pixels. - -**resize set** [px] [ [px]]:: - Sets the _width_ and/or _height_ of the currently focused container to - _amount_. The [px] parameters are optional and have no effect. This command - only accepts a size in pixels. - -**scratchpad show**:: - Shows a window from the scratchpad. Repeatedly using this command will cycle - through the windows in the scratchpad. - -**split** :: - Splits the current container, vertically or horizontally. If toggled, then the - current container is split opposite to the parent container. - -**splith**:: - Equivalent to **split horizontal**. - -**splitv**:: - Equivalent to **split vertical**. - -**splitt**:: - Equivalent to **split toggle**. - -**sticky** :: - "Sticks" a floating window to the current output so that it shows up on all - workspaces. - -The following commands may be used either in the configuration file -or triggered at runtime. - -**assign** [→] :: - Assigns views matching _criteria_ (see **Criteria** section below) to - _workspace_. The → (U+2192) is optional and purely for aesthetics. This - command is exactly equivalent to "for_window move container to - workspace ". - -**bindsym** :: - Binds _key combo_ to execute _command_ when pressed. You may use XKB key - names here (**xev**(1) is a good tool for discovering them). An example - bindsym command would be **bindsym Mod1+Shift+f exec firefox**, which would - execute Firefox if the alt, shift, and F keys are pressed together. Any - valid sway command is eligible to be bound to a key combo. - + - **bindcode** is also available for binding with key codes - instead of key names. - -**client**. :: - The client commands control the colors of the view borders and title bars. All - client commands _require_ five color values. (The one exception is - **client.background** which _requires_ one color value.) If you only want to - specify a subset, supply default colors for all the others. Colors must be - defined in hex. i.e. _#rrggbb_ or _#rrggbbaa_, when including the alpha - channel. - + - The command tokens are: - **color_class**::: Specifies the view to which the colors apply. - **client.background**:::: The color a view will be painted, underneath the - client itself. This will only be visible if a client does not fully - cover its allocated view space. This command only requires one color. _Note_: - This is not currently implemented. - **client.focused**:::: The view that has focus. - **client.focused_inactive**:::: A view that has focus within its - container, but the container is not focused. - **client.placeholder**:::: Used when drawing placeholder view contents. - Only background and text colors are used. _Note_: This is not - currently implemented. - **client.unfocused**:::: A view that does not have focus. - **client.urgent**:::: A view with an urgency hint. _Note_: This is not - currently implemented. - **border**::: The border around the title bar. - **background**::: The background of the title bar. - **text**::: The text color of the title bar. - **indicator**::: The color used to indicate where a new view will open. In a - tiled container, this would paint the right border of the current view if - a new view would be opened to the right. - **child_border**::: The border around the view itself. - -+ -The default colors are: -+ --- -[options="header"] -|=========================================================================== -|color_class |border |background |text |indicator |child_border -|background |n/a |#ffffff |n/a |n/a |n/a -|focused |#4c7899 |#285577 |#ffffff |#2e9ef4 |#285577 -|focused_inactive |#333333 |#5f676a |#ffffff |#484e50 |#5f676a -|unfocused |#333333 |#222222 |#888888 |#292d2e |#222222 -|urgent |#2f343a |#900000 |#ffffff |#900000 |#900000 -|placeholder |#000000 |#0c0c0c |#ffffff |#000000 |#0c0c0c -|=========================================================================== --- - -**debuglog** :: - Enables, disables or toggles debug logging. The toggle argument cannot be used - in the configuration file. - -**default_border** []:: - Set default border style for new windows. This command was previously called - **new_window**. While **new_window** still works, it is considered deprecated - and support for it will be removed in the future. - -**default_floating_border** []:: - Set default border style for new floating windows. This only applies to - windows that are spawned in floating mode, not windows that become floating - after the fact. This command was previously called **new_float**. While - **new_float** still works, it is considered deprecated and support for it will - be removed in the future. - -**exec** :: - Executes _shell command_ with sh. - -**exec_always** :: - Like exec, but the shell command will be executed _again_ after *reload* or - *restart* is executed. - -**floating_maximum_size** x :: - Specifies the maximum size of floating windows. - Uses the container size as default. - -1 x -1 will remove any restriction on size. - 0 x 0 has the same behavior as not setting any value. - If in conflict, this option has precedence over floating_minimum_size. - -**floating_minimum_size** x :: - Specifies the minimum size of floating windows. - Default parameters are 75 x 50. - -1 and 0 are invalid parameters, default will be used instead. - -**floating_modifier** [normal|inverse]:: - When the _modifier_ key is held down, you may hold left click to move floating - windows, and right click to resize them. Unlike i3, this modifier may also be - used to resize and move windows that are tiled. With the _inverse_ mode - enabled, left click is used for resizing and right click for dragging. The - mode parameter is optional and defaults to _normal_ if it isn't defined. - -**floating_scroll** [command]:: - Sets a command to be executed when the mouse wheel is scrolled in the - specified direction while holding the floating modifier. Resets the command, - when given no arguments. - -**focus_follows_mouse** :: - If set to _yes_, moving your mouse over a window will focus that window. - -**font** :: - Sets font for use in title bars. Generally the format is something like "Name - Style Size" e.g. "Deja Vu Sans Book 12". You can also use Pango font - descriptions with "pango:font". - -**for_window** :: - Whenever a window that matches _criteria_ appears, run list of commands. See - **Criteria** section below. - -**gaps** edge_gaps :: - Whether or not to add gaps between views and workspace edges if amount of - inner gap is not zero. When _off_, no gap is added where the view is aligned to - the workspace edge, effectively creating gaps only between views. The toggle - argument cannot be used in the configuration file. - -**gaps** :: - Sets default _amount_ pixels as the gap between each view, and around each - workspace. - -**gaps** :: - Sets default _amount_ pixels as the _inner_ or _outer_ gap, where the former - affects spacing between views and the latter affects the space around each - workspace. - -**gaps** :: - Changes the gaps for the _inner_ or _outer_ gap. _all_ changes the gaps for - all views or workspace, _workspace_ changes gaps for all views in current - workspace (or current workspace), and _current_ changes gaps for the current - view or workspace. - -**hide_edge_borders** :: - Hide window borders adjacent to the screen edges. Default is _none_. - -**input** :: - Append _{_ to this command, the following lines will be commands to configure - the named input device, and _}_ on its own line will close the block. - + - **input * ** may be used to match all input devices. - + - See **sway-input**(5) for details. - -**seat** :: - Append _{_ to this command, the following lines will be commands to configure - the named seat, and _}_ on its own line will close the block. - See **sway-input**(5) for details. - -**seat** cursor :: - Move cursor relatively to current position or set to absolute screen position. - A value of 0 causes the axis to be ignored in both commands. - -**seat** cursor :: - Simulate press of mouse button specified by left, right, or numerical code. - -**kill**:: - Kills (force-closes) the currently-focused container and all of its children. - -**smart_gaps** :: - If smart_gaps are _on_ then gaps will only be enabled if a workspace has more - than one child container. - -**mark** \<--add|--replace> \<--toggle> :: - Marks are arbitrary labels that can be used to identify certain windows and - then jump to them at a later time. By default, the **mark** command sets - _identifier_ as the only mark on a window. By specifying _--add_, mark will - add _identifier_ to the list of current marks. If _--toggle_ is specified mark - will remove _identifier_ if it is already a label. Marks may be found by using - a criteria. See the **Criteria** section below. - -**mode** :: - Switches to the given mode_name. The default mode is simply _default_. To - create a new mode append _{_ to this command, the following lines - will be keybindings for that mode, and _}_ on its own line to close the block. - -**mouse_warping** :: - When _output_: place mouse at center of newly focused window when changing - output. When _none_: don't move mouse. - -**no_focus** :: - Prevents windows matching from being focused automatically when - they're created. This does not apply to the first window in a workspace. - -**output** mode|resolution|res [@[Hz]]:: - Configures the specified output to use the given mode. Modes are a combination - of width and height (in pixels) and a refresh rate that your display can be - configured to use. For a list of available modes, use swaymsg -t get_outputs. - + - Examples: - + - output HDMI-A-1 mode 1920x1080 - + - output HDMI-A-1 mode 1920x1080@60Hz - -**output** position|pos :: - Configures the specified output to be arranged at the given position. - -**output** scale :: - Configures the specified output to be scaled up by the specified integer - scaling factor (usually 2 for HiDPI screens). Fractional scaling is supported. - -**output** background|bg :: - Sets the wallpaper for the given output to the specified file, using the given - scaling mode (one of "stretch", "fill", "fit", "center", "tile"). - -**output** background|bg solid_color:: - Sets the background of the given output to the specified color. _color_ should - be specified as an _#rrggbb_ (no alpha) color. - -**output** transform :: - Sets the background transform to the given value. Can be one of "90", "180", - "270" for rotation; or "flipped", "flipped-90", "flipped-180", "flipped-270" - to apply a rotation and flip, or "normal" to apply no transform. - -**output** disable:: - Disables the specified output. - -**NOTES FOR THE OUTPUT COMMAND**:: - You may combine output commands into one, like so: - + - output HDMI-A-1 mode 1920x1080 pos 1920,0 bg ~/wallpaper.png stretch - + - You can get a list of output names like so: - + - swaymsg -t get_outputs - + - You may also match any output by using the output name "*". Be sure to add - this output config after the others, or it will be matched instead of the - others. - -**seamless_mouse** :: - Change output seamlessly when pointer touches edge of output. Outputs need to - be configured with perfectly aligned adjacent positions for this option to - have any effect. - -**show_marks** :: - If **show_marks** is on then marks will be showed in the window decoration. - However, any mark that starts with an underscore will not be drawn even if the - option is on. The default option is _on_. - -**opacity** :: - Set the opacity of the window between 0 (completely transparent) and 1 - (completely opaque). - -**unmark** :: - **Unmark** will remove _identifier_ from the list of current marks on a window. If - no _identifier_ is specified, then **unmark** will remove all marks. - -**workspace** [number] :: - Switches to the specified workspace. The string "number" is optional. The - workspace _name_, if unquoted, may not contain the string "output", as sway - will assume that the command is moving a workspace to an output, as described - below. - -**workspace** :: - Switches to the next workspace on the current output or on the next output - if currently on the last workspace. - -**workspace** :: - Switches to the next workspace on the current output. - -**workspace** output :: - Specifies that the workspace named _name_ should appear on the specified - _output_. - -**workspace_auto_back_and_forth** :: - When _yes_, repeating a workspace switch command will switch back to the - prior workspace. For example, if you are currently on workspace 1, - switch to workspace 2, then invoke the "workspace 2" command again, you - will be returned to workspace 1. Defaults to _no_. - -**workspace_layout** :: Specifies the start layout for new workspaces. - -**include** :: - Includes a sub config file by _path_. _path_ can be either a full path or a - path relative to the parent config. - -Criteria --------- - -A criteria is a string in the form of e.g.: - - [class="[Rr]egex.*" title="some title"] - -The string contains one or more (space separated) attribute/value pairs. They -are used by some commands to choose which views to execute actions on. All attributes -must match for the criteria to match. - -Criteria may be used with either the **for_window** or **assign** commands to -specify operations to perform on new views. A criteria may also be used to -perform specific commands (ones that normally act upon one window) on all views -that match that criteria. For example: - -Focus on a window with the mark "IRC": - [con_mark="IRC"] focus - -Kill all windows with the title "Emacs": - [class="Emacs"] kill - -Mark all Firefox windows with "Browser": - [class="Firefox"] mark Browser - -Currently supported attributes: - -**app_id**:: - Compare value against the app id. Can be a regular expression. If value is - __focused__, then the app id must be the same as that of the currently - focused window. - -**class**:: - Compare value against the window class. Can be a regular expression. If - value is __focused__, then the window class must be the same as that of the - currently focused window. - -**con_id**:: - Compare against the internal container ID, which you can find via IPC. - -**con_mark**:: - Compare against the window marks. Can be a regular expression. - -**floating**:: - Matches against floating windows. - -**id**:: - Compare value against the X11 window id. Must be numeric. - -**instance**:: - Compare value against the window instance. Can be a regular expression. If - value is __focused__, then the window instance must be the same as that of - the currently focused window. - -**tiling**:: - Matches against tiling windows. - -**title**:: - Compare against the window title. Can be a regular expression. If value is - __focused__, then the window title must be the same as that of the currently - focused window. - -**urgent**:: - Compares the urgent state of the window. Can be "latest" or "oldest". - -**window_role**:: - Compare against the window role (WM_WINDOW_ROLE). Can be a regular - expression. If value is __focused__, then the window role must be the same - as that of the currently focused window. - -**window_type**:: - Compare against the window type (_NET_WM_WINDOW_TYPE). Possible values are - normal, dialog, utility, toolbar, splash, menu, dropdown_menu, popup_menu, - tooltip and notification. - -**workspace**:: - Compare against the workspace name for this view. Can be a regular - expression. If the value is __focused__, then all the views on the currently - focused workspace matches. - -See Also --------- - -**sway**(1) **sway-input**(5) **sway-bar**(5) -- cgit v1.2.3 From 18134822666691a25050eff1a46df82a4108de3f Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 11 May 2018 21:13:43 -0400 Subject: Add sway-bar(5) --- meson.build | 1 + sway/sway-bar.5.scd | 147 ++++++++++++++++++++++++++++++++++++++++++++++++ sway/sway-bar.5.txt | 159 ---------------------------------------------------- sway/sway.5.scd | 4 ++ 4 files changed, 152 insertions(+), 159 deletions(-) create mode 100644 sway/sway-bar.5.scd delete mode 100644 sway/sway-bar.5.txt diff --git a/meson.build b/meson.build index 38590444..6b0f6a15 100644 --- a/meson.build +++ b/meson.build @@ -55,6 +55,7 @@ if scdoc.found() man_files = [ 'sway/sway.1.scd', 'sway/sway.5.scd', + 'sway/sway-bar.5.scd', ] foreach filename : man_files topic = filename.split('.')[-3].split('/')[-1] diff --git a/sway/sway-bar.5.scd b/sway/sway-bar.5.scd new file mode 100644 index 00000000..a61e2829 --- /dev/null +++ b/sway/sway-bar.5.scd @@ -0,0 +1,147 @@ +sway-bar(5) + +# NAME + +sway-bar - bar configuration file and commands + +# DESCRIPTION + +Sway allows configuring swaybar in the sway configuration file. Swaybar +commands must be used inside a _bar { }_ block in the config file. + +# COMMANDS + +*status\_command* + Executes the bar _status command_ with _sh -c_. Each line of text printed + to stdout from this command will be displayed in the status area of the + bar. You may also use the i3bar JSON protocol: + + https://i3wm.org/docs/i3bar-protocol.html + +*pango\_markup* enabled|disabled + Enables or disables pango markup for status lines. This has no effect on + status lines using the i3bar JSON protocol. + +*id* + Sets the ID of the bar. + +*position* top|bottom + Sets position of the bar. Default is _bottom_. + +*output* + Restrict the bar to a certain output, can be specified multiple times. If + the output command is omitted, the bar will be displayed on all outputs. + +*swaybar\_command* + Executes custom bar command. Default is _swaybar_. + +*font* + Specifies the font to be used in the bar. + +*separator\_symbol* + Specifies the separator symbol to separate blocks on the bar. + +*wrap\_scroll* yes|no + Enables or disables wrapping when scrolling through workspaces with the + scroll wheel. Default is _no_. + +*workspace\_buttons* yes|no + Enables or disables workspace buttons on the bar. Default is _yes_. + +*strip\_workspace\_numbers* yes|no + If set to _yes_, then workspace numbers will be omitted from the workspace + button and only the custom name will be shown. Default is _no_. + +*binding\_mode\_indicator* yes|no + Enable or disable binding mode indicator. Default is _yes_. + +*height* + Sets the height of the bar. Default height will match the font size. + +## TRAY + +Swaybar provides a system tray where third-party applications may place icons. +The following commands configure the tray. + +The _button_ argument in all cases is a platform-specific button code. On Linux +you can find a list of these at linux/input-event-codes.h. + +*activate\_button*