From 8cd7f0171ad8ffc4ce490f6f4b18522cb178c951 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Tue, 19 Mar 2019 23:07:32 -0400 Subject: [PATCH 01/21] cmd_mode: allow cmd_set to be a subcommand This allows set to be used in mode blocks --- sway/commands/mode.c | 3 ++- sway/sway.5.scd | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sway/commands/mode.c b/sway/commands/mode.c index 3e0ee80cb..ef2c5d794 100644 --- a/sway/commands/mode.c +++ b/sway/commands/mode.c @@ -13,7 +13,8 @@ static struct cmd_handler mode_handlers[] = { { "bindcode", cmd_bindcode }, { "bindswitch", cmd_bindswitch }, - { "bindsym", cmd_bindsym } + { "bindsym", cmd_bindsym }, + { "set", cmd_set }, }; struct cmd_results *cmd_mode(int argc, char **argv) { diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 18fc28a30..dbfeefe3c 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -573,9 +573,9 @@ The default colors are: Switches to the specified mode. The default mode _default_. *mode* [--pango_markup] - The only valid _mode-subcommands..._ are *bindsym*, *bindcode* and - *bindswitch*. If _--pango_markup_ is given, then _mode_ will be interpreted - as pango markup. + The only valid _mode-subcommands..._ are *bindsym*, *bindcode*, + *bindswitch*, and *set*. If _--pango_markup_ is given, then _mode_ will be + interpreted as pango markup. *mouse_warping* output|container|none If _output_ is specified, the mouse will be moved to new outputs as you From 7d2076cbff2b363061d52362927d0da2f3c4865b Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sat, 23 Mar 2019 03:49:29 -0400 Subject: [PATCH 02/21] criteria: fix __focused__ when no focus or unset This fixes the behavior of `__focused__` when there is no focused view to match i3's behavior of successfully matching no views instead of returning an error of a missing value. It also applies the same logic when a token is not applicable (or unset) for a view such as `app_id` for a focused xwayland view or `class` for a focused xdg-shell view. This adds an `autofail` boolean to `struct criteria`. If it is set to `true`, then `criteria_matches_view` will immediately bail out as a no match. If `autofail` is set, the criteria will also not be considered empty by `criteria_is_empty`. To set this new `autofail` property, `get_focused_prop` will now take in a boolean pointer of the same name. If `__focused__` is supported for the token and there is no focused view or the focused view does not have a value for the token, then the boolean will be set to true. In `parse_token`, the boolean value will be checked and if set to true, then `criteria->autofail` will be set to true and `parse_token` will bail successfully. Tokens will still be parsed to make sure the whole criteria is syntactically valid, which is also why `&criteria->autofail` is not passed to `get_focused_prop` and a local boolean is declared in `parse_token`. --- include/sway/criteria.h | 1 + sway/criteria.c | 69 ++++++++++++++++++++++++++++------------- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/include/sway/criteria.h b/include/sway/criteria.h index f7e788c8b..8a1d9e5ef 100644 --- a/include/sway/criteria.h +++ b/include/sway/criteria.h @@ -20,6 +20,7 @@ struct criteria { char *cmdlist; char *target; // workspace or output name for `assign` criteria + bool autofail; // __focused__ while no focus or n/a for focused view pcre *title; pcre *shell; pcre *app_id; diff --git a/sway/criteria.c b/sway/criteria.c index f2db6c184..11b41f356 100644 --- a/sway/criteria.c +++ b/sway/criteria.c @@ -16,7 +16,8 @@ #include "config.h" bool criteria_is_empty(struct criteria *criteria) { - return !criteria->title + return !criteria->autofail + && !criteria->title && !criteria->shell && !criteria->app_id && !criteria->con_mark @@ -98,6 +99,10 @@ static void find_urgent_iterator(struct sway_container *con, void *data) { static bool criteria_matches_view(struct criteria *criteria, struct sway_view *view) { + if (criteria->autofail) { + return false; + } + if (criteria->title) { const char *title = view_get_title(view); if (!title || regex_cmp(title, criteria->title) != 0) { @@ -366,50 +371,66 @@ static enum criteria_token token_from_name(char *name) { * using criteria via IPC. Using __focused__ in config is not useful because * criteria is only executed once per view. */ -static char *get_focused_prop(enum criteria_token token) { +static char *get_focused_prop(enum criteria_token token, bool *autofail) { struct sway_seat *seat = input_manager_current_seat(); struct sway_container *focus = seat_get_focused_container(seat); - if (!focus || !focus->view) { - return NULL; - } - struct sway_view *view = focus->view; + struct sway_view *view = focus ? focus->view : NULL; const char *value = NULL; switch (token) { case T_APP_ID: - value = view_get_app_id(view); + *autofail = true; + if (view) { + value = view_get_app_id(view); + } break; case T_SHELL: - value = view_get_shell(view); + *autofail = true; + if (view) { + value = view_get_shell(view); + } break; case T_TITLE: - value = view_get_title(view); + *autofail = true; + if (view) { + value = view_get_title(view); + } break; case T_WORKSPACE: - if (focus->workspace) { + *autofail = true; + if (focus && focus->workspace) { value = focus->workspace->name; } break; case T_CON_ID: - if (view->container == NULL) { - return NULL; + *autofail = true; + if (view && view->container) { + size_t id = view->container->node.id; + size_t id_size = snprintf(NULL, 0, "%zu", id) + 1; + char *id_str = malloc(id_size); + snprintf(id_str, id_size, "%zu", id); + value = id_str; } - size_t id = view->container->node.id; - size_t id_size = snprintf(NULL, 0, "%zu", id) + 1; - char *id_str = malloc(id_size); - snprintf(id_str, id_size, "%zu", id); - value = id_str; break; #if HAVE_XWAYLAND case T_CLASS: - value = view_get_class(view); + *autofail = true; + if (view) { + value = view_get_class(view); + } break; case T_INSTANCE: - value = view_get_instance(view); + *autofail = true; + if (view) { + value = view_get_instance(view); + } break; case T_WINDOW_ROLE: - value = view_get_window_role(view); + *autofail = true; + if (view) { + value = view_get_window_role(view); + } break; case T_WINDOW_TYPE: // These do not support __focused__ case T_ID: @@ -419,6 +440,7 @@ static char *get_focused_prop(enum criteria_token token) { case T_TILING: case T_URGENT: case T_INVALID: + *autofail = false; break; } if (value) { @@ -439,7 +461,12 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) { char *effective_value = NULL; if (value && strcmp(value, "__focused__") == 0) { - effective_value = get_focused_prop(token); + bool autofail = false; + effective_value = get_focused_prop(token, &autofail); + if (!effective_value && autofail) { + criteria->autofail = true; + return true; + } } else if (value) { effective_value = strdup(value); } From cd8b4ace926bd5a5289a5d5d6f6dddc1e4732287 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sat, 23 Mar 2019 17:24:53 -0400 Subject: [PATCH 03/21] fix opening a floating view on the NOOP output Since the NOOP output has no size, the minimum floating size is greater than the workspace size for the NOOP output. In this case, the floater gets centered in the output instead of the workspace. However, the NOOP output is not part of the output layout and thus has a NULL box. Attempting to access the properties of this box was causing a segfault. This fixes the issue by just setting the floater's box to all zeroes when mapping on the NOOP output. When the workspace gets moved from the NOOP output to a new output, any floater whose width or height is zero or has an x or y location outside of the output, gets passed to `container_init_floating` again. This will then set the appropriate size and centering. For any floater that has a valid size and location, they are preserved. --- sway/tree/container.c | 15 +++++++++++---- sway/tree/output.c | 21 +++++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/sway/tree/container.c b/sway/tree/container.c index 93cff7ff5..f84ce3602 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -651,6 +651,17 @@ void floating_calculate_constraints(int *min_width, int *max_width, void container_init_floating(struct sway_container *con) { struct sway_workspace *ws = con->workspace; + struct wlr_box *ob = wlr_output_layout_get_box(root->output_layout, + ws->output->wlr_output); + if (!ob) { + // On NOOP output. Will be called again when moved to an output + con->x = 0; + con->y = 0; + con->width = 0; + con->height = 0; + return; + } + int min_width, max_width, min_height, max_height; floating_calculate_constraints(&min_width, &max_width, &min_height, &max_height); @@ -659,8 +670,6 @@ void container_init_floating(struct sway_container *con) { con->width = max_width; con->height = max_height; if (con->width > ws->width || con->height > ws->height) { - struct wlr_box *ob = wlr_output_layout_get_box(root->output_layout, - ws->output->wlr_output); con->x = ob->x + (ob->width - con->width) / 2; con->y = ob->y + (ob->height - con->height) / 2; } else { @@ -675,8 +684,6 @@ void container_init_floating(struct sway_container *con) { fmax(min_height, fmin(view->natural_height, max_height)); if (con->content_width > ws->width || con->content_height > ws->height) { - struct wlr_box *ob = wlr_output_layout_get_box(root->output_layout, - ws->output->wlr_output); con->content_x = ob->x + (ob->width - con->content_width) / 2; con->content_y = ob->y + (ob->height - con->content_height) / 2; } else { diff --git a/sway/tree/output.c b/sway/tree/output.c index 1202ba3c5..7867c6bc6 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -60,6 +60,27 @@ static void restore_workspaces(struct sway_output *output) { struct sway_workspace *ws = root->noop_output->workspaces->items[0]; workspace_detach(ws); output_add_workspace(output, ws); + + // If the floater was made floating while on the NOOP output, its width + // and height will be zero and it should be reinitialized as a floating + // container to get the appropriate size and location. Additionally, if + // the floater is wider or taller than the output or is completely + // outside of the output's bounds, do the same as the output layout has + // likely changed and the maximum size needs to be checked and the + // floater re-centered + for (int i = 0; i < ws->floating->length; i++) { + struct sway_container *floater = ws->floating->items[i]; + if (floater->width == 0 || floater->height == 0 || + floater->width > output->width || + floater->height > output->height || + floater->x > output->lx + output->width || + floater->y > output->ly + output->height || + floater->x + floater->width < output->lx || + floater->y + floater->height < output->ly) { + container_init_floating(floater); + } + } + ipc_event_workspace(NULL, ws, "move"); } From 200833caaea36dd65324e5460520731f5c98ff8a Mon Sep 17 00:00:00 2001 From: mliszcz Date: Sat, 23 Mar 2019 11:32:44 +0100 Subject: [PATCH 04/21] Allow for workspace renaming during exec handling This change adds support for renaming a workspace when `exec` command is being processed by keeping sway_workspace and pid_workspace names in sync. The change can be verified by running following command: swaymsg exec ; swaymsg rename workspace number 1 to 5 Fixes: #3952 --- include/sway/tree/root.h | 2 ++ sway/commands/rename.c | 4 ++++ sway/tree/root.c | 14 ++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/include/sway/tree/root.h b/include/sway/tree/root.h index 9f6cd3bb6..c4f84207d 100644 --- a/include/sway/tree/root.h +++ b/include/sway/tree/root.h @@ -85,4 +85,6 @@ struct sway_container *root_find_container( void root_get_box(struct sway_root *root, struct wlr_box *box); +void root_rename_pid_workspaces(const char *old_name, const char *new_name); + #endif diff --git a/sway/commands/rename.c b/sway/commands/rename.c index 88377b092..3b855fdf7 100644 --- a/sway/commands/rename.c +++ b/sway/commands/rename.c @@ -9,6 +9,7 @@ #include "sway/output.h" #include "sway/tree/container.h" #include "sway/tree/workspace.h" +#include "sway/tree/root.h" static const char expected_syntax[] = "Expected 'rename workspace to ' or " @@ -89,6 +90,9 @@ struct cmd_results *cmd_rename(int argc, char **argv) { } sway_log(SWAY_DEBUG, "renaming workspace '%s' to '%s'", workspace->name, new_name); + + root_rename_pid_workspaces(workspace->name, new_name); + free(workspace->name); workspace->name = new_name; diff --git a/sway/tree/root.c b/sway/tree/root.c index 0744192b2..5dde9f22d 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c @@ -390,3 +390,17 @@ void root_get_box(struct sway_root *root, struct wlr_box *box) { box->width = root->width; box->height = root->height; } + +void root_rename_pid_workspaces(const char *old_name, const char *new_name) { + if (!pid_workspaces.prev && !pid_workspaces.next) { + wl_list_init(&pid_workspaces); + } + + struct pid_workspace *pw = NULL; + wl_list_for_each(pw, &pid_workspaces, link) { + if (strcmp(pw->workspace, old_name) == 0) { + free(pw->workspace); + pw->workspace = strdup(new_name); + } + } +} From 6e3046878d4dced3f2e503973ad31d7921c0c400 Mon Sep 17 00:00:00 2001 From: Geoff Greer Date: Sun, 10 Feb 2019 16:56:57 -0800 Subject: [PATCH 05/21] Add support for manually setting subpixel hinting on outputs. Many laptop screens report unknown subpixel order. Allow users to manually set subpixel hinting to work around this. Addresses https://github.com/swaywm/sway/issues/3163 --- common/util.c | 21 +++++++++++++++++++ include/sway/commands.h | 1 + include/sway/config.h | 1 + include/sway/output.h | 1 + include/util.h | 3 +++ sway/commands/output.c | 1 + sway/commands/output/subpixel.c | 36 +++++++++++++++++++++++++++++++++ sway/config/output.c | 23 +++++++++++++++++---- sway/ipc-server.c | 2 ++ sway/meson.build | 1 + sway/sway-ipc.7.scd | 4 ++++ sway/sway-output.5.scd | 7 +++++++ sway/tree/output.c | 1 + swaymsg/main.c | 5 ++++- 14 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 sway/commands/output/subpixel.c diff --git a/common/util.c b/common/util.c index edbbf3f77..c43c5ddf6 100644 --- a/common/util.c +++ b/common/util.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "log.h" #include "util.h" @@ -54,3 +55,23 @@ float parse_float(const char *value) { } return flt; } + + +const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel) { + switch (subpixel) { + case WL_OUTPUT_SUBPIXEL_UNKNOWN: + return "unknown"; + case WL_OUTPUT_SUBPIXEL_NONE: + return "none"; + case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB: + return "rgb"; + case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR: + return "bgr"; + case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB: + return "vrgb"; + case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR: + return "vbgr"; + } + sway_assert(false, "Unknown value for wl_output_subpixel."); + return NULL; +} diff --git a/include/sway/commands.h b/include/sway/commands.h index 1c147c5ab..7533a14d3 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -261,6 +261,7 @@ sway_cmd output_cmd_enable; sway_cmd output_cmd_mode; sway_cmd output_cmd_position; sway_cmd output_cmd_scale; +sway_cmd output_cmd_subpixel; sway_cmd output_cmd_transform; sway_cmd seat_cmd_attach; diff --git a/include/sway/config.h b/include/sway/config.h index 8970696c4..d49120a06 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -184,6 +184,7 @@ struct output_config { int x, y; float scale; int32_t transform; + enum wl_output_subpixel subpixel; char *background; char *background_option; diff --git a/include/sway/output.h b/include/sway/output.h index 8015f2110..c336c5592 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -31,6 +31,7 @@ struct sway_output { int lx, ly; // layout coords int width, height; // transformed buffer size + enum wl_output_subpixel detected_subpixel; bool enabled, configured; list_t *workspaces; diff --git a/include/util.h b/include/util.h index 1fd772c0c..6a668fd65 100644 --- a/include/util.h +++ b/include/util.h @@ -3,6 +3,7 @@ #include #include +#include /** * Wrap i into the range [0, max[ @@ -29,4 +30,6 @@ bool parse_boolean(const char *boolean, bool current); */ float parse_float(const char *value); +const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel); + #endif diff --git a/sway/commands/output.c b/sway/commands/output.c index 40dbf3ca4..44e28512f 100644 --- a/sway/commands/output.c +++ b/sway/commands/output.c @@ -18,6 +18,7 @@ static struct cmd_handler output_handlers[] = { { "res", output_cmd_mode }, { "resolution", output_cmd_mode }, { "scale", output_cmd_scale }, + { "subpixel", output_cmd_subpixel }, { "transform", output_cmd_transform }, }; diff --git a/sway/commands/output/subpixel.c b/sway/commands/output/subpixel.c new file mode 100644 index 000000000..63191ee62 --- /dev/null +++ b/sway/commands/output/subpixel.c @@ -0,0 +1,36 @@ +#include +#include "log.h" +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/output.h" + +struct cmd_results *output_cmd_subpixel(int argc, char **argv) { + if (!config->handler_context.output_config) { + return cmd_results_new(CMD_FAILURE, "Missing output config"); + } + if (!argc) { + return cmd_results_new(CMD_INVALID, "Missing subpixel argument."); + } + enum wl_output_subpixel subpixel; + + if (strcmp(*argv, "rgb") == 0) { + subpixel = WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB; + } else if (strcmp(*argv, "bgr") == 0) { + subpixel = WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR; + } else if (strcmp(*argv, "vrgb") == 0) { + subpixel = WL_OUTPUT_SUBPIXEL_VERTICAL_RGB; + } else if (strcmp(*argv, "vbgr") == 0) { + subpixel = WL_OUTPUT_SUBPIXEL_VERTICAL_BGR; + } else if (strcmp(*argv, "none") == 0) { + subpixel = WL_OUTPUT_SUBPIXEL_NONE; + } else { + return cmd_results_new(CMD_INVALID, "Invalid output subpixel."); + } + + struct output_config *oc = config->handler_context.output_config; + config->handler_context.leftovers.argc = argc - 1; + config->handler_context.leftovers.argv = argv + 1; + + oc->subpixel = subpixel; + return NULL; +} diff --git a/sway/config/output.c b/sway/config/output.c index 44aae03aa..d06051b34 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -8,10 +8,11 @@ #include #include #include -#include "log.h" #include "sway/config.h" #include "sway/output.h" #include "sway/tree/root.h" +#include "log.h" +#include "util.h" int output_name_cmp(const void *item, const void *data) { const struct output_config *output = item; @@ -43,6 +44,7 @@ struct output_config *new_output_config(const char *name) { oc->x = oc->y = -1; oc->scale = -1; oc->transform = -1; + oc->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN; return oc; } @@ -65,6 +67,9 @@ void merge_output_config(struct output_config *dst, struct output_config *src) { if (src->scale != -1) { dst->scale = src->scale; } + if (src->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN) { + dst->subpixel = src->subpixel; + } if (src->refresh_rate != -1) { dst->refresh_rate = src->refresh_rate; } @@ -187,10 +192,10 @@ struct output_config *store_output_config(struct output_config *oc) { } sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz " - "position %d,%d scale %f transform %d) (bg %s %s) (dpms %d)", + "position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (dpms %d)", oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate, - oc->x, oc->y, oc->scale, oc->transform, oc->background, - oc->background_option, oc->dpms_state); + oc->x, oc->y, oc->scale, sway_wl_output_subpixel_to_string(oc->subpixel), + oc->transform, oc->background, oc->background_option, oc->dpms_state); return oc; } @@ -363,6 +368,14 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { sway_log(SWAY_DEBUG, "Set %s scale to %f", oc->name, oc->scale); wlr_output_set_scale(wlr_output, oc->scale); } + + if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) { + sway_log(SWAY_DEBUG, "Set %s subpixel to %s", oc->name, + sway_wl_output_subpixel_to_string(oc->subpixel)); + wlr_output_set_subpixel(wlr_output, oc->subpixel); + output_damage_whole(output); + } + if (oc && oc->transform >= 0) { sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, oc->transform); wlr_output_set_transform(wlr_output, oc->transform); @@ -424,6 +437,8 @@ static void default_output_config(struct output_config *oc, } oc->x = oc->y = -1; oc->scale = 1; + struct sway_output *output = wlr_output->data; + oc->subpixel = output->detected_subpixel; oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; oc->dpms_state = DPMS_ON; } diff --git a/sway/ipc-server.c b/sway/ipc-server.c index df57cba51..e133a5bf1 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -644,6 +644,8 @@ void ipc_client_handle_command(struct ipc_client *client) { json_object_object_add(output_json, "focused", json_object_new_boolean(focused)); + const char *subpixel = sway_wl_output_subpixel_to_string(output->wlr_output->subpixel); + json_object_object_add(output_json, "subpixel_hinting", json_object_new_string(subpixel)); json_object_array_add(outputs, output_json); } struct sway_output *output; diff --git a/sway/meson.build b/sway/meson.build index 66876bdcd..9f79fb6ce 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -169,6 +169,7 @@ sway_sources = files( 'commands/output/mode.c', 'commands/output/position.c', 'commands/output/scale.c', + 'commands/output/subpixel.c', 'commands/output/transform.c', 'tree/arrange.c', diff --git a/sway/sway-ipc.7.scd b/sway/sway-ipc.7.scd index b43b30302..3d22008e4 100644 --- a/sway/sway-ipc.7.scd +++ b/sway/sway-ipc.7.scd @@ -211,6 +211,9 @@ following properties: |- scale : float : The scale currently in use on the output or _-1_ for disabled outputs +|- subpixel_hinting +: string +: The subpixel hinting current in use on the output. This can be _rgb_, _bgr_, _vrgb_, _vbgr_, or _none_ |- transform : string : The transform currently in use for the output. This can be _normal_, _90_, @@ -242,6 +245,7 @@ following properties: "active": true, "primary": false, "scale": 1.0, + "subpixel_hinting": "rgb", "transform": "normal", "current_workspace": "1", "modes": [ diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd index bb3745f36..1efe2f7bf 100644 --- a/sway/sway-output.5.scd +++ b/sway/sway-output.5.scd @@ -64,6 +64,13 @@ must be separated by one space. For example: applications to taste. HiDPI isn't supported with Xwayland clients (windows will blur). +*output* subpixel rgb|bgr|vrgb|vbgr|none + Manually sets the subpixel hinting for the specified output. This value is + usually auto-detected, but some displays may misreport their subpixel + geometry. Using the correct subpixel hinting allows for sharper text. + Incorrect values will result in blurrier text. When changing this via + *swaymsg*, some applications may need to be restarted to use the new value. + *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"). If diff --git a/sway/tree/output.c b/sway/tree/output.c index 7867c6bc6..283036524 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -92,6 +92,7 @@ struct sway_output *output_create(struct wlr_output *wlr_output) { node_init(&output->node, N_OUTPUT, output); output->wlr_output = wlr_output; wlr_output->data = output; + output->detected_subpixel = wlr_output->subpixel; wl_signal_init(&output->events.destroy); diff --git a/swaymsg/main.c b/swaymsg/main.c index 65cc4bbb1..f86000a42 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -186,11 +186,12 @@ static void pretty_print_output(json_object *o) { json_object_object_get_ex(o, "focused", &focused); json_object_object_get_ex(o, "active", &active); json_object_object_get_ex(o, "current_workspace", &ws); - json_object *make, *model, *serial, *scale, *transform; + json_object *make, *model, *serial, *scale, *subpixel, *transform; json_object_object_get_ex(o, "make", &make); json_object_object_get_ex(o, "model", &model); json_object_object_get_ex(o, "serial", &serial); json_object_object_get_ex(o, "scale", &scale); + json_object_object_get_ex(o, "subpixel_hinting", &subpixel); json_object_object_get_ex(o, "transform", &transform); json_object *x, *y; json_object_object_get_ex(rect, "x", &x); @@ -209,6 +210,7 @@ static void pretty_print_output(json_object *o) { " Current mode: %dx%d @ %f Hz\n" " Position: %d,%d\n" " Scale factor: %f\n" + " Subpixel hinting: %s\n" " Transform: %s\n" " Workspace: %s\n", json_object_get_string(name), @@ -221,6 +223,7 @@ static void pretty_print_output(json_object *o) { (float)json_object_get_int(refresh) / 1000, json_object_get_int(x), json_object_get_int(y), json_object_get_double(scale), + json_object_get_string(subpixel), json_object_get_string(transform), json_object_get_string(ws) ); From c3d7036867b958b08f6506737ffafe9052c17194 Mon Sep 17 00:00:00 2001 From: Philz69 Date: Sun, 24 Mar 2019 15:19:13 -0400 Subject: [PATCH 06/21] Updated the french readme (#3964) * Updated the french readme Removed the image at the start of the readme. Removed the mention of bounties. Updated the dependencies. Removed a few lines that were not present in the english readme anymore. * Fix errors. Fixed capitalisation. Changed "root" to italics. --- README.fr.md | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/README.fr.md b/README.fr.md index ad627ba54..97c09667b 100644 --- a/README.fr.md +++ b/README.fr.md @@ -6,14 +6,8 @@ avec i3, **en cours de développement**. Lisez la IRC](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway sur irc.freenode.net). -[![](https://sr.ht/ICd5.png)](https://sr.ht/ICd5.png) - -Si vous souhaitez soutenir le développement de Sway, vous pouvez contribuer à [ma page -Patreon](https://patreon.com/sircmpwn) ou aux [primes](https://github.com/swaywm/sway/issues/986) -pour des fonctionnalités spécifiques. -Tout le monde est invité à réclamer une prime et vous pouvez donner une prime pour n'importe quelle -fonctionnalité souhaitée. Patreon est plus utile pour supporter l'état général et la -maintenance de Sway. +Si vous souhaitez soutenir le développement de Sway, vous pouvez contribuer à [la page +Patreon de SirCmpwn](https://patreon.com/sircmpwn). ## Aide en français @@ -39,21 +33,21 @@ IRC ou envoyez un e-mail à sir@cmpwn.com (en anglais seulement) pour des consei Installez les dépendances : -* meson -* [wlc](https://github.com/Cloudef/wlc) +* meson \* +* [wlroots](https://github.com/swaywm/wlroots) * wayland -* xwayland -* libinput >= 1.6.0 -* libcap +* wayland-protocols \* * pcre -* json-c >= 0.13 +* json-c * pango * cairo -* gdk-pixbuf2 * -* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (requis pour les pages man) -* git +* gdk-pixbuf2 \*\* +* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (optionnel: requis pour les pages man) \* +* git \* -_\*Uniquement requis pour swaybar, swaybg_ +_\*Requis uniquement pour la compilation_ + +_\*\*Optionnel: requis uniquement pour swaybg_ Exécutez ces commandes : @@ -65,6 +59,8 @@ Sur les systèmes sans logind, vous devez suid le binaire de sway : sudo chmod a+s /usr/local/bin/sway +Sway se débarassera des permissions *root* peu de temps après le démarrage. + ## Configuration Si vous utilisez déjà i3, copiez votre configuration i3 à `~/.config/sway/config` et @@ -72,10 +68,6 @@ cela va fonctionner. Sinon, copiez l'exemple de fichier de configuration à `~/.config/sway/config`. Il se trouve généralement dans `/etc/sway/config`. Exécutez `man 5 sway` pour l'information sur la configuration. -Mes propres dotfiles sont disponibles [ici](https://git.sr.ht/~sircmpwn/dotfiles) si -vous voulez un peu d'inspiration. Je vous recommande aussi de consulter le -[wiki](https://github.com/swaywm/sway/wiki). - ## Exécution Exécutez `sway` à partir d'un TTY. Certains gestionnaires d'affichage peuvent fonctionner, From 8d2c982f3fea5b7f83680809bf4d986edfd625a3 Mon Sep 17 00:00:00 2001 From: Philipe Goulet Date: Fri, 22 Mar 2019 20:51:10 -0400 Subject: [PATCH 07/21] Fix #3924 Removes "unescape_string(argv[i]);". Since "do_var_replacement(argv[i])" never adds escape characters, it is both wrong and unnecessary to remove escape characters on the next line. This caused characters that were meant to be escaped to not be anymore. --- sway/commands.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sway/commands.c b/sway/commands.c index 18b95c738..0d9460a21 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -276,7 +276,6 @@ list_t *execute_command(char *_exec, struct sway_seat *seat, // Var replacement, for all but first argument of set for (int i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { argv[i] = do_var_replacement(argv[i]); - unescape_string(argv[i]); } if (!config->handler_context.using_criteria) { From d9de5b87583ccf8b633980ebbdec67227bbe7db4 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sun, 24 Mar 2019 21:21:24 -0400 Subject: [PATCH 08/21] Implement inhibit_idle command This implements the following command to set/unset a user idle inhibitor for a view: `inhibit_idle focus|fullscreen|open|none|visible` The modes are as follows: - focus: inhibited when the view is focused by any seat - fullscreen: inhibited when the view is fullscreen (or a descendant of a fullscreen container) and is visible on any output - open: inhibited until the view is closed or the inhibitor is unset or changed - none: unsets any user set idle inhibitors for the view - visible: inhibited when the view is visible on any output This should have no effect on idle inhibitors set by the applications themselves and those should still work as intended. Since this operates on the view in the handler context, it is possible to set it on the currently focused view, on any existing view with criteria, or for any future view with for_window. --- include/sway/commands.h | 1 + include/sway/desktop/idle_inhibit_v1.h | 20 +++++- sway/commands.c | 1 + sway/commands/inhibit_idle.c | 51 +++++++++++++ sway/desktop/idle_inhibit_v1.c | 99 ++++++++++++++++++++++---- sway/desktop/transaction.c | 2 +- sway/meson.build | 1 + sway/sway.5.scd | 12 ++++ 8 files changed, 171 insertions(+), 16 deletions(-) create mode 100644 sway/commands/inhibit_idle.c diff --git a/include/sway/commands.h b/include/sway/commands.h index 7533a14d3..9bd0f1cb5 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -136,6 +136,7 @@ sway_cmd cmd_fullscreen; sway_cmd cmd_gaps; sway_cmd cmd_hide_edge_borders; sway_cmd cmd_include; +sway_cmd cmd_inhibit_idle; sway_cmd cmd_input; sway_cmd cmd_seat; sway_cmd cmd_ipc; diff --git a/include/sway/desktop/idle_inhibit_v1.h b/include/sway/desktop/idle_inhibit_v1.h index e5ed8a3de..4d4e59b0b 100644 --- a/include/sway/desktop/idle_inhibit_v1.h +++ b/include/sway/desktop/idle_inhibit_v1.h @@ -4,6 +4,14 @@ #include #include "sway/server.h" +enum sway_idle_inhibit_mode { + INHIBIT_IDLE_APPLICATION, // Application set inhibitor (when visible) + INHIBIT_IDLE_FOCUS, // User set inhibitor when focused + INHIBIT_IDLE_FULLSCREEN, // User set inhibitor when fullscreen + visible + INHIBIT_IDLE_OPEN, // User set inhibitor while open + INHIBIT_IDLE_VISIBLE // User set inhibitor when visible +}; + struct sway_idle_inhibit_manager_v1 { struct wlr_idle_inhibit_manager_v1 *wlr_manager; struct wl_listener new_idle_inhibitor_v1; @@ -15,14 +23,24 @@ struct sway_idle_inhibit_manager_v1 { struct sway_idle_inhibitor_v1 { struct sway_idle_inhibit_manager_v1 *manager; struct sway_view *view; + enum sway_idle_inhibit_mode mode; struct wl_list link; struct wl_listener destroy; }; -void idle_inhibit_v1_check_active( +void sway_idle_inhibit_v1_check_active( struct sway_idle_inhibit_manager_v1 *manager); +void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view, + enum sway_idle_inhibit_mode mode); + +struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view( + struct sway_view *view); + +void sway_idle_inhibit_v1_user_inhibitor_destroy( + struct sway_idle_inhibitor_v1 *inhibitor); + struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create( struct wl_display *wl_display, struct wlr_idle *idle); #endif diff --git a/sway/commands.c b/sway/commands.c index 0d9460a21..abdaa3b87 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -112,6 +112,7 @@ static struct cmd_handler command_handlers[] = { { "exit", cmd_exit }, { "floating", cmd_floating }, { "fullscreen", cmd_fullscreen }, + { "inhibit_idle", cmd_inhibit_idle }, { "kill", cmd_kill }, { "layout", cmd_layout }, { "mark", cmd_mark }, diff --git a/sway/commands/inhibit_idle.c b/sway/commands/inhibit_idle.c new file mode 100644 index 000000000..aebc2bf9f --- /dev/null +++ b/sway/commands/inhibit_idle.c @@ -0,0 +1,51 @@ +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/desktop/idle_inhibit_v1.h" +#include "sway/tree/container.h" +#include "sway/tree/view.h" + +struct cmd_results *cmd_inhibit_idle(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "inhibit_idle", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + struct sway_container *con = config->handler_context.container; + if (!con || !con->view) { + return cmd_results_new(CMD_INVALID, + "Only views can have idle inhibitors"); + } + + bool clear = false; + enum sway_idle_inhibit_mode mode; + if (strcmp(argv[0], "focus") == 0) { + mode = INHIBIT_IDLE_FOCUS; + } else if (strcmp(argv[0], "fullscreen") == 0) { + mode = INHIBIT_IDLE_FULLSCREEN; + } else if (strcmp(argv[0], "open") == 0) { + mode = INHIBIT_IDLE_OPEN; + } else if (strcmp(argv[0], "none") == 0) { + clear = true; + } else if (strcmp(argv[0], "visible") == 0) { + mode = INHIBIT_IDLE_VISIBLE; + } else { + return cmd_results_new(CMD_INVALID, + "Expected `inhibit_idle focus|fullscreen|open|none|visible`"); + } + + struct sway_idle_inhibitor_v1 *inhibitor = + sway_idle_inhibit_v1_user_inhibitor_for_view(con->view); + if (inhibitor) { + if (clear) { + sway_idle_inhibit_v1_user_inhibitor_destroy(inhibitor); + } else { + inhibitor->mode = mode; + sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); + } + } else if (!clear) { + sway_idle_inhibit_v1_user_inhibitor_register(con->view, mode); + } + + return cmd_results_new(CMD_SUCCESS, NULL); +} diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c index 87b4ef43d..b981e5e5a 100644 --- a/sway/desktop/idle_inhibit_v1.c +++ b/sway/desktop/idle_inhibit_v1.c @@ -2,18 +2,24 @@ #include #include "log.h" #include "sway/desktop/idle_inhibit_v1.h" +#include "sway/input/seat.h" +#include "sway/tree/container.h" #include "sway/tree/view.h" #include "sway/server.h" +static void destroy_inhibitor(struct sway_idle_inhibitor_v1 *inhibitor) { + wl_list_remove(&inhibitor->link); + wl_list_remove(&inhibitor->destroy.link); + sway_idle_inhibit_v1_check_active(inhibitor->manager); + free(inhibitor); +} + static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_idle_inhibitor_v1 *inhibitor = wl_container_of(listener, inhibitor, destroy); sway_log(SWAY_DEBUG, "Sway idle inhibitor destroyed"); - wl_list_remove(&inhibitor->link); - wl_list_remove(&inhibitor->destroy.link); - idle_inhibit_v1_check_active(inhibitor->manager); - free(inhibitor); + destroy_inhibitor(inhibitor); } void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) { @@ -29,28 +35,93 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) { } inhibitor->manager = manager; + inhibitor->mode = INHIBIT_IDLE_APPLICATION; inhibitor->view = view_from_wlr_surface(wlr_inhibitor->surface); wl_list_insert(&manager->inhibitors, &inhibitor->link); - inhibitor->destroy.notify = handle_destroy; wl_signal_add(&wlr_inhibitor->events.destroy, &inhibitor->destroy); - idle_inhibit_v1_check_active(manager); + sway_idle_inhibit_v1_check_active(manager); } -void idle_inhibit_v1_check_active( +void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view, + enum sway_idle_inhibit_mode mode) { + struct sway_idle_inhibitor_v1 *inhibitor = + calloc(1, sizeof(struct sway_idle_inhibitor_v1)); + if (!inhibitor) { + return; + } + + inhibitor->manager = server.idle_inhibit_manager_v1; + inhibitor->mode = mode; + inhibitor->view = view; + wl_list_insert(&inhibitor->manager->inhibitors, &inhibitor->link); + + inhibitor->destroy.notify = handle_destroy; + wl_signal_add(&view->events.unmap, &inhibitor->destroy); + + sway_idle_inhibit_v1_check_active(inhibitor->manager); +} + +struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view( + struct sway_view *view) { + struct sway_idle_inhibitor_v1 *inhibitor; + wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors, + link) { + if (inhibitor->view == view && + inhibitor->mode != INHIBIT_IDLE_APPLICATION) { + return inhibitor; + } + } + return NULL; +} + +void sway_idle_inhibit_v1_user_inhibitor_destroy( + struct sway_idle_inhibitor_v1 *inhibitor) { + if (!inhibitor) { + return; + } + if (!sway_assert(inhibitor->mode != INHIBIT_IDLE_APPLICATION, + "User should not be able to destroy application inhibitor")) { + return; + } + destroy_inhibitor(inhibitor); +} + +static bool check_active(struct sway_idle_inhibitor_v1 *inhibitor) { + switch (inhibitor->mode) { + case INHIBIT_IDLE_APPLICATION: + // If there is no view associated with the inhibitor, assume visible + return !inhibitor->view || view_is_visible(inhibitor->view); + case INHIBIT_IDLE_FOCUS:; + struct sway_seat *seat = NULL; + wl_list_for_each(seat, &server.input->seats, link) { + struct sway_container *con = seat_get_focused_container(seat); + if (con && con->view && con->view == inhibitor->view) { + return true; + } + } + return false; + case INHIBIT_IDLE_FULLSCREEN: + return inhibitor->view->container && + container_is_fullscreen_or_child(inhibitor->view->container) && + view_is_visible(inhibitor->view); + case INHIBIT_IDLE_OPEN: + // Inhibitor is destroyed on unmap so it must be open/mapped + return true; + case INHIBIT_IDLE_VISIBLE: + return view_is_visible(inhibitor->view); + } + return false; +} + +void sway_idle_inhibit_v1_check_active( struct sway_idle_inhibit_manager_v1 *manager) { struct sway_idle_inhibitor_v1 *inhibitor; bool inhibited = false; wl_list_for_each(inhibitor, &manager->inhibitors, link) { - if (!inhibitor->view || !inhibitor->view->container) { - /* Cannot guess if view is visible so assume it is */ - inhibited = true; - break; - } - if (view_is_visible(inhibitor->view)) { - inhibited = true; + if ((inhibited = check_active(inhibitor))) { break; } } diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index e5f0ee3d1..51c6e7fca 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -349,7 +349,7 @@ static void transaction_progress_queue(void) { list_del(server.transactions, 0); if (!server.transactions->length) { - idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); + sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); return; } diff --git a/sway/meson.build b/sway/meson.build index 9f79fb6ce..12b86efb8 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -63,6 +63,7 @@ sway_sources = files( 'commands/fullscreen.c', 'commands/gaps.c', 'commands/hide_edge_borders.c', + 'commands/inhibit_idle.c', 'commands/kill.c', 'commands/mark.c', 'commands/opacity.c', diff --git a/sway/sway.5.scd b/sway/sway.5.scd index dbfeefe3c..1650cd60c 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -146,6 +146,18 @@ set|plus|minus _right_, _bottom_, and _left_ or per direction with _horizontal_ and _vertical_. +*inhibit_idle* focus|fullscreen|open|none|visible + Set/unset an idle inhibitor for the view. _focus_ will inhibit idle when + the view is focused by any seat. _fullscreen_ will inhibit idle when the + view is fullscreen (or a descendant of a fullscreen container) and is + visible. _open_ will inhibit idle until the view is closed (or the + inhibitor is unset/changed). _visible_ will inhibit idle when the view is + visible on any output. _none_ will remove any existing idle inhibitor for + the view. + + This can also be used with criteria to set an idle inhibitor for any + existing view or with _for_window_ to set idle inhibitors for future views. + *layout* default|splith|splitv|stacking|tabbed Sets the layout mode of the focused container. From e9d096468a3fe9d8346dd97a67e050938f0befde Mon Sep 17 00:00:00 2001 From: Igor Sviatniy Date: Mon, 25 Mar 2019 17:53:10 +0200 Subject: [PATCH 09/21] Update README.uk.md --- README.uk.md | 49 +++++++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/README.uk.md b/README.uk.md index 4c378a89f..b0c81c512 100644 --- a/README.uk.md +++ b/README.uk.md @@ -1,20 +1,12 @@ # sway -**Sway** це сумісний з i3 композитор [Wayland](http://wayland.freedesktop.org/) -(**у стані розробки**). Ознайомтесь з -[ЧаПами](https://github.com/swaywm/sway/wiki). Приєднуйтесь до [спільноти в +Sway це сумісний з i3 композитор [Wayland](http://wayland.freedesktop.org/). +Ознайомтесь з [ЧаПами](https://github.com/swaywm/sway/wiki). Приєднуйтесь до [спільноти в IRC](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway на irc.freenode.net). -[![](https://sr.ht/ICd5.png)](https://sr.ht/ICd5.png) - -Якщо ви хочете підтримати розробку Sway, ви можете зробити свій внесок у -[SirCmpwn'ову сторінку Patreon](https://patreon.com/sircmpwn) або до -[фонду винагород](https://github.com/swaywm/sway/issues/986) за реалізацію -певного функціоналу. -Кожен може виставити винагороду за реалізацію довільної функції -(і, відповідно, забрати її собі, виконавши це завдання); -кошти від сторінки Patreon підтримують загальну розробку та підтримку Sway. +Якщо ви маєте бажання підтримати розробку sway, ви можете зробити свій внесок на сторінці +[SirCmpwn у Patreon](https://patreon.com/sircmpwn). ## Підтримка українською мовою @@ -39,28 +31,28 @@ Sway доступний у багатьох дистрибутивах Linux (а для інформації щодо встановлення на вашому дистрибутиві. Якщо ви готові та зацікавлені запакувати і підтримувати Sway у вашому -дистрибутиві, будемо раді вас бачити у нашому каналі IRC. Ви також можете -спитати порад за адресою sir@cmpwn.com. +дистрибутиві, звертайтесь за порадами до нашого каналу в IRC або +пишіть на електронну пошту [sir@cmpwn.com](mailto:sir@cmpwn.com). ### З вихідного коду Встановіть залежності: -* meson -* [wlc](https://github.com/Cloudef/wlc) +* meson \* +* [wlroots](https://github.com/swaywm/wlroots) * wayland -* xwayland -* libinput >= 1.6.0 -* libcap +* wayland-protocols \* * pcre -* json-c >= 0.13 +* json-c * pango * cairo -* gdk-pixbuf2 * -* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (required for man pages) -* git +* gdk-pixbuf2 \*\* +* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (необов'язково, необхідно для сторінок man) \* +* git \* -_\*Лише для swaybar, swaybg_ +_\*Лише для компіляції_ + +_\*\*Необов'язково, необхідно для swaybg_ Виконайте ці команди: @@ -68,15 +60,12 @@ _\*Лише для swaybar, swaybg_ ninja -C build sudo ninja -C build install -На системах **з** logind, варто встановити декілька можливостей (caps) -на виконуваний файл sway: - - sudo setcap "cap_sys_ptrace,cap_sys_tty_config=eip" /usr/local/bin/sway - -На системах **без** logind, необхідно встановити біт SUID на виконуваний файл sway: +На системах без logind, необхідно встановити біт SUID на виконуваний файл sway: sudo chmod a+s /usr/local/bin/sway +Sway втратить права доступу root незабаром після запуску. + ## Налаштування Якщо ви вже використовуєте i3, скопіюйте свій файл налаштувань From 3a31889d7cb00c28724bc093653b3015393c5cb4 Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Tue, 26 Mar 2019 20:32:50 -0700 Subject: [PATCH 10/21] Fix crash for floating command on scratchpad window --- sway/commands/floating.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sway/commands/floating.c b/sway/commands/floating.c index 821093695..5df9b1bfb 100644 --- a/sway/commands/floating.c +++ b/sway/commands/floating.c @@ -45,7 +45,10 @@ struct cmd_results *cmd_floating(int argc, char **argv) { container_set_floating(container, wants_floating); - arrange_workspace(container->workspace); + // Floating containers in the scratchpad should be ignored + if (container->workspace) { + arrange_workspace(container->workspace); + } return cmd_results_new(CMD_SUCCESS, NULL); } From bfdee1319ffc8a720d0536a752a19ba23615a1e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= Date: Tue, 26 Mar 2019 23:21:30 +0100 Subject: [PATCH 11/21] bindings: fix overwrite log argument mismatch Thanks, @RedSoxFan, for the review spotting another instance. --- sway/commands/bind.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sway/commands/bind.c b/sway/commands/bind.c index b3d391da6..9a937c611 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c @@ -316,7 +316,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, struct sway_binding *config_binding = mode_bindings->items[i]; if (binding_key_compare(binding, config_binding)) { sway_log(SWAY_INFO, "Overwriting binding '%s' for device '%s' " - "from `%s` to `%s`", argv[0], binding->input, + "to `%s` from `%s`", argv[0], binding->input, binding->command, config_binding->command); if (warn) { config_add_swaynag_warning("Overwriting binding" @@ -420,7 +420,7 @@ struct cmd_results *cmd_bindswitch(int argc, char **argv) { for (int i = 0; i < mode_bindings->length; ++i) { struct sway_switch_binding *config_binding = mode_bindings->items[i]; if (binding_switch_compare(binding, config_binding)) { - sway_log(SWAY_INFO, "Overwriting binding '%s' from `%s` to `%s`", + sway_log(SWAY_INFO, "Overwriting binding '%s' to `%s` from `%s`", argv[0], binding->command, config_binding->command); if (warn) { config_add_swaynag_warning("Overwriting binding" From 2cae0d5e3a9c5abc7c2aa2aad4021c86730b2ec9 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Fri, 29 Mar 2019 18:29:34 +1000 Subject: [PATCH 12/21] Fix null pointer crash when doing tiling drag * Create layout S[V[view view] view] * Drag bottom view to the top * Sway would crash when the cursor hovers the V[view view] title while dragging --- sway/input/seatop_move_tiling.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sway/input/seatop_move_tiling.c b/sway/input/seatop_move_tiling.c index 0a2480919..64a16c098 100644 --- a/sway/input/seatop_move_tiling.c +++ b/sway/input/seatop_move_tiling.c @@ -108,7 +108,7 @@ static void handle_motion_postthreshold(struct sway_seat *seat) { } if (node->type == N_WORKSPACE) { - // Emtpy workspace + // Empty workspace e->target_node = node; e->target_edge = WLR_EDGE_NONE; workspace_get_box(node->sway_workspace, &e->drop_box); @@ -164,7 +164,7 @@ static void handle_motion_postthreshold(struct sway_seat *seat) { // Use the hovered view - but we must be over the actual surface con = node->sway_container; - if (!con->view->surface || node == &e->con->node + if (!con->view || !con->view->surface || node == &e->con->node || node_has_ancestor(node, &e->con->node)) { e->target_node = NULL; e->target_edge = WLR_EDGE_NONE; From 31eeda11b0952e7520a5171c5b683ad6fba0f519 Mon Sep 17 00:00:00 2001 From: Alex Maese Date: Sat, 30 Mar 2019 13:01:38 -0500 Subject: [PATCH 13/21] Fix a crash in swaybar when an icon dir is not readable --- swaybar/tray/icon.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/swaybar/tray/icon.c b/swaybar/tray/icon.c index 8587f3f7b..56f230e14 100644 --- a/swaybar/tray/icon.c +++ b/swaybar/tray/icon.c @@ -348,6 +348,9 @@ void init_themes(list_t **themes, list_t **basedirs) { *themes = create_list(); for (int i = 0; i < (*basedirs)->length; ++i) { list_t *dir_themes = load_themes_in_dir((*basedirs)->items[i]); + if (dir_themes == NULL) { + continue; + } list_cat(*themes, dir_themes); list_free(dir_themes); } From dd28e6a6d6abf06d2d16e6c91aeaf942bf225af7 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Wed, 27 Mar 2019 14:00:19 -0400 Subject: [PATCH 14/21] Fix xwayland configure request scratchpad crash This fixes a crash in `container_init_floating` when a xwayland view sends a configure request while in the scratchpad. `container_init_floating` gets called so the configured minimum and maximum sizes gets respected when resizing to the requested size. Since the workspace was NULL, it would SIGSEGV when attempting to get the workspace's output for the output box retrieval. This extracts the resizing portion of `container_init_floating` into a separate function. If the container is in the scratchpad, it will just be resized and skip the centering. Additionally, `container_init_floating` has been renamed to `container_floating_resize_and_center` to more accurately describe what it does. --- include/sway/tree/container.h | 5 +---- sway/desktop/xwayland.c | 2 +- sway/tree/container.c | 41 +++++++++++++++++++++++------------ sway/tree/output.c | 2 +- sway/tree/root.c | 10 +-------- 5 files changed, 31 insertions(+), 29 deletions(-) diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index d25089949..964061db6 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -215,10 +215,7 @@ size_t container_titlebar_height(void); void floating_calculate_constraints(int *min_width, int *max_width, int *min_height, int *max_height); -/** - * Resize and center the container in its workspace. - */ -void container_init_floating(struct sway_container *container); +void container_floating_resize_and_center(struct sway_container *con); void container_set_floating(struct sway_container *container, bool enable); diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index f5ade8dcb..37d0b986a 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -435,7 +435,7 @@ static void handle_request_configure(struct wl_listener *listener, void *data) { // Respect minimum and maximum sizes view->natural_width = ev->width; view->natural_height = ev->height; - container_init_floating(view->container); + container_floating_resize_and_center(view->container); configure(view, view->container->content_x, view->container->content_y, diff --git a/sway/tree/container.c b/sway/tree/container.c index f84ce3602..b7ea2b7e2 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -649,8 +649,31 @@ void floating_calculate_constraints(int *min_width, int *max_width, } -void container_init_floating(struct sway_container *con) { +static void floating_natural_resize(struct sway_container *con) { + int min_width, max_width, min_height, max_height; + floating_calculate_constraints(&min_width, &max_width, + &min_height, &max_height); + if (!con->view) { + con->width = max_width; + con->height = max_height; + } else { + struct sway_view *view = con->view; + con->content_width = + fmax(min_width, fmin(view->natural_width, max_width)); + con->content_height = + fmax(min_height, fmin(view->natural_height, max_height)); + container_set_geometry_from_content(con); + } +} + +void container_floating_resize_and_center(struct sway_container *con) { struct sway_workspace *ws = con->workspace; + if (!ws) { + // On scratchpad, just resize + floating_natural_resize(con); + return; + } + struct wlr_box *ob = wlr_output_layout_get_box(root->output_layout, ws->output->wlr_output); if (!ob) { @@ -662,13 +685,8 @@ void container_init_floating(struct sway_container *con) { return; } - int min_width, max_width, min_height, max_height; - floating_calculate_constraints(&min_width, &max_width, - &min_height, &max_height); - + floating_natural_resize(con); if (!con->view) { - con->width = max_width; - con->height = max_height; if (con->width > ws->width || con->height > ws->height) { con->x = ob->x + (ob->width - con->width) / 2; con->y = ob->y + (ob->height - con->height) / 2; @@ -677,11 +695,6 @@ void container_init_floating(struct sway_container *con) { con->y = ws->y + (ws->height - con->height) / 2; } } else { - struct sway_view *view = con->view; - con->content_width = - fmax(min_width, fmin(view->natural_width, max_width)); - con->content_height = - fmax(min_height, fmin(view->natural_height, max_height)); if (con->content_width > ws->width || con->content_height > ws->height) { con->content_x = ob->x + (ob->width - con->content_width) / 2; @@ -711,7 +724,7 @@ void container_set_floating(struct sway_container *container, bool enable) { struct sway_container *old_parent = container->parent; container_detach(container); workspace_add_floating(workspace, container); - container_init_floating(container); + container_floating_resize_and_center(container); if (container->view) { view_set_tiled(container->view, false); if (container->view->using_csd) { @@ -995,7 +1008,7 @@ void container_fullscreen_disable(struct sway_container *con) { // criteria, it needs to be reinitialized as floating to get the proper // size and location if (container_is_floating(con) && (con->width == 0 || con->height == 0)) { - container_init_floating(con); + container_floating_resize_and_center(con); } con->fullscreen_mode = FULLSCREEN_NONE; diff --git a/sway/tree/output.c b/sway/tree/output.c index 283036524..b3589be5d 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -77,7 +77,7 @@ static void restore_workspaces(struct sway_output *output) { floater->y > output->ly + output->height || floater->x + floater->width < output->lx || floater->y + floater->height < output->ly) { - container_init_floating(floater); + container_floating_resize_and_center(floater); } } diff --git a/sway/tree/root.c b/sway/tree/root.c index 5dde9f22d..bc9c610df 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c @@ -124,15 +124,7 @@ void root_scratchpad_show(struct sway_container *con) { struct wlr_box workspace_box; workspace_get_box(new_ws, &workspace_box); if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) { - // Maybe resize it - if (con->width > new_ws->width || con->height > new_ws->height) { - container_init_floating(con); - } - - // Center it - double new_lx = new_ws->x + (new_ws->width - con->width) / 2; - double new_ly = new_ws->y + (new_ws->height - con->height) / 2; - container_floating_move_to(con, new_lx, new_ly); + container_floating_resize_and_center(con); } arrange_workspace(new_ws); From 0676ace97fdd0054af6b0a4950e219ebd0a18de4 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Fri, 29 Mar 2019 12:15:17 -0400 Subject: [PATCH 15/21] floating: fix size of non-view containers This fixes the sizing of floating non-view containers. On master, the floater will get set to the maximum width and height, which by default is the entire output layout. When setting a non-view container to floating, this will set a sane default size of 50% of the workspace width and 75% of the workspace height, or whatever the closest is that the minimum and maximum floating width/height values allow for. On all future calls to `floating_natural_resize`, the width and height will be kept unless they need to be changed to respect the min/max floating width/height values. --- sway/tree/container.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/sway/tree/container.c b/sway/tree/container.c index b7ea2b7e2..064d85f61 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -654,8 +654,8 @@ static void floating_natural_resize(struct sway_container *con) { floating_calculate_constraints(&min_width, &max_width, &min_height, &max_height); if (!con->view) { - con->width = max_width; - con->height = max_height; + con->width = fmax(min_width, fmin(con->width, max_width)); + con->height = fmax(min_height, fmin(con->height, max_height)); } else { struct sway_view *view = con->view; con->content_width = @@ -712,6 +712,22 @@ void container_floating_resize_and_center(struct sway_container *con) { } } +static void container_floating_set_default_size(struct sway_container *con) { + if (!sway_assert(con->workspace, "Expected a container on a workspace")) { + return; + } + int min_width, max_width, min_height, max_height; + floating_calculate_constraints(&min_width, &max_width, + &min_height, &max_height); + struct wlr_box *box = calloc(1, sizeof(struct wlr_box)); + workspace_get_box(con->workspace, box); + if (!con->view) { + con->width = fmax(min_width, fmin(box->width * 0.5, max_width)); + con->height = fmax(min_height, fmin(box->height * 0.75, max_height)); + } + free(box); +} + void container_set_floating(struct sway_container *container, bool enable) { if (container_is_floating(container) == enable) { return; @@ -724,6 +740,7 @@ void container_set_floating(struct sway_container *container, bool enable) { struct sway_container *old_parent = container->parent; container_detach(container); workspace_add_floating(workspace, container); + container_floating_set_default_size(container); container_floating_resize_and_center(container); if (container->view) { view_set_tiled(container->view, false); From 679c058fac986314675bacf7a7b01d263fb0db39 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Fri, 29 Mar 2019 12:26:08 -0400 Subject: [PATCH 16/21] scratchpad: set initial size This matches i3's behavior of setting scratchpad containers to 50% of the workspace's width and 75% of the workspace's height, bound by the minimum and maximum floating width/height. --- include/sway/tree/container.h | 2 ++ sway/tree/container.c | 15 ++++++++++++--- sway/tree/root.c | 2 ++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 964061db6..8448d7059 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -217,6 +217,8 @@ void floating_calculate_constraints(int *min_width, int *max_width, void container_floating_resize_and_center(struct sway_container *con); +void container_floating_set_default_size(struct sway_container *con); + void container_set_floating(struct sway_container *container, bool enable); void container_set_geometry_from_content(struct sway_container *con); diff --git a/sway/tree/container.c b/sway/tree/container.c index 064d85f61..02b4d1b0e 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -712,19 +712,28 @@ void container_floating_resize_and_center(struct sway_container *con) { } } -static void container_floating_set_default_size(struct sway_container *con) { +void container_floating_set_default_size(struct sway_container *con) { if (!sway_assert(con->workspace, "Expected a container on a workspace")) { return; } + int min_width, max_width, min_height, max_height; floating_calculate_constraints(&min_width, &max_width, &min_height, &max_height); struct wlr_box *box = calloc(1, sizeof(struct wlr_box)); workspace_get_box(con->workspace, box); + + double width = fmax(min_width, fmin(box->width * 0.5, max_width)); + double height = fmax(min_height, fmin(box->height * 0.75, max_height)); if (!con->view) { - con->width = fmax(min_width, fmin(box->width * 0.5, max_width)); - con->height = fmax(min_height, fmin(box->height * 0.75, max_height)); + con->width = width; + con->height = height; + } else { + con->content_width = width; + con->content_height = height; + container_set_geometry_from_content(con); } + free(box); } diff --git a/sway/tree/root.c b/sway/tree/root.c index bc9c610df..3d93405e4 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c @@ -62,6 +62,8 @@ void root_scratchpad_add_container(struct sway_container *con) { struct sway_container *parent = con->parent; struct sway_workspace *workspace = con->workspace; container_set_floating(con, true); + container_floating_set_default_size(con); + container_floating_move_to_center(con); container_detach(con); con->scratchpad = true; list_add(root->scratchpad, con); From a32125c984a41dbbfbe5a12b450a84d78e04867a Mon Sep 17 00:00:00 2001 From: Dacheng Gao <13791720+gaodacheng@users.noreply.github.com> Date: Wed, 27 Mar 2019 21:55:59 +0800 Subject: [PATCH 17/21] add chinese translation --- README.zh-CN.md | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 README.zh-CN.md diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 000000000..3e56f229b --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,68 @@ +# sway + +sway 是和 i3 兼容的 [Wayland](http://wayland.freedesktop.org/) compositor. +阅读 [FAQ](https://github.com/swaywm/sway/wiki). 加入 [IRC +频道](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on +irc.freenode.net). + +如果你想要支持 sway 的发展, 请到这 [SirCmpwn's +Patreon page](https://patreon.com/sircmpwn)贡献. + +## 发布签名 + +发布以 [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) 签名 +并发布在 [GitHub](https://github.com/swaywm/sway/releases). + +## 安装 + +### 从软件包中 + +Sway 在很多发行版中可用. 尝试在你的发行版中安装 "sway" 包. +如何这不可用, 请到 [此 wiki 页](https://github.com/swaywm/sway/wiki/Unsupported-packages) +检查针对你的发行版关于安装的信息. + +如果你有兴趣给你的发行版打包 sway, 停下来到 IRC 频道或者发邮件至 sir@cmpwn.com 获取建议. + +### 从源代码编译 + +安装依赖: + +* meson \* +* [wlroots](https://github.com/swaywm/wlroots) +* wayland +* wayland-protocols \* +* pcre +* json-c +* pango +* cairo +* gdk-pixbuf2 \*\* +* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (可选的: man pages) \* +* git \* + +_\*编译时依赖_ + +_\*\*可选的: swaybg 依赖_ + +运行这些命令: + + meson build + ninja -C build + sudo ninja -C build install + +在没有 logind 的系统上, 你需要给 sway 二进制设置 suid: + + sudo chmod a+s /usr/local/bin/sway + +Sway 将会在启动后尽快丢掉 root 权限. + +## 配置 + +如果你已经在使用 i3, 接下来复制你的 i3 配置到 `~/.config/sway/config` +它可以直接工作. 或者, 复制样本配置文件到 +`~/.config/sway/config`. 它通常位于 `/etc/sway/config`. +运行 `man 5 sway` 获取关于配置的信息. + +## 运行 + +从 TTY 中运行 `sway` . 某些显示管理器可能会工作但并不被 sway 支持 +(已知的 gdm 工作得非常好. From 3353bb58329aab882ff1d547448fa89d166d53d3 Mon Sep 17 00:00:00 2001 From: Dacheng Gao <13791720+gaodacheng@users.noreply.github.com> Date: Wed, 27 Mar 2019 21:58:41 +0800 Subject: [PATCH 18/21] fix cs --- README.zh-CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.zh-CN.md b/README.zh-CN.md index 3e56f229b..a443889da 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -65,4 +65,4 @@ Sway 将会在启动后尽快丢掉 root 权限. ## 运行 从 TTY 中运行 `sway` . 某些显示管理器可能会工作但并不被 sway 支持 -(已知的 gdm 工作得非常好. +(已知的 gdm 工作得非常好). From 078935ac8856a3c6ee5d0f61e2f9760520465520 Mon Sep 17 00:00:00 2001 From: Dacheng Gao <13791720+gaodacheng@users.noreply.github.com> Date: Wed, 27 Mar 2019 22:00:40 +0800 Subject: [PATCH 19/21] fix cs --- README.zh-CN.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.zh-CN.md b/README.zh-CN.md index a443889da..a60090f6a 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -5,12 +5,12 @@ sway 是和 i3 兼容的 [Wayland](http://wayland.freedesktop.org/) compositor. 频道](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on irc.freenode.net). -如果你想要支持 sway 的发展, 请到这 [SirCmpwn's +如果你想要支持 sway 的发展, 请到 [SirCmpwn's Patreon page](https://patreon.com/sircmpwn)贡献. ## 发布签名 -发布以 [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) 签名 +发布是以 [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) 签名 并发布在 [GitHub](https://github.com/swaywm/sway/releases). ## 安装 From 4938da2a341888dd5cd0ae3c9bf37ec417e05e25 Mon Sep 17 00:00:00 2001 From: Dacheng Gao <13791720+gaodacheng@users.noreply.github.com> Date: Wed, 27 Mar 2019 22:22:00 +0800 Subject: [PATCH 20/21] add link to README-zh-CN --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 99835d6e5..662025ef5 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [**English**](https://github.com/swaywm/sway/blob/master/README.md#sway--) - [日本語](https://github.com/swaywm/sway/blob/master/README.ja.md#sway--) - [Deutsch](https://github.com/swaywm/sway/blob/master/README.de.md#sway--) - [Ελληνικά](https://github.com/swaywm/sway/blob/master/README.el.md#sway--) - [Français](https://github.com/swaywm/sway/blob/master/README.fr.md#sway--) - [Українська](https://github.com/swaywm/sway/blob/master/README.uk.md#sway--) - [Italiano](https://github.com/swaywm/sway/blob/master/README.it.md#sway--) - [Português](https://github.com/swaywm/sway/blob/master/README.pt.md#sway--) - [Русский](https://github.com/swaywm/sway/blob/master/README.ru.md#sway--) - [Български](https://github.com/swaywm/sway/blob/master/README.bg.md#sway--) - [Español](https://github.com/swaywm/sway/blob/master/README.es.md#sway--) - -[Polski](https://github.com/swaywm/sway/blob/master/README.pl.md#sway--) +[Polski](https://github.com/swaywm/sway/blob/master/README.pl.md#sway--) - [**中文-简体**](https://github.com/swaywm/sway/blob/master/README-zh-CN.md#sway--) sway is an i3-compatible [Wayland](http://wayland.freedesktop.org/) compositor. Read the [FAQ](https://github.com/swaywm/sway/wiki). Join the [IRC From f3140506a886107c39da3ea5b17ccc3519b2ac26 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Mon, 1 Apr 2019 10:56:56 -0400 Subject: [PATCH 21/21] Update formatting of zh-cn link in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 662025ef5..d1d78799e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [**English**](https://github.com/swaywm/sway/blob/master/README.md#sway--) - [日本語](https://github.com/swaywm/sway/blob/master/README.ja.md#sway--) - [Deutsch](https://github.com/swaywm/sway/blob/master/README.de.md#sway--) - [Ελληνικά](https://github.com/swaywm/sway/blob/master/README.el.md#sway--) - [Français](https://github.com/swaywm/sway/blob/master/README.fr.md#sway--) - [Українська](https://github.com/swaywm/sway/blob/master/README.uk.md#sway--) - [Italiano](https://github.com/swaywm/sway/blob/master/README.it.md#sway--) - [Português](https://github.com/swaywm/sway/blob/master/README.pt.md#sway--) - [Русский](https://github.com/swaywm/sway/blob/master/README.ru.md#sway--) - [Български](https://github.com/swaywm/sway/blob/master/README.bg.md#sway--) - [Español](https://github.com/swaywm/sway/blob/master/README.es.md#sway--) - -[Polski](https://github.com/swaywm/sway/blob/master/README.pl.md#sway--) - [**中文-简体**](https://github.com/swaywm/sway/blob/master/README-zh-CN.md#sway--) +[Polski](https://github.com/swaywm/sway/blob/master/README.pl.md#sway--) - [中文-简体](https://github.com/swaywm/sway/blob/master/README-zh-CN.md#sway--) sway is an i3-compatible [Wayland](http://wayland.freedesktop.org/) compositor. Read the [FAQ](https://github.com/swaywm/sway/wiki). Join the [IRC