From bac9559665bc908e4f61a6405a6ce5109956f4a3 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Mon, 6 Jul 2020 17:18:47 -0400 Subject: [PATCH 01/33] ISSUE_TEMPLATE: Use the newer issue templates This utilizes the newer Github issue templates. They allow for the user to specify what type of issue they are submitting to allow for a more specific issue template to be shown. In addition to a hopefully easier to read/parse/follow bug report template, this also include templates for enhancements and i3 compatibility. This also includes a link to the IRC under the section title Questions. For the three templates, the labels bug, enhancement, and i3-compat will be automatically applied for the appropriate report to assist in triaging. Hopefully, this will result in less questions and issues for new window management functionality on Github and allow for better quality issues being submitted. At the very least, it allows us to outline our stances for bugs, enhancements, and i3-compatibility in an easier to read format. --- .github/ISSUE_TEMPLATE/bug_report.md | 33 ++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 5 +++ .github/ISSUE_TEMPLATE/enhancement.md | 13 ++++++++ .github/ISSUE_TEMPLATE/i3_compat.md | 20 +++++++++++ ISSUE_TEMPLATE.md | 48 --------------------------- 5 files changed, 71 insertions(+), 48 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/enhancement.md create mode 100644 .github/ISSUE_TEMPLATE/i3_compat.md delete mode 100644 ISSUE_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..4e4f6a778 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,33 @@ +--- +name: Bugs +about: Crashes and other bugs +labels: 'bug' + +--- + +### Please read the following before submitting: +- Please do NOT submit bug reports for questions. Ask questions on IRC at #sway on irc.freenode.net. +- Proprietary graphics drivers, including nvidia, are not supported. Please use the open source equivalents, such as nouveau, if you would like to use Sway. +- Problems with the Wayland version of Firefox are likely to be Firefox bugs. Start by submitting your issue to the Firefox Bugzilla and come back here only after they confirm otherwise. + +### Please fill out the following: +- **Sway Version:** + - `swaymsg -t get_version` or `sway -v` + +- **Debug Log:** + - Run `sway -d 2> ~/sway.log` from a TTY and upload it to a pastebin, such as gist.github.com. + - This will record information about sway's activity. Please try to keep the reproduction as brief as possible and exit sway. + +- **Configuration File:** + - Please try to produce with the default configuration. + - If you cannot reproduce with the default configuration, please try to find the minimal configuration to reproduce. + - Upload the config to a pastebin such as gist.github.com. + +- **Stack Trace:** + - This is only needed if sway crashes. + - If you use systemd, you should be able to open the coredump of the most recent crash with gdb with + `coredumpctl gdb sway` and then `bt full` to obtain the stack trace. + - If the lines mentioning sway or wlroots have `??` for the location, your binaries were built without debug symbols. Please compile both sway and wlroots from source and try to reproduce. + +- **Description:** + - The steps you took in plain English to reproduce the problem. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..f09cdf5bb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Questions + url: "http://webchat.freenode.net/?channels=sway&uio=d4" + about: "Please ask questions on IRC in #sway on irc.freenode.net" diff --git a/.github/ISSUE_TEMPLATE/enhancement.md b/.github/ISSUE_TEMPLATE/enhancement.md new file mode 100644 index 000000000..3ed45b01d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/enhancement.md @@ -0,0 +1,13 @@ +--- +name: Enhancements +about: New functionality +labels: 'enhancement' + +--- + +### Please read the following before submitting: +- We are not accepting any new window management features unless they get implemented by i3. Please consider searching for or opening an i3 feature request. + +### Please fill out the following: +- **Description:** +Please describe in plain English what the enhancement is and what the use case is. diff --git a/.github/ISSUE_TEMPLATE/i3_compat.md b/.github/ISSUE_TEMPLATE/i3_compat.md new file mode 100644 index 000000000..4dfa21c3c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/i3_compat.md @@ -0,0 +1,20 @@ +--- +name: i3 Compatibility +about: Sway behaves differently from or lacks i3 functionality +labels: 'i3-compat' + +--- + +### Please read the following before submitting: +- The following either do not make sense for Wayland or we have decided against supporting: + - `restart` + - `resource` + - saving and loading layouts + - the i3 sync protocol + +### Please fill out the following: +- **i3 PR:** + - If this is new i3 functionality, please add a link to the i3 pull request. + +- **Description:** + - Please describe in plain English how Sway and i3's behaviors differ or what functionality Sway is lacking. diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md deleted file mode 100644 index 4b715aeb6..000000000 --- a/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,48 +0,0 @@ -If you want to ask a question, please check out the wiki. If you don't find an answer there, ask on IRC (#sway on irc.freenode.net). The issue tracker may not be used for questions. - -If you are using the Nvidia proprietary driver for any reason, you have two choices: - -1. Uninstall it and use nouveau instead -2. Use X11+i3 and close your browser tab - -If `lsmod | grep nvidia | wc -l` shows anything other than zero, your bug report is not welcome here. - -Additionally, problems with Firefox are almost certainly Firefox bugs, not sway bugs. Start by submitting your issue to the Firefox Bugzilla and come back here only after they confirm otherwise. - -Otherwise, please include the following four components in your bug report: sway version, debug log, configuration (if applicable), and an explanation of steps taken to reproduce the issue. If sway crashes, also include a stack trace. - -Obtain your version like so: - - swaymsg -t get_version - -If this doesn't work, use: - - sway -v - -* Sway Version: - -Obtain a debug log by running the following command from a TTY: - - sway -d 2> ~/sway.log - -This will record information about sway's activity when it's running. Briefly reproduce your problem and exit sway. When preparing a debug log, brevity is important - start up sway, do the minimum work necessary to reproduce the error, then close sway. - -Upload the debug log to a pastebin service such as [gist.github.com](https://gist.github.com), and link to it below. - -* Debug Log: - -You should try to reproduce the issue with the default configuration. If you cannot, please reproduce with a minimal configuration, upload the config to a pastebin service, and link to it below. - -* Configuration File: - -Finally, explain the steps you took in plain English to reproduce the problem below. - -* Stack Trace, if sway crashes: - -If you use systemd, you should be able to open the coredump of the most recent crash with GDB like so: - - coredumpctl gdb sway - -And then type `bt full` to obtain the stack trace. - -If the lines mentioning sway/wlroots have "??" for the location, your binaries were built without debug symbols, and the stack trace is unlikely to be useful. You can find instructions to compile sway from source [here](https://github.com/swaywm/sway/wiki/Development-Setup#compiling-as-a-subproject). Note that debug symbols are included in Meson builds by default. From e5954f321f76c9337efaf9c5f66140bfba2bae77 Mon Sep 17 00:00:00 2001 From: Nick Diego Yamane Date: Mon, 6 Jul 2020 17:17:04 -0400 Subject: [PATCH 02/33] seat/dnd: support null drag icon surfaces As per the Wayland spec [1]: > The icon surface is an optional (can be NULL) surface that provides an > icon to be moved around with the cursor. However, as of now Sway "start_drag" signal handler does not starts the DND session unless a non-NULL drag icons is provided. This patch fixes it by skipping handling of the drag icon if it is null. Fixes #5509 [1] https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_data_device Signed-off-by: Nick Diego Yamane --- sway/input/seat.c | 46 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/sway/input/seat.c b/sway/input/seat.c index 656e3e7e8..bcf01962f 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -470,31 +470,29 @@ static void handle_start_drag(struct wl_listener *listener, void *data) { wl_signal_add(&wlr_drag->events.destroy, &drag->destroy); struct wlr_drag_icon *wlr_drag_icon = wlr_drag->icon; - if (wlr_drag_icon == NULL) { - return; + if (wlr_drag_icon != NULL) { + struct sway_drag_icon *icon = calloc(1, sizeof(struct sway_drag_icon)); + if (icon == NULL) { + sway_log(SWAY_ERROR, "Allocation failed"); + return; + } + icon->seat = seat; + icon->wlr_drag_icon = wlr_drag_icon; + wlr_drag_icon->data = icon; + + icon->surface_commit.notify = drag_icon_handle_surface_commit; + wl_signal_add(&wlr_drag_icon->surface->events.commit, &icon->surface_commit); + icon->unmap.notify = drag_icon_handle_unmap; + wl_signal_add(&wlr_drag_icon->events.unmap, &icon->unmap); + icon->map.notify = drag_icon_handle_map; + wl_signal_add(&wlr_drag_icon->events.map, &icon->map); + icon->destroy.notify = drag_icon_handle_destroy; + wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy); + + wl_list_insert(&root->drag_icons, &icon->link); + + drag_icon_update_position(icon); } - - struct sway_drag_icon *icon = calloc(1, sizeof(struct sway_drag_icon)); - if (icon == NULL) { - sway_log(SWAY_ERROR, "Allocation failed"); - return; - } - icon->seat = seat; - icon->wlr_drag_icon = wlr_drag_icon; - wlr_drag_icon->data = icon; - - icon->surface_commit.notify = drag_icon_handle_surface_commit; - wl_signal_add(&wlr_drag_icon->surface->events.commit, &icon->surface_commit); - icon->unmap.notify = drag_icon_handle_unmap; - wl_signal_add(&wlr_drag_icon->events.unmap, &icon->unmap); - icon->map.notify = drag_icon_handle_map; - wl_signal_add(&wlr_drag_icon->events.map, &icon->map); - icon->destroy.notify = drag_icon_handle_destroy; - wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy); - - wl_list_insert(&root->drag_icons, &icon->link); - - drag_icon_update_position(icon); seatop_begin_default(seat); } From ea3ba203cc65671d9bf9da5ddbc698b18ed7685c Mon Sep 17 00:00:00 2001 From: Geoffrey Casper Date: Sat, 4 Jul 2020 12:28:19 -0400 Subject: [PATCH 03/33] Reload command now matches i3's implementation --- include/sway/config.h | 1 + sway/commands/reload.c | 14 ++++++++++++-- sway/config.c | 1 + sway/sway.5.scd | 4 +++- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index b3fd66681..5ad240d34 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -500,6 +500,7 @@ struct sway_config { struct side_gaps gaps_outer; list_t *config_chain; + bool user_config_path; const char *current_config_path; const char *current_config; int current_config_line_number; diff --git a/sway/commands/reload.c b/sway/commands/reload.c index 19ec065cd..3c994d54f 100644 --- a/sway/commands/reload.c +++ b/sway/commands/reload.c @@ -22,7 +22,12 @@ static void do_reload(void *data) { list_add(bar_ids, strdup(bar->id)); } - if (!load_main_config(config->current_config_path, true, false)) { + const char *path = NULL; + if (config->user_config_path) { + path = config->current_config_path; + } + + if (!load_main_config(path, true, false)) { sway_log(SWAY_ERROR, "Error(s) reloading config"); list_free_items_and_destroy(bar_ids); return; @@ -55,7 +60,12 @@ struct cmd_results *cmd_reload(int argc, char **argv) { return error; } - if (!load_main_config(config->current_config_path, true, true)) { + const char *path = NULL; + if (config->user_config_path) { + path = config->current_config_path; + } + + if (!load_main_config(path, true, true)) { return cmd_results_new(CMD_FAILURE, "Error(s) reloading config."); } diff --git a/sway/config.c b/sway/config.c index bcf8d56fc..71382b864 100644 --- a/sway/config.c +++ b/sway/config.c @@ -447,6 +447,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) { } } + config->user_config_path = file ? true : false; config->current_config_path = path; list_add(config->config_chain, real_path); diff --git a/sway/sway.5.scd b/sway/sway.5.scd index f4323f65e..fed4c3c77 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -272,7 +272,9 @@ set|plus|minus optional comment argument is ignored, but logged for debugging purposes. *reload* - Reloads the sway config file and applies any changes. + Reloads the sway config file and applies any changes. The config file is + located at path specified by the command line arguments when started, + otherwise according to the priority stated in *sway*(1). *rename workspace* [] to Rename either or the focused workspace to the From 5432f00adfdd8375fb422ad9033253d17f04efc7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 10 Jul 2020 18:04:45 +0200 Subject: [PATCH 04/33] config/output: don't change output state before commit Previously, we called output_disable prior to wlr_output_commit. This mutates Sway's output state before the output commit actually succeeds. This results in Sway's state getting out-of-sync with wlroots'. An alternative fix [1] was to revert the changes made by output_disable in case of failure. This is a little complicated. Instead, this patch makes it so Sway's internal state is never changed before a successful wlr_output commit. We had two output flags: enabled and configured. However enabled was set prior to the output becoming enabled, and was used to prevent the output event handlers (specifically, the mode handler) from calling apply_output_config again (infinite loop). Rename enabled to enabling and use it exclusively for this purpose. Rename configure to enabled, because that's what it really means. [1]: https://github.com/swaywm/sway/pull/5521 Closes: https://github.com/swaywm/sway/issues/5483 --- include/sway/output.h | 4 ++-- sway/config/output.c | 26 ++++++++++++-------------- sway/desktop/output.c | 8 ++++---- sway/input/cursor.c | 4 ++-- sway/tree/output.c | 7 +++---- 5 files changed, 23 insertions(+), 26 deletions(-) diff --git a/include/sway/output.h b/include/sway/output.h index cabb4b557..f27f6344a 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -36,7 +36,7 @@ struct sway_output { // last applied mode when the output is DPMS'ed struct wlr_output_mode *current_mode; - bool enabled, configured; + bool enabling, enabled; list_t *workspaces; struct sway_output_state current; @@ -98,7 +98,7 @@ struct sway_output *all_output_by_name_or_id(const char *name_or_id); void output_sort_workspaces(struct sway_output *output); -void output_configure(struct sway_output *output); +void output_enable(struct sway_output *output); void output_disable(struct sway_output *output); diff --git a/sway/config/output.c b/sway/config/output.c index 68aafbe1c..b59cabd4e 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -397,17 +397,8 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { struct wlr_output *wlr_output = output->wlr_output; - bool was_enabled = output->enabled; - if (oc && !oc->enabled) { - // Output is configured to be disabled - sway_log(SWAY_DEBUG, "Disabling output %s", oc->name); - if (output->enabled) { - output_disable(output); - wlr_output_layout_remove(root->output_layout, wlr_output); - } - } else { - output->enabled = true; - } + // Flag to prevent the output mode event handler from calling us + output->enabling = (!oc || oc->enabled); queue_output_config(oc, output); @@ -421,11 +412,18 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { // Leave the output disabled for now and try again when the output gets // the mode we asked for. sway_log(SWAY_ERROR, "Failed to commit output %s", wlr_output->name); - output->enabled = was_enabled; + output->enabling = false; return false; } + output->enabling = false; + if (oc && !oc->enabled) { + sway_log(SWAY_DEBUG, "Disabling output %s", oc->name); + if (output->enabled) { + output_disable(output); + wlr_output_layout_remove(root->output_layout, wlr_output); + } return true; } @@ -468,8 +466,8 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { output->width = output_box->width; output->height = output_box->height; - if (!output->configured) { - output_configure(output); + if (!output->enabled) { + output_enable(output); } if (oc && oc->max_render_time >= 0) { diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 4a51b5cc7..5fdaba680 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -844,7 +844,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { static void handle_mode(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, mode); - if (!output->configured && !output->enabled) { + if (!output->enabled && !output->enabling) { struct output_config *oc = find_output_config(output); if (output->wlr_output->current_mode != NULL && (!oc || oc->enabled)) { @@ -857,7 +857,7 @@ static void handle_mode(struct wl_listener *listener, void *data) { } return; } - if (!output->enabled || !output->configured) { + if (!output->enabled) { return; } arrange_layers(output); @@ -869,7 +869,7 @@ static void handle_mode(struct wl_listener *listener, void *data) { static void handle_transform(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, transform); - if (!output->enabled || !output->configured) { + if (!output->enabled) { return; } arrange_layers(output); @@ -886,7 +886,7 @@ static void update_textures(struct sway_container *con, void *data) { static void handle_scale(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, scale); - if (!output->enabled || !output->configured) { + if (!output->enabled) { return; } arrange_layers(output); diff --git a/sway/input/cursor.c b/sway/input/cursor.c index d10ba444b..0d5b076b0 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -99,8 +99,8 @@ struct sway_node *node_at_coords( return NULL; } struct sway_output *output = wlr_output->data; - if (!output || !output->configured) { - // output is being destroyed or is being configured + if (!output || !output->enabled) { + // output is being destroyed or is being enabled return NULL; } double ox = lx, oy = ly; diff --git a/sway/tree/output.c b/sway/tree/output.c index 9a10c6a89..ae3c3abfc 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -110,12 +110,12 @@ struct sway_output *output_create(struct wlr_output *wlr_output) { return output; } -void output_configure(struct sway_output *output) { - if (!sway_assert(!output->configured, "output is already configured")) { +void output_enable(struct sway_output *output) { + if (!sway_assert(!output->enabled, "output is already enabled")) { return; } struct wlr_output *wlr_output = output->wlr_output; - output->configured = true; + output->enabled = true; list_add(root->outputs, output); restore_workspaces(output); @@ -262,7 +262,6 @@ void output_disable(struct sway_output *output) { list_del(root->outputs, index); output->enabled = false; - output->configured = false; output->current_mode = NULL; arrange_root(); From 585236f1687930d36e1d47d69e0a45fe3dcbd0cf Mon Sep 17 00:00:00 2001 From: Wai Hon Law Date: Sat, 11 Jul 2020 16:52:41 -0700 Subject: [PATCH 05/33] Make the default workspace commands compatible with i3 **Problem** When I rename the workspace to something like "1:web", `$mod+1` does not move to the "1:web" with the default config. This breaks the expectation of i3 users. **Cause** The default Sway binding for `$mod+1` does not have the number keyword: ``` bindsym $mod+1 workspace 1 ``` Instead, the default Sway binding for `$mod+1` is ``` bindsym Mod1+1 workspace number $ws1 ``` https://github.com/i3/i3/commit/e6662df114329ba45bd1d117c731b3dc8bdd13fb is the corresponding commit from i3. --- config.in | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/config.in b/config.in index 67c748ba3..559431693 100644 --- a/config.in +++ b/config.in @@ -112,27 +112,27 @@ output * bg @datadir@/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill # Workspaces: # # Switch to workspace - bindsym $mod+1 workspace 1 - bindsym $mod+2 workspace 2 - bindsym $mod+3 workspace 3 - bindsym $mod+4 workspace 4 - bindsym $mod+5 workspace 5 - bindsym $mod+6 workspace 6 - bindsym $mod+7 workspace 7 - bindsym $mod+8 workspace 8 - bindsym $mod+9 workspace 9 - bindsym $mod+0 workspace 10 + bindsym $mod+1 workspace number 1 + bindsym $mod+2 workspace number 2 + bindsym $mod+3 workspace number 3 + bindsym $mod+4 workspace number 4 + bindsym $mod+5 workspace number 5 + bindsym $mod+6 workspace number 6 + bindsym $mod+7 workspace number 7 + bindsym $mod+8 workspace number 8 + bindsym $mod+9 workspace number 9 + bindsym $mod+0 workspace number 10 # Move focused container to workspace - bindsym $mod+Shift+1 move container to workspace 1 - bindsym $mod+Shift+2 move container to workspace 2 - bindsym $mod+Shift+3 move container to workspace 3 - bindsym $mod+Shift+4 move container to workspace 4 - bindsym $mod+Shift+5 move container to workspace 5 - bindsym $mod+Shift+6 move container to workspace 6 - bindsym $mod+Shift+7 move container to workspace 7 - bindsym $mod+Shift+8 move container to workspace 8 - bindsym $mod+Shift+9 move container to workspace 9 - bindsym $mod+Shift+0 move container to workspace 10 + bindsym $mod+Shift+1 move container to workspace number 1 + bindsym $mod+Shift+2 move container to workspace number 2 + bindsym $mod+Shift+3 move container to workspace number 3 + bindsym $mod+Shift+4 move container to workspace number 4 + bindsym $mod+Shift+5 move container to workspace number 5 + bindsym $mod+Shift+6 move container to workspace number 6 + bindsym $mod+Shift+7 move container to workspace number 7 + bindsym $mod+Shift+8 move container to workspace number 8 + bindsym $mod+Shift+9 move container to workspace number 9 + bindsym $mod+Shift+0 move container to workspace number 10 # Note: workspaces can have any name you want, not just numbers. # We just use 1-10 as the default. # From 10ec97c073ea7c06f7c129a4baa4576783248148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Gro=C3=9Fe=20Sundrup?= Date: Sun, 12 Jul 2020 13:57:30 +0200 Subject: [PATCH 06/33] rephrase swayidle-timout example to improve readability --- config.in | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config.in b/config.in index 559431693..08703bef2 100644 --- a/config.in +++ b/config.in @@ -37,8 +37,7 @@ output * bg @datadir@/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill # # exec swayidle -w \ # timeout 300 'swaylock -f -c 000000' \ -# timeout 600 'swaymsg "output * dpms off"' \ -# resume 'swaymsg "output * dpms on"' \ +# timeout 600 'swaymsg "output * dpms off"' resume 'swaymsg "output * dpms on"' \ # before-sleep 'swaylock -f -c 000000' # # This will lock your screen after 300 seconds of inactivity, then turn off From 39d677af15bd4c8cdea6b62fda80ac9a9e998045 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Mon, 6 Jul 2020 23:57:48 -0700 Subject: [PATCH 07/33] input: implement xdg_toplevel interactive resize hints --- include/sway/tree/container.h | 2 ++ include/sway/tree/view.h | 1 + sway/desktop/xdg_shell.c | 9 ++++++ sway/input/seatop_resize_floating.c | 6 ++++ sway/input/seatop_resize_tiling.c | 50 +++++++++++++++++++++++++++++ sway/tree/container.c | 22 +++++++++++++ 6 files changed, 90 insertions(+) diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index fd028131c..136d618b2 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -219,6 +219,8 @@ void container_floating_resize_and_center(struct sway_container *con); void container_floating_set_default_size(struct sway_container *con); +void container_set_resizing(struct sway_container *con, bool resizing); + void container_set_floating(struct sway_container *container, bool enable); void container_set_geometry_from_content(struct sway_container *con); diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index b495fdf93..665c516f9 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -43,6 +43,7 @@ struct sway_view_impl { void (*set_activated)(struct sway_view *view, bool activated); void (*set_tiled)(struct sway_view *view, bool tiled); void (*set_fullscreen)(struct sway_view *view, bool fullscreen); + void (*set_resizing)(struct sway_view *view, bool resizing); bool (*wants_floating)(struct sway_view *view); void (*for_each_surface)(struct sway_view *view, wlr_surface_iterator_func_t iterator, void *user_data); diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index df751ef6f..3437cc073 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -185,6 +185,14 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) { wlr_xdg_toplevel_set_fullscreen(surface, fullscreen); } +static void set_resizing(struct sway_view *view, bool resizing) { + if (xdg_shell_view_from_view(view) == NULL) { + return; + } + struct wlr_xdg_surface *surface = view->wlr_xdg_surface; + wlr_xdg_toplevel_set_resizing(surface, resizing); +} + static bool wants_floating(struct sway_view *view) { struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_surface->toplevel; struct wlr_xdg_toplevel_state *state = &toplevel->current; @@ -260,6 +268,7 @@ static const struct sway_view_impl view_impl = { .set_activated = set_activated, .set_tiled = set_tiled, .set_fullscreen = set_fullscreen, + .set_resizing = set_resizing, .wants_floating = wants_floating, .for_each_surface = for_each_surface, .for_each_popup = for_each_popup, diff --git a/sway/input/seatop_resize_floating.c b/sway/input/seatop_resize_floating.c index ec10cfc8d..10af06fed 100644 --- a/sway/input/seatop_resize_floating.c +++ b/sway/input/seatop_resize_floating.c @@ -21,7 +21,12 @@ struct seatop_resize_floating_event { static void handle_button(struct sway_seat *seat, uint32_t time_msec, struct wlr_input_device *device, uint32_t button, enum wlr_button_state state) { + struct seatop_resize_floating_event *e = seat->seatop_data; + struct sway_container *con = e->con; + if (seat->cursor->pressed_button_count == 0) { + container_set_resizing(con, false); + arrange_container(con); // Send configure w/o resizing hint seatop_begin_default(seat); } } @@ -170,6 +175,7 @@ void seatop_begin_resize_floating(struct sway_seat *seat, seat->seatop_impl = &seatop_impl; seat->seatop_data = e; + container_set_resizing(con, true); container_raise_floating(con); const char *image = edge == WLR_EDGE_NONE ? diff --git a/sway/input/seatop_resize_tiling.c b/sway/input/seatop_resize_tiling.c index f6f106ef2..0dfafbd07 100644 --- a/sway/input/seatop_resize_tiling.c +++ b/sway/input/seatop_resize_tiling.c @@ -4,6 +4,9 @@ #include "sway/commands.h" #include "sway/input/cursor.h" #include "sway/input/seat.h" +#include "sway/tree/arrange.h" +#include "sway/tree/container.h" +#include "sway/tree/view.h" struct seatop_resize_tiling_event { struct sway_container *con; // leaf container @@ -12,6 +15,10 @@ struct seatop_resize_tiling_event { struct sway_container *h_con; struct sway_container *v_con; + // sibling con(s) that will be resized to accommodate + struct sway_container *h_sib; + struct sway_container *v_sib; + enum wlr_edges edge; enum wlr_edges edge_x, edge_y; double ref_lx, ref_ly; // cursor's x/y at start of op @@ -19,10 +26,47 @@ struct seatop_resize_tiling_event { double v_con_orig_height; // height of the vertical ancestor at start }; +static struct sway_container *container_get_resize_sibling( + struct sway_container *con, uint32_t edge) { + if (!con) { + return NULL; + } + + list_t *siblings = container_get_siblings(con); + int index = container_sibling_index(con); + int offset = edge & (WLR_EDGE_TOP | WLR_EDGE_LEFT) ? -1 : 1; + + if (siblings->length == 1) { + return NULL; + } else { + return siblings->items[index + offset]; + } +} + static void handle_button(struct sway_seat *seat, uint32_t time_msec, struct wlr_input_device *device, uint32_t button, enum wlr_button_state state) { + struct seatop_resize_tiling_event *e = seat->seatop_data; + if (seat->cursor->pressed_button_count == 0) { + if (e->h_con) { + container_set_resizing(e->h_con, false); + container_set_resizing(e->h_sib, false); + if (e->h_con->parent) { + arrange_container(e->h_con->parent); + } else { + arrange_workspace(e->h_con->workspace); + } + } + if (e->v_con) { + container_set_resizing(e->v_con, false); + container_set_resizing(e->v_sib, false); + if (e->v_con->parent) { + arrange_container(e->v_con->parent); + } else { + arrange_workspace(e->v_con->workspace); + } + } seatop_begin_default(seat); } } @@ -89,16 +133,22 @@ void seatop_begin_resize_tiling(struct sway_seat *seat, if (edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) { e->edge_x = edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT); e->h_con = container_find_resize_parent(e->con, e->edge_x); + e->h_sib = container_get_resize_sibling(e->h_con, e->edge_x); if (e->h_con) { + container_set_resizing(e->h_con, true); + container_set_resizing(e->h_sib, true); e->h_con_orig_width = e->h_con->width; } } if (edge & (WLR_EDGE_TOP | WLR_EDGE_BOTTOM)) { e->edge_y = edge & (WLR_EDGE_TOP | WLR_EDGE_BOTTOM); e->v_con = container_find_resize_parent(e->con, e->edge_y); + e->v_sib = container_get_resize_sibling(e->v_con, e->edge_y); if (e->v_con) { + container_set_resizing(e->v_con, true); + container_set_resizing(e->v_sib, true); e->v_con_orig_height = e->v_con->height; } } diff --git a/sway/tree/container.c b/sway/tree/container.c index fa1598ef9..65696f15e 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -746,6 +746,28 @@ void container_floating_set_default_size(struct sway_container *con) { free(box); } + +/** + * Indicate to clients in this container that they are participating in (or + * have just finished) an interactive resize + */ +void container_set_resizing(struct sway_container *con, bool resizing) { + if (!con) { + return; + } + + if (con->view) { + if (con->view->impl->set_resizing) { + con->view->impl->set_resizing(con->view, resizing); + } + } else { + for (int i = 0; i < con->children->length; ++i ) { + struct sway_container *child = con->children->items[i]; + container_set_resizing(child, resizing); + } + } +} + void container_set_floating(struct sway_container *container, bool enable) { if (container_is_floating(container) == enable) { return; From 9bb70283e967037e6d57bc863ef96d3b5185a989 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 12 Jul 2020 16:50:11 +0200 Subject: [PATCH 08/33] Assert output is found before removing from list References: https://github.com/swaywm/sway/issues/5483 --- sway/tree/output.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sway/tree/output.c b/sway/tree/output.c index ae3c3abfc..d600c5c31 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -251,6 +251,11 @@ void output_disable(struct sway_output *output) { if (!sway_assert(output->enabled, "Expected an enabled output")) { return; } + int index = list_find(root->outputs, output); + if (!sway_assert(index >= 0, "Output not found in root node")) { + return; + } + sway_log(SWAY_DEBUG, "Disabling output '%s'", output->wlr_output->name); wl_signal_emit(&output->events.destroy, output); @@ -258,7 +263,6 @@ void output_disable(struct sway_output *output) { root_for_each_container(untrack_output, output); - int index = list_find(root->outputs, output); list_del(root->outputs, index); output->enabled = false; From 4dd46f06acc520449b980a5ea52be544cc5bfb6d Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Sun, 12 Jul 2020 19:53:16 -0700 Subject: [PATCH 09/33] xdg_shell: schedule configure on maximize requests --- sway/desktop/xdg_shell.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 3437cc073..03f372416 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -369,6 +369,11 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) transaction_commit_dirty(); } +static void handle_request_maximize(struct wl_listener *listener, void *data) { + struct wlr_xdg_surface *surface = data; + wlr_xdg_surface_schedule_configure(surface); +} + static void handle_request_move(struct wl_listener *listener, void *data) { struct sway_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, request_move); @@ -411,6 +416,7 @@ static void handle_unmap(struct wl_listener *listener, void *data) { wl_list_remove(&xdg_shell_view->commit.link); wl_list_remove(&xdg_shell_view->new_popup.link); wl_list_remove(&xdg_shell_view->request_fullscreen.link); + wl_list_remove(&xdg_shell_view->request_maximize.link); wl_list_remove(&xdg_shell_view->request_move.link); wl_list_remove(&xdg_shell_view->request_resize.link); wl_list_remove(&xdg_shell_view->set_title.link); @@ -459,6 +465,10 @@ static void handle_map(struct wl_listener *listener, void *data) { wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, &xdg_shell_view->request_fullscreen); + xdg_shell_view->request_maximize.notify = handle_request_maximize; + wl_signal_add(&xdg_surface->toplevel->events.request_maximize, + &xdg_shell_view->request_maximize); + xdg_shell_view->request_move.notify = handle_request_move; wl_signal_add(&xdg_surface->toplevel->events.request_move, &xdg_shell_view->request_move); From acbe9028157c67eb3937299ff86e5ee26816a408 Mon Sep 17 00:00:00 2001 From: Campbell Vertesi Date: Mon, 13 Jul 2020 16:47:20 +0200 Subject: [PATCH 10/33] Add note on quoting to swaymsg manpage --- swaymsg/swaymsg.1.scd | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/swaymsg/swaymsg.1.scd b/swaymsg/swaymsg.1.scd index b8a38b544..4228a0f00 100644 --- a/swaymsg/swaymsg.1.scd +++ b/swaymsg/swaymsg.1.scd @@ -44,12 +44,18 @@ _swaymsg_ [options...] [message] The message is a sway command (the same commands you can bind to keybindings in your sway config file). It will be executed immediately. - See **sway**(5) for a list of commands. + See *sway*(5) for a list of commands. - Tip: If you are proving a command that contains a leading hyphen (_-_), - insert two hyphens (_--_) before the command to signal to swaymsg not to - parse anything beyond that point as an option. For example, use - _swaymsg -- mark --add test_ instead of _swaymsg mark --add test_ + Tips: + - Command expansion is performed twice: once by swaymsg, and again by sway. + If you have quoted multi-word strings in your command, enclose the entire + command in single-quotes. For example, use + _swaymsg 'output "Foobar Display" enable'_ instead of + _swaymsg output "Foobar Display" enable_. + - If you are proving a command that contains a leading hyphen (_-_), insert + two hyphens (_--_) before the command to signal to swaymsg not to parse + anything beyond that point as an option. For example, use + _swaymsg -- mark --add test_ instead of _swaymsg mark --add test_. *get\_workspaces* Gets a JSON-encoded list of workspaces and their status. From c65cd1cffa5a791202ee913afef40dffdc54e5bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vinko=20Ka=C5=A1ljevi=C4=87?= Date: Wed, 15 Jul 2020 18:31:09 +0200 Subject: [PATCH 11/33] Add check for empty GEOM variable In case when slurp is used to select part of screen or a window, if user aborts the selection, grimshot will capture the whole screen instead of exiting. This is fixed with check for empty variable. --- contrib/grimshot | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/contrib/grimshot b/contrib/grimshot index 4ee8d902c..461a5eeff 100755 --- a/contrib/grimshot +++ b/contrib/grimshot @@ -111,6 +111,10 @@ if [ "$ACTION" = "check" ] ; then exit elif [ "$SUBJECT" = "area" ] ; then GEOM=$(slurp -d) + # Check if user exited slurp without selecting the area + if [ -z "$GEOM" ]; then + exit + fi WHAT="Area" elif [ "$SUBJECT" = "active" ] ; then FOCUSED=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]?, .floating_nodes[]?) | select(.focused)') @@ -126,6 +130,10 @@ elif [ "$SUBJECT" = "output" ] ; then WHAT="$OUTPUT" elif [ "$SUBJECT" = "window" ] ; then GEOM=$(swaymsg -t get_tree | jq -r '.. | select(.pid? and .visible?) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' | slurp) + # Check if user exited slurp without selecting the area + if [ -z "$GEOM" ]; then + exit + fi WHAT="Window" else die "Unknown subject to take a screen shot from" "$SUBJECT" From 2f3afef95c3eb692a081660e40583e7521c1d7c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Defferrard?= Date: Thu, 4 Jun 2020 15:27:49 +0200 Subject: [PATCH 12/33] readme: link to the development doc The subproject compilation is the best way to test sway and wlroots but it's hidden. I only found it from comments in issues. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index aa11f60df..336403a63 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ channel or shoot an email to sir@cmpwn.com for advice. ### Compiling from Source +Check out [this wiki page](https://github.com/swaywm/sway/wiki/Development-Setup) if you want to build the HEAD of sway and wlroots for testing or development. + Install dependencies: * meson \* From 6b9a9b62462c0fae7b09294700112c569a3ccc19 Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Sun, 7 Jun 2020 16:43:53 -0400 Subject: [PATCH 13/33] input/cursor: don't send wl_pointer.motion event on pointer unlock warp On warping to a cursor hint, update the pointer position we track as well, so that on the next pointer rebase we don't send an unexpected synthetic motion event to clients. Fixes #5405. --- sway/input/cursor.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 0d5b076b0..e43a0e719 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -1244,6 +1244,10 @@ static void warp_to_constraint_cursor_hint(struct sway_cursor *cursor) { double ly = sy + con->content_y - view->geometry.y; wlr_cursor_warp(cursor->cursor, NULL, lx, ly); + + // Warp the pointer as well, so that on the next pointer rebase we don't + // send an unexpected synthetic motion event to clients. + wlr_seat_pointer_warp(constraint->seat, sx, sy); } } From 9f944ff05d8ba86c11f3d694120bf0c960e57905 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 16 Jul 2020 00:59:25 +0200 Subject: [PATCH 14/33] Bump wlroots dependency to 0.11.0 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 997110601..efb05ab64 100644 --- a/meson.build +++ b/meson.build @@ -60,7 +60,7 @@ math = cc.find_library('m') rt = cc.find_library('rt') # Try first to find wlroots as a subproject, then as a system dependency -wlroots_version = ['>=0.10.0', '<0.11.0'] +wlroots_version = ['>=0.11.0', '<0.12.0'] wlroots_proj = subproject( 'wlroots', default_options: ['examples=false'], From e215557ba0f12659fb0fde559e0953f66ba2617d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 16 Jul 2020 00:59:41 +0200 Subject: [PATCH 15/33] Bump version to 1.5 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index efb05ab64..0e4f4ccff 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'sway', 'c', - version: 'v1.5-rc2', #release_version + version: 'v1.5', #release_version license: 'MIT', meson_version: '>=0.53.0', default_options: [ From 6deb4ff40bb1681f879fdb86b291e50c7aeaae0b Mon Sep 17 00:00:00 2001 From: Michael Weiss Date: Thu, 16 Jul 2020 13:31:13 +0200 Subject: [PATCH 16/33] meson.build: Fix the version format The current version is prefixed by a "v" and therefore breaks the output of "swaymsg -rt get_version" which is implemented trough "sscanf(SWAY_VERSION, "%u.%u.%u", &major, &minor, &patch)". The prefixed "v" was added in 8b2ff2f1, probably by accident. --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 0e4f4ccff..372c6db0a 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'sway', 'c', - version: 'v1.5', #release_version + version: '1.5', #release_version license: 'MIT', meson_version: '>=0.53.0', default_options: [ From 380f6c9b46283cf927bc84f7fafd1e0eda230cb5 Mon Sep 17 00:00:00 2001 From: Michael Weiss Date: Thu, 16 Jul 2020 13:39:39 +0200 Subject: [PATCH 17/33] contrib/_incr_version: Disallow the "v"-prefixed version format The check is a bit strange but should be POSIX compliant. --- contrib/_incr_version | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/contrib/_incr_version b/contrib/_incr_version index 436faf148..a4fa26547 100755 --- a/contrib/_incr_version +++ b/contrib/_incr_version @@ -1,6 +1,13 @@ #!/bin/sh -eu old_version="$1" new_version="$2" + +if [ "$new_version" != "${new_version#v}" ] +then + echo "Error: The new version shouldn't be prefixed with a \"v\"." >&2 + exit 1 +fi + sed -i meson.build -e "s/^ version: .*#release_version/ version: '$new_version', #release_version/g" printf "Minimum wlroots version? " From ab8ded626b5d0e9c59495b0988be4077b605d3a2 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Sat, 18 Jul 2020 15:56:43 +0000 Subject: [PATCH 18/33] desktop: output: Scale custom output refresh rate This fixes an issue with wlr-output-management causing the frame rate to jump to 60000 Hz when setting a custom mode. --- sway/desktop/output.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 5fdaba680..90653fa16 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -996,7 +996,8 @@ static void output_manager_apply(struct sway_server *server, } else { oc->width = config_head->state.custom_mode.width; oc->height = config_head->state.custom_mode.height; - oc->refresh_rate = config_head->state.custom_mode.refresh; + oc->refresh_rate = + config_head->state.custom_mode.refresh / 1000.f; } oc->x = config_head->state.x; oc->y = config_head->state.y; From 36c3c222d2418b30fea02c28ea21652ec90238c4 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Thu, 16 Jul 2020 12:18:06 -0700 Subject: [PATCH 19/33] sway.5: add missing underscore --- sway/sway.5.scd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/sway.5.scd b/sway/sway.5.scd index fed4c3c77..6e3ae86d5 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -306,7 +306,7 @@ set|plus|minus Shows a window from the scratchpad. Repeatedly using this command will cycle through the windows in the scratchpad. -*shortcuts inhibitor* enable|disable +*shortcuts_inhibitor* enable|disable Enables or disables the ability of clients to inhibit keyboard shortcuts for a view. This is primarily useful for virtualization and remote desktop software. It affects either the currently focused view From 6898d1963f7a7f6dcc0bff5d4c484818f38cdacf Mon Sep 17 00:00:00 2001 From: Nils Schulte Date: Thu, 16 Jul 2020 10:23:24 +0200 Subject: [PATCH 20/33] moved and renamed movement-unit parsing to common --- common/util.c | 34 ++++++++++ include/util.h | 24 +++++++ sway/commands/resize.c | 144 ++++++++++++++--------------------------- 3 files changed, 106 insertions(+), 96 deletions(-) diff --git a/common/util.c b/common/util.c index cb142a5e1..5ea94f481 100644 --- a/common/util.c +++ b/common/util.c @@ -71,6 +71,40 @@ float parse_float(const char *value) { return flt; } +enum movement_unit parse_movement_unit(const char *unit) { + if (strcasecmp(unit, "px") == 0) { + return MOVEMENT_UNIT_PX; + } + if (strcasecmp(unit, "ppt") == 0) { + return MOVEMENT_UNIT_PPT; + } + if (strcasecmp(unit, "default") == 0) { + return MOVEMENT_UNIT_DEFAULT; + } + return MOVEMENT_UNIT_INVALID; +} + +int parse_movement_amount(int argc, char **argv, + struct movement_amount *amount) { + char *err; + amount->amount = (int)strtol(argv[0], &err, 10); + if (*err) { + // e.g. 10px + amount->unit = parse_movement_unit(err); + return 1; + } + if (argc == 1) { + amount->unit = MOVEMENT_UNIT_DEFAULT; + return 1; + } + // Try the second argument + amount->unit = parse_movement_unit(argv[1]); + if (amount->unit == MOVEMENT_UNIT_INVALID) { + amount->unit = MOVEMENT_UNIT_DEFAULT; + return 1; + } + return 2; +} const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel) { switch (subpixel) { diff --git a/include/util.h b/include/util.h index 7f47d7138..c80da1cbc 100644 --- a/include/util.h +++ b/include/util.h @@ -5,6 +5,30 @@ #include #include +enum movement_unit { + MOVEMENT_UNIT_PX, + MOVEMENT_UNIT_PPT, + MOVEMENT_UNIT_DEFAULT, + MOVEMENT_UNIT_INVALID, +}; + +struct movement_amount { + int amount; + enum movement_unit unit; +}; + +/* + * Parse units such as "px" or "ppt" + */ +enum movement_unit parse_movement_unit(const char *unit); + +/* + * Parse arguments such as "10", "10px" or "10 px". + * Returns the number of arguments consumed. + */ +int parse_movement_amount(int argc, char **argv, + struct movement_amount *amount); + /** * Get the current time, in milliseconds. */ diff --git a/sway/commands/resize.c b/sway/commands/resize.c index 7ff4ef7b2..4038e331b 100644 --- a/sway/commands/resize.c +++ b/sway/commands/resize.c @@ -11,59 +11,11 @@ #include "sway/tree/view.h" #include "sway/tree/workspace.h" #include "log.h" +#include "util.h" #define AXIS_HORIZONTAL (WLR_EDGE_LEFT | WLR_EDGE_RIGHT) #define AXIS_VERTICAL (WLR_EDGE_TOP | WLR_EDGE_BOTTOM) -enum resize_unit { - RESIZE_UNIT_PX, - RESIZE_UNIT_PPT, - RESIZE_UNIT_DEFAULT, - RESIZE_UNIT_INVALID, -}; - -struct resize_amount { - int amount; - enum resize_unit unit; -}; - -static enum resize_unit parse_resize_unit(const char *unit) { - if (strcasecmp(unit, "px") == 0) { - return RESIZE_UNIT_PX; - } - if (strcasecmp(unit, "ppt") == 0) { - return RESIZE_UNIT_PPT; - } - if (strcasecmp(unit, "default") == 0) { - return RESIZE_UNIT_DEFAULT; - } - return RESIZE_UNIT_INVALID; -} - -// Parse arguments such as "10", "10px" or "10 px". -// Returns the number of arguments consumed. -static int parse_resize_amount(int argc, char **argv, - struct resize_amount *amount) { - char *err; - amount->amount = (int)strtol(argv[0], &err, 10); - if (*err) { - // e.g. 10px - amount->unit = parse_resize_unit(err); - return 1; - } - if (argc == 1) { - amount->unit = RESIZE_UNIT_DEFAULT; - return 1; - } - // Try the second argument - amount->unit = parse_resize_unit(argv[1]); - if (amount->unit == RESIZE_UNIT_INVALID) { - amount->unit = RESIZE_UNIT_DEFAULT; - return 1; - } - return 2; -} - static uint32_t parse_resize_axis(const char *axis) { if (strcasecmp(axis, "width") == 0 || strcasecmp(axis, "horizontal") == 0) { return AXIS_HORIZONTAL; @@ -237,7 +189,7 @@ void container_resize_tiled(struct sway_container *con, * Implement `resize ` for a floating container. */ static struct cmd_results *resize_adjust_floating(uint32_t axis, - struct resize_amount *amount) { + struct movement_amount *amount) { struct sway_container *con = config->handler_context.container; int grow_width = 0, grow_height = 0; @@ -294,13 +246,13 @@ static struct cmd_results *resize_adjust_floating(uint32_t axis, * Implement `resize ` for a tiled container. */ static struct cmd_results *resize_adjust_tiled(uint32_t axis, - struct resize_amount *amount) { + struct movement_amount *amount) { struct sway_container *current = config->handler_context.container; - if (amount->unit == RESIZE_UNIT_DEFAULT) { - amount->unit = RESIZE_UNIT_PPT; + if (amount->unit == MOVEMENT_UNIT_DEFAULT) { + amount->unit = MOVEMENT_UNIT_PPT; } - if (amount->unit == RESIZE_UNIT_PPT) { + if (amount->unit == MOVEMENT_UNIT_PPT) { float pct = amount->amount / 100.0f; if (is_horizontal(axis)) { @@ -324,10 +276,10 @@ static struct cmd_results *resize_adjust_tiled(uint32_t axis, * Implement `resize set` for a tiled container. */ static struct cmd_results *resize_set_tiled(struct sway_container *con, - struct resize_amount *width, struct resize_amount *height) { + struct movement_amount *width, struct movement_amount *height) { if (width->amount) { - if (width->unit == RESIZE_UNIT_PPT || - width->unit == RESIZE_UNIT_DEFAULT) { + if (width->unit == MOVEMENT_UNIT_PPT || + width->unit == MOVEMENT_UNIT_DEFAULT) { // Convert to px struct sway_container *parent = con->parent; while (parent && parent->layout != L_HORIZ) { @@ -338,17 +290,17 @@ static struct cmd_results *resize_set_tiled(struct sway_container *con, } else { width->amount = con->workspace->width * width->amount / 100; } - width->unit = RESIZE_UNIT_PX; + width->unit = MOVEMENT_UNIT_PX; } - if (width->unit == RESIZE_UNIT_PX) { + if (width->unit == MOVEMENT_UNIT_PX) { container_resize_tiled(con, AXIS_HORIZONTAL, width->amount - con->width); } } if (height->amount) { - if (height->unit == RESIZE_UNIT_PPT || - height->unit == RESIZE_UNIT_DEFAULT) { + if (height->unit == MOVEMENT_UNIT_PPT || + height->unit == MOVEMENT_UNIT_DEFAULT) { // Convert to px struct sway_container *parent = con->parent; while (parent && parent->layout != L_VERT) { @@ -359,9 +311,9 @@ static struct cmd_results *resize_set_tiled(struct sway_container *con, } else { height->amount = con->workspace->height * height->amount / 100; } - height->unit = RESIZE_UNIT_PX; + height->unit = MOVEMENT_UNIT_PX; } - if (height->unit == RESIZE_UNIT_PX) { + if (height->unit == MOVEMENT_UNIT_PX) { container_resize_tiled(con, AXIS_VERTICAL, height->amount - con->height); } @@ -374,30 +326,30 @@ static struct cmd_results *resize_set_tiled(struct sway_container *con, * Implement `resize set` for a floating container. */ static struct cmd_results *resize_set_floating(struct sway_container *con, - struct resize_amount *width, struct resize_amount *height) { + struct movement_amount *width, struct movement_amount *height) { int min_width, max_width, min_height, max_height, grow_width = 0, grow_height = 0; floating_calculate_constraints(&min_width, &max_width, &min_height, &max_height); if (width->amount) { switch (width->unit) { - case RESIZE_UNIT_PPT: + case MOVEMENT_UNIT_PPT: if (container_is_scratchpad_hidden(con)) { return cmd_results_new(CMD_FAILURE, "Cannot resize a hidden scratchpad container by ppt"); } // Convert to px width->amount = con->workspace->width * width->amount / 100; - width->unit = RESIZE_UNIT_PX; + width->unit = MOVEMENT_UNIT_PX; // Falls through - case RESIZE_UNIT_PX: - case RESIZE_UNIT_DEFAULT: + case MOVEMENT_UNIT_PX: + case MOVEMENT_UNIT_DEFAULT: width->amount = fmax(min_width, fmin(width->amount, max_width)); grow_width = width->amount - con->width; con->x -= grow_width / 2; con->width = width->amount; break; - case RESIZE_UNIT_INVALID: + case MOVEMENT_UNIT_INVALID: sway_assert(false, "invalid width unit"); break; } @@ -405,23 +357,23 @@ static struct cmd_results *resize_set_floating(struct sway_container *con, if (height->amount) { switch (height->unit) { - case RESIZE_UNIT_PPT: + case MOVEMENT_UNIT_PPT: if (container_is_scratchpad_hidden(con)) { return cmd_results_new(CMD_FAILURE, "Cannot resize a hidden scratchpad container by ppt"); } // Convert to px height->amount = con->workspace->height * height->amount / 100; - height->unit = RESIZE_UNIT_PX; + height->unit = MOVEMENT_UNIT_PX; // Falls through - case RESIZE_UNIT_PX: - case RESIZE_UNIT_DEFAULT: + case MOVEMENT_UNIT_PX: + case MOVEMENT_UNIT_DEFAULT: height->amount = fmax(min_height, fmin(height->amount, max_height)); grow_height = height->amount - con->height; con->y -= grow_height / 2; con->height = height->amount; break; - case RESIZE_UNIT_INVALID: + case MOVEMENT_UNIT_INVALID: sway_assert(false, "invalid height unit"); break; } @@ -454,30 +406,30 @@ static struct cmd_results *cmd_resize_set(int argc, char **argv) { "'resize set [width] [px|ppt] [height] [px|ppt]'"; // Width - struct resize_amount width = {0}; + struct movement_amount width = {0}; if (argc >= 2 && !strcmp(argv[0], "width") && strcmp(argv[1], "height")) { argc--; argv++; } if (strcmp(argv[0], "height")) { - int num_consumed_args = parse_resize_amount(argc, argv, &width); + int num_consumed_args = parse_movement_amount(argc, argv, &width); argc -= num_consumed_args; argv += num_consumed_args; - if (width.unit == RESIZE_UNIT_INVALID) { + if (width.unit == MOVEMENT_UNIT_INVALID) { return cmd_results_new(CMD_INVALID, usage); } } // Height - struct resize_amount height = {0}; + struct movement_amount height = {0}; if (argc) { if (argc >= 2 && !strcmp(argv[0], "height")) { argc--; argv++; } - int num_consumed_args = parse_resize_amount(argc, argv, &height); + int num_consumed_args = parse_movement_amount(argc, argv, &height); if (argc > num_consumed_args) { return cmd_results_new(CMD_INVALID, usage); } - if (width.unit == RESIZE_UNIT_INVALID) { + if (width.unit == MOVEMENT_UNIT_INVALID) { return cmd_results_new(CMD_INVALID, usage); } } @@ -515,17 +467,17 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv, --argc; ++argv; // First amount - struct resize_amount first_amount; + struct movement_amount first_amount; if (argc) { - int num_consumed_args = parse_resize_amount(argc, argv, &first_amount); + int num_consumed_args = parse_movement_amount(argc, argv, &first_amount); argc -= num_consumed_args; argv += num_consumed_args; - if (first_amount.unit == RESIZE_UNIT_INVALID) { + if (first_amount.unit == MOVEMENT_UNIT_INVALID) { return cmd_results_new(CMD_INVALID, usage); } } else { first_amount.amount = 10; - first_amount.unit = RESIZE_UNIT_DEFAULT; + first_amount.unit = MOVEMENT_UNIT_DEFAULT; } // "or" @@ -537,18 +489,18 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv, } // Second amount - struct resize_amount second_amount; + struct movement_amount second_amount; if (argc) { - int num_consumed_args = parse_resize_amount(argc, argv, &second_amount); + int num_consumed_args = parse_movement_amount(argc, argv, &second_amount); if (argc > num_consumed_args) { return cmd_results_new(CMD_INVALID, usage); } - if (second_amount.unit == RESIZE_UNIT_INVALID) { + if (second_amount.unit == MOVEMENT_UNIT_INVALID) { return cmd_results_new(CMD_INVALID, usage); } } else { second_amount.amount = 0; - second_amount.unit = RESIZE_UNIT_INVALID; + second_amount.unit = MOVEMENT_UNIT_INVALID; } first_amount.amount *= multiplier; @@ -558,13 +510,13 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv, if (container_is_floating(con)) { // Floating containers can only resize in px. Choose an amount which // uses px, with fallback to an amount that specified no unit. - if (first_amount.unit == RESIZE_UNIT_PX) { + if (first_amount.unit == MOVEMENT_UNIT_PX) { return resize_adjust_floating(axis, &first_amount); - } else if (second_amount.unit == RESIZE_UNIT_PX) { + } else if (second_amount.unit == MOVEMENT_UNIT_PX) { return resize_adjust_floating(axis, &second_amount); - } else if (first_amount.unit == RESIZE_UNIT_DEFAULT) { + } else if (first_amount.unit == MOVEMENT_UNIT_DEFAULT) { return resize_adjust_floating(axis, &first_amount); - } else if (second_amount.unit == RESIZE_UNIT_DEFAULT) { + } else if (second_amount.unit == MOVEMENT_UNIT_DEFAULT) { return resize_adjust_floating(axis, &second_amount); } else { return cmd_results_new(CMD_INVALID, @@ -573,13 +525,13 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv, } // For tiling, prefer ppt -> default -> px - if (first_amount.unit == RESIZE_UNIT_PPT) { + if (first_amount.unit == MOVEMENT_UNIT_PPT) { return resize_adjust_tiled(axis, &first_amount); - } else if (second_amount.unit == RESIZE_UNIT_PPT) { + } else if (second_amount.unit == MOVEMENT_UNIT_PPT) { return resize_adjust_tiled(axis, &second_amount); - } else if (first_amount.unit == RESIZE_UNIT_DEFAULT) { + } else if (first_amount.unit == MOVEMENT_UNIT_DEFAULT) { return resize_adjust_tiled(axis, &first_amount); - } else if (second_amount.unit == RESIZE_UNIT_DEFAULT) { + } else if (second_amount.unit == MOVEMENT_UNIT_DEFAULT) { return resize_adjust_tiled(axis, &second_amount); } else { return resize_adjust_tiled(axis, &first_amount); From b513981378f0ba79a5d3b80b7410addf5595a8ee Mon Sep 17 00:00:00 2001 From: Nils Schulte Date: Thu, 16 Jul 2020 12:04:29 +0200 Subject: [PATCH 21/33] added ppt unit to move position command --- sway/commands/move.c | 90 +++++++++++++++++++++++++++++++++----------- sway/sway.5.scd | 8 ++-- 2 files changed, 72 insertions(+), 26 deletions(-) diff --git a/sway/commands/move.c b/sway/commands/move.c index 038390832..8111a07c0 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -820,37 +820,81 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) { return cmd_results_new(CMD_FAILURE, expected_position_syntax); } - double lx, ly; - char *inv; - lx = (double)strtol(argv[0], &inv, 10); - if (*inv != '\0' && strcasecmp(inv, "px") != 0) { - return cmd_results_new(CMD_FAILURE, "Invalid position specified"); - } - if (strcmp(argv[1], "px") == 0) { - --argc; - ++argv; + struct movement_amount lx = { .amount = 0, .unit = MOVEMENT_UNIT_INVALID }; + // X direction + int num_consumed_args = parse_movement_amount(argc, argv, &lx); + argc -= num_consumed_args; + argv += num_consumed_args; + if (lx.unit == MOVEMENT_UNIT_INVALID) { + return cmd_results_new(CMD_INVALID, "Invalid x position specified"); } - if (argc > 3) { - return cmd_results_new(CMD_FAILURE, expected_position_syntax); + struct movement_amount ly = { .amount = 0, .unit = MOVEMENT_UNIT_INVALID }; + // Y direction + num_consumed_args = parse_movement_amount(argc, argv, &ly); + argc -= num_consumed_args; + argv += num_consumed_args; + if (argc > 0) { + return cmd_results_new(CMD_INVALID, expected_position_syntax); + } + if (ly.unit == MOVEMENT_UNIT_INVALID) { + return cmd_results_new(CMD_INVALID, "Invalid y position specified"); } - ly = (double)strtol(argv[1], &inv, 10); - if ((*inv != '\0' && strcasecmp(inv, "px") != 0) || - (argc == 3 && strcmp(argv[2], "px") != 0)) { - return cmd_results_new(CMD_FAILURE, "Invalid position specified"); + struct sway_workspace *ws = container->workspace; + if (!ws) { + struct sway_seat *seat = config->handler_context.seat; + ws = seat_get_focused_workspace(seat); } - if (!absolute) { - struct sway_workspace *ws = container->workspace; - if (!ws) { - struct sway_seat *seat = config->handler_context.seat; - ws = seat_get_focused_workspace(seat); + switch (lx.unit) { + case MOVEMENT_UNIT_PPT: + if (container_is_scratchpad_hidden(container)) { + return cmd_results_new(CMD_FAILURE, + "Cannot move a hidden scratchpad container by ppt"); } - lx += ws->x; - ly += ws->y; + if (absolute) { + return cmd_results_new(CMD_FAILURE, + "Cannot move to absolute positions by ppt"); + } + // Convert to px + lx.amount = ws->width * lx.amount / 100; + lx.unit = MOVEMENT_UNIT_PX; + // Falls through + case MOVEMENT_UNIT_PX: + case MOVEMENT_UNIT_DEFAULT: + break; + case MOVEMENT_UNIT_INVALID: + sway_assert(false, "invalid x unit"); + break; } - container_floating_move_to(container, lx, ly); + + switch (ly.unit) { + case MOVEMENT_UNIT_PPT: + if (container_is_scratchpad_hidden(container)) { + return cmd_results_new(CMD_FAILURE, + "Cannot move a hidden scratchpad container by ppt"); + } + if (absolute) { + return cmd_results_new(CMD_FAILURE, + "Cannot move to absolute positions by ppt"); + } + // Convert to px + ly.amount = ws->height * ly.amount / 100; + ly.unit = MOVEMENT_UNIT_PX; + // Falls through + case MOVEMENT_UNIT_PX: + case MOVEMENT_UNIT_DEFAULT: + break; + case MOVEMENT_UNIT_INVALID: + sway_assert(false, "invalid y unit"); + break; + } + if (!absolute) { + lx.amount += ws->x; + ly.amount += ws->y; + } + container_floating_move_to(container, lx.amount, ly.amount); return cmd_results_new(CMD_SUCCESS, NULL); } diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 6e3ae86d5..65ae90870 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -215,9 +215,11 @@ set|plus|minus If unspecified, the default is 10 pixels. Pixels are ignored when moving tiled containers. -*move* [absolute] position [px] [px] - Moves the focused container to the specified position in the workspace. If - _absolute_ is used, the position is relative to all outputs. +*move* [absolute] position [px|ppt] [px|ptt] + Moves the focused container to the specified position in the workspace. + The position can be specified in pixels or percentage points, ommitting + the unit defualts to pixels. If _absolute_ is used, the position is + relative to all outputs. _absolute_ can not be used with percentage points. *move* [absolute] position center Moves the focused container to be centered on the workspace. If _absolute_ From 7c7afa3b297d17bb36fd1d112485ebf6b9a40c5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonin=20D=C3=A9cimo?= Date: Tue, 21 Jul 2020 17:43:12 +0200 Subject: [PATCH 22/33] Fix typos in man page. --- sway/sway.5.scd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 65ae90870..1ca82f7b5 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -217,8 +217,8 @@ set|plus|minus *move* [absolute] position [px|ppt] [px|ptt] Moves the focused container to the specified position in the workspace. - The position can be specified in pixels or percentage points, ommitting - the unit defualts to pixels. If _absolute_ is used, the position is + The position can be specified in pixels or percentage points, omitting + the unit defaults to pixels. If _absolute_ is used, the position is relative to all outputs. _absolute_ can not be used with percentage points. *move* [absolute] position center From 66b7ac6a82ccf62e6408443f66c6a370a314ebaa Mon Sep 17 00:00:00 2001 From: Charmander <~@charmander.me> Date: Sat, 11 Jul 2020 10:21:02 -0700 Subject: [PATCH 23/33] swaybar: allow status line cleanup to proceed when hidden MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `determine_bar_visibility` stops and starts the status command process according to the bar’s visibility. If the bar was hidden during teardown, teardown would stall while waiting for the stopped status command process to exit. This resumes a stopped status command during teardown and allows, for example, sway to reload or quit without leaving a swaybar instance behind each time. Fixes #5536. CONT before TERM as requested in review. --- swaybar/status_line.c | 1 + 1 file changed, 1 insertion(+) diff --git a/swaybar/status_line.c b/swaybar/status_line.c index 71ceb1d04..ecd91032a 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c @@ -185,6 +185,7 @@ struct status_line *status_line_init(char *cmd) { void status_line_free(struct status_line *status) { status_line_close_fds(status); + kill(status->pid, status->cont_signal); kill(status->pid, SIGTERM); waitpid(status->pid, NULL, 0); if (status->protocol == PROTOCOL_I3BAR) { From 4f718e6c75d2168d417b4b41c0e3d5408e0afded Mon Sep 17 00:00:00 2001 From: Tobias Langendorf Date: Sat, 18 Jul 2020 21:26:15 +0200 Subject: [PATCH 24/33] Fix X11 clients getting stuck minimized Usually it should be enough to simply not grant a client's minimize request, however some applications (Steam, fullscreen games in Wine) don't wait for the compositor and minimize anyway, getting them stuck in an unrecoverable state. Restoring them immediately lead to heavy flickering when unfocused on my test application (Earth Defense Force 5 via Steam), so it's preferable to grant their request without actually minimizing and then restoring them once they are in focus again. --- include/sway/tree/view.h | 1 + sway/desktop/xwayland.c | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 665c516f9..a32f5907c 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -147,6 +147,7 @@ struct sway_xwayland_view { struct wl_listener request_move; struct wl_listener request_resize; struct wl_listener request_maximize; + struct wl_listener request_minimize; struct wl_listener request_configure; struct wl_listener request_fullscreen; struct wl_listener request_activate; diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index c972fd3a7..db21dc785 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -222,6 +222,11 @@ static void set_activated(struct sway_view *view, bool activated) { return; } struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; + + if (activated && surface->minimized) { + wlr_xwayland_surface_set_minimized(surface, false); + } + wlr_xwayland_surface_activate(surface, activated); } @@ -406,6 +411,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { 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->request_minimize.link); wl_list_remove(&xwayland_view->request_move.link); wl_list_remove(&xwayland_view->request_resize.link); wl_list_remove(&xwayland_view->request_activate.link); @@ -508,6 +514,21 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) transaction_commit_dirty(); } +static void handle_request_minimize(struct wl_listener *listener, void *data) { + struct sway_xwayland_view *xwayland_view = + wl_container_of(listener, xwayland_view, request_minimize); + struct sway_view *view = &xwayland_view->view; + struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; + if (!xsurface->mapped) { + return; + } + + struct wlr_xwayland_minimize_event *e = data; + struct sway_seat *seat = input_manager_current_seat(); + bool focused = seat_get_focus(seat) == &view->container->node; + wlr_xwayland_surface_set_minimized(xsurface, !focused && e->minimize); +} + static void handle_request_move(struct wl_listener *listener, void *data) { struct sway_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view, request_move); @@ -653,6 +674,10 @@ 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.request_minimize, + &xwayland_view->request_minimize); + xwayland_view->request_minimize.notify = handle_request_minimize; + wl_signal_add(&xsurface->events.request_activate, &xwayland_view->request_activate); xwayland_view->request_activate.notify = handle_request_activate; From 3520fd2c192f087dc6f3525b0d7d15c2790103b8 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Fri, 24 Jul 2020 10:33:01 -0700 Subject: [PATCH 25/33] view: display scratchpad hidden containers when activated by ftm --- sway/tree/view.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sway/tree/view.c b/sway/tree/view.c index ac3147953..2353feffd 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -625,7 +625,12 @@ static void handle_foreign_activate_request( struct sway_seat *seat; wl_list_for_each(seat, &server.input->seats, link) { if (seat->wlr_seat == event->seat) { + if (container_is_scratchpad_hidden_or_child(view->container)) { + root_scratchpad_show(view->container); + } seat_set_focus_container(seat, view->container); + seat_consider_warp_to_focus(seat); + container_raise_floating(view->container); break; } } From dae74057b3b81b5c9b7646b9c09b4549f4e35740 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Thu, 23 Jul 2020 02:21:12 -0700 Subject: [PATCH 26/33] commands: disallow runtime include --- sway/commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/commands.c b/sway/commands.c index f20a8baa8..fe1e98b53 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -72,7 +72,6 @@ static struct cmd_handler handlers[] = { { "fullscreen", cmd_fullscreen }, { "gaps", cmd_gaps }, { "hide_edge_borders", cmd_hide_edge_borders }, - { "include", cmd_include }, { "input", cmd_input }, { "mode", cmd_mode }, { "mouse_warping", cmd_mouse_warping }, @@ -101,6 +100,7 @@ static struct cmd_handler handlers[] = { /* Config-time only commands. Keep alphabetized */ static struct cmd_handler config_handlers[] = { { "default_orientation", cmd_default_orientation }, + { "include", cmd_include }, { "swaybg_command", cmd_swaybg_command }, { "swaynag_command", cmd_swaynag_command }, { "workspace_layout", cmd_workspace_layout }, From cfa403fc58f3df9cdef2bc03d0a8bbdd4333ed00 Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Tue, 21 Jan 2020 01:32:22 -0700 Subject: [PATCH 27/33] Keep windows in bounds on move to position mouse If the mouse/cursor/pointer is near the edge of an output when a "move position to pointer" command is run, then the floating container will be constrained to fit inside the bounds of the output as much as possible. This behavior matches what i3 does in this scenario. I also think it is a better user experience. Relates to #4906 The logic for the bounds check follows the implementation in i3: https://github.com/i3/i3/blob/733077822302d8b77eacb606a26fd002a42f534f/src/floating.c#L536 --- sway/commands/move.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/sway/commands/move.c b/sway/commands/move.c index 8111a07c0..23d392f95 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -1,5 +1,6 @@ #define _POSIX_C_SOURCE 200809L #include +#include #include #include #include @@ -753,6 +754,39 @@ static struct cmd_results *cmd_move_in_direction( return cmd_results_new(CMD_SUCCESS, NULL); } +static struct cmd_results *cmd_move_to_position_pointer( + struct sway_container *container) { + struct sway_seat *seat = config->handler_context.seat; + if (!seat->cursor) { + return cmd_results_new(CMD_FAILURE, "No cursor device"); + } + struct wlr_cursor *cursor = seat->cursor->cursor; + /* Determine where to put the window. */ + double lx = cursor->x - container->width / 2; + double ly = cursor->y - container->height / 2; + + /* Correct target coordinates to be in bounds (on screen). */ + for (int i = 0; i < root->outputs->length; ++i) { + struct wlr_box box; + output_get_box(root->outputs->items[i], &box); + if (wlr_box_contains_point(&box, cursor->x, cursor->y)) { + lx = fmax(lx, box.x); + ly = fmax(ly, box.y); + if (lx + container->width > box.x + box.width) { + lx = box.x + box.width - container->width; + } + if (ly + container->height > box.y + box.height) { + ly = box.y + box.height - container->height; + } + break; + } + } + + /* Actually move the container. */ + container_floating_move_to(container, lx, ly); + return cmd_results_new(CMD_SUCCESS, NULL); +} + static const char expected_position_syntax[] = "Expected 'move [absolute] position [px] [px]' or " "'move [absolute] position center' or " @@ -790,14 +824,7 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) { if (absolute) { return cmd_results_new(CMD_INVALID, expected_position_syntax); } - struct sway_seat *seat = config->handler_context.seat; - if (!seat->cursor) { - return cmd_results_new(CMD_FAILURE, "No cursor device"); - } - double lx = seat->cursor->cursor->x - container->width / 2; - double ly = seat->cursor->cursor->y - container->height / 2; - container_floating_move_to(container, lx, ly); - return cmd_results_new(CMD_SUCCESS, NULL); + return cmd_move_to_position_pointer(container); } else if (strcmp(argv[0], "center") == 0) { double lx, ly; if (absolute) { From b20d52f71d6567b26199050ac0a2735eefd5a985 Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Tue, 21 Jan 2020 23:05:39 -0700 Subject: [PATCH 28/33] Use wlr_output_layout_output_at to get output for move to cursor --- sway/commands/move.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/sway/commands/move.c b/sway/commands/move.c index 23d392f95..c1d1fade6 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -766,19 +766,18 @@ static struct cmd_results *cmd_move_to_position_pointer( double ly = cursor->y - container->height / 2; /* Correct target coordinates to be in bounds (on screen). */ - for (int i = 0; i < root->outputs->length; ++i) { - struct wlr_box box; - output_get_box(root->outputs->items[i], &box); - if (wlr_box_contains_point(&box, cursor->x, cursor->y)) { - lx = fmax(lx, box.x); - ly = fmax(ly, box.y); - if (lx + container->width > box.x + box.width) { - lx = box.x + box.width - container->width; - } - if (ly + container->height > box.y + box.height) { - ly = box.y + box.height - container->height; - } - break; + struct wlr_output *output = wlr_output_layout_output_at( + root->output_layout, cursor->x, cursor->y); + if (output) { + struct wlr_box *box = + wlr_output_layout_get_box(root->output_layout, output); + lx = fmax(lx, box->x); + ly = fmax(ly, box->y); + if (lx + container->width > box->x + box->width) { + lx = box->x + box->width - container->width; + } + if (ly + container->height > box->y + box->height) { + ly = box->y + box->height - container->height; } } From 8033b575f7f83203371343457c102233b17cfd77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonin=20D=C3=A9cimo?= Date: Thu, 4 Jun 2020 13:00:45 +0200 Subject: [PATCH 29/33] ipc: fix aligment issue of data buffer The pointer `data` is cast to a more strictly aligned pointer type. To prevent issues, the `data32` buffer is removed and its occurrences are replaced with an offset from the `data` buffer. --- common/ipc-client.c | 12 +++++------- sway/ipc-server.c | 10 ++++------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/common/ipc-client.c b/common/ipc-client.c index ec0454c96..d30212d25 100644 --- a/common/ipc-client.c +++ b/common/ipc-client.c @@ -79,7 +79,6 @@ bool ipc_set_recv_timeout(int socketfd, struct timeval tv) { struct ipc_response *ipc_recv_response(int socketfd) { char data[IPC_HEADER_SIZE]; - uint32_t *data32 = (uint32_t *)(data + sizeof(ipc_magic)); size_t total = 0; while (total < IPC_HEADER_SIZE) { @@ -95,15 +94,15 @@ struct ipc_response *ipc_recv_response(int socketfd) { goto error_1; } - total = 0; - memcpy(&response->size, &data32[0], sizeof(data32[0])); - memcpy(&response->type, &data32[1], sizeof(data32[1])); + memcpy(&response->size, data + sizeof(ipc_magic), sizeof(uint32_t)); + memcpy(&response->type, data + sizeof(ipc_magic) + sizeof(uint32_t), sizeof(uint32_t)); char *payload = malloc(response->size + 1); if (!payload) { goto error_2; } + total = 0; while (total < response->size) { ssize_t received = recv(socketfd, payload + total, response->size - total, 0); if (received < 0) { @@ -129,10 +128,9 @@ void free_ipc_response(struct ipc_response *response) { char *ipc_single_command(int socketfd, uint32_t type, const char *payload, uint32_t *len) { char data[IPC_HEADER_SIZE]; - uint32_t *data32 = (uint32_t *)(data + sizeof(ipc_magic)); memcpy(data, ipc_magic, sizeof(ipc_magic)); - memcpy(&data32[0], len, sizeof(*len)); - memcpy(&data32[1], &type, sizeof(type)); + memcpy(data + sizeof(ipc_magic), len, sizeof(*len)); + memcpy(data + sizeof(ipc_magic) + sizeof(*len), &type, sizeof(type)); if (write(socketfd, data, IPC_HEADER_SIZE) == -1) { sway_abort("Unable to send IPC header"); diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 62bdccb88..8ba8b9baa 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -242,7 +242,6 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { } uint8_t buf[IPC_HEADER_SIZE]; - uint32_t *buf32 = (uint32_t*)(buf + sizeof(ipc_magic)); // Should be fully available, because read_available >= IPC_HEADER_SIZE ssize_t received = recv(client_fd, buf, IPC_HEADER_SIZE, 0); if (received == -1) { @@ -257,8 +256,8 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { return 0; } - memcpy(&client->pending_length, &buf32[0], sizeof(buf32[0])); - memcpy(&client->pending_type, &buf32[1], sizeof(buf32[1])); + memcpy(&client->pending_length, buf + sizeof(ipc_magic), sizeof(uint32_t)); + memcpy(&client->pending_type, buf + sizeof(ipc_magic) + sizeof(uint32_t), sizeof(uint32_t)); if (read_available - received >= (long)client->pending_length) { // Reset pending values. @@ -920,11 +919,10 @@ bool ipc_send_reply(struct ipc_client *client, enum ipc_command_type payload_typ assert(payload); char data[IPC_HEADER_SIZE]; - uint32_t *data32 = (uint32_t*)(data + sizeof(ipc_magic)); memcpy(data, ipc_magic, sizeof(ipc_magic)); - memcpy(&data32[0], &payload_length, sizeof(payload_length)); - memcpy(&data32[1], &payload_type, sizeof(payload_type)); + memcpy(data + sizeof(ipc_magic), &payload_length, sizeof(payload_length)); + memcpy(data + sizeof(ipc_magic) + sizeof(payload_length), &payload_type, sizeof(payload_type)); while (client->write_buffer_len + IPC_HEADER_SIZE + payload_length >= client->write_buffer_size) { From 2960b2c9b6c77d42f2696c1997bda965594e5dd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonin=20D=C3=A9cimo?= Date: Thu, 4 Jun 2020 13:47:57 +0200 Subject: [PATCH 30/33] cmd/bar/colors: fix dereference of null pointer `!*rgba` tests if the first byte of rgba isn't `'\0'`. `hex_to_rgba_hex` returns NULL if `parse_color` fails. There's a null pointer dereference in that case. The intended behavior is `!rgba`. --- sway/commands/bar/colors.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sway/commands/bar/colors.c b/sway/commands/bar/colors.c index ea2b912d3..2d5b22bf6 100644 --- a/sway/commands/bar/colors.c +++ b/sway/commands/bar/colors.c @@ -24,6 +24,9 @@ static char *hex_to_rgba_hex(const char *hex) { return NULL; } char *rgba = malloc(10); + if (!rgba) { + return NULL; + } snprintf(rgba, 10, "#%08x", color); return rgba; } @@ -36,7 +39,7 @@ static struct cmd_results *parse_single_color(char **color, } char *rgba = hex_to_rgba_hex(argv[0]); - if (!*rgba) { + if (!rgba) { return cmd_results_new(CMD_INVALID, "Invalid color: %s", argv[0]); } From a1c6052383d382d978ca597dc5fb280c0343db60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonin=20D=C3=A9cimo?= Date: Thu, 4 Jun 2020 14:41:22 +0200 Subject: [PATCH 31/33] Log empty value if envvar is not defined If the environment variable is not defined, getenv returns NULL. Passing a NULL pointer to the "%s" format specifier is undefined behavior. Even if some implementations output "(null)", an empty string is nicer. --- sway/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sway/main.c b/sway/main.c index d893654fd..57716071e 100644 --- a/sway/main.c +++ b/sway/main.c @@ -138,7 +138,8 @@ static void log_env(void) { "SWAYSOCK", }; for (size_t i = 0; i < sizeof(log_vars) / sizeof(char *); ++i) { - sway_log(SWAY_INFO, "%s=%s", log_vars[i], getenv(log_vars[i])); + char *value = getenv(log_vars[i]); + sway_log(SWAY_INFO, "%s=%s", log_vars[i], value != NULL ? value : ""); } } From bbf7b92fe4b34288dbe7c58827a1f69428ffb263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonin=20D=C3=A9cimo?= Date: Thu, 4 Jun 2020 15:43:42 +0200 Subject: [PATCH 32/33] Fix incorrect format specifiers --- sway/commands/bind.c | 2 +- sway/desktop/layer_shell.c | 6 +++--- sway/input/libinput.c | 4 ++-- sway/input/seat.c | 2 +- sway/ipc-json.c | 2 +- sway/ipc-server.c | 2 +- swaynag/main.c | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sway/commands/bind.c b/sway/commands/bind.c index f903f939e..f6e58d991 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c @@ -715,7 +715,7 @@ bool translate_binding(struct sway_binding *binding) { struct keycode_matches matches = get_keycode_for_keysym(*keysym); if (matches.count != 1) { - sway_log(SWAY_INFO, "Unable to convert keysym %d into" + sway_log(SWAY_INFO, "Unable to convert keysym %" PRIu32 " into" " a single keycode (found %d matches)", *keysym, matches.count); goto error; diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 60a8f06b1..738b17979 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -510,11 +510,11 @@ struct sway_layer_surface *layer_from_wlr_layer_surface_v1( void handle_layer_shell_surface(struct wl_listener *listener, void *data) { struct wlr_layer_surface_v1 *layer_surface = data; - sway_log(SWAY_DEBUG, "new layer surface: namespace %s layer %d anchor %d " - "size %dx%d margin %d,%d,%d,%d", + sway_log(SWAY_DEBUG, "new layer surface: namespace %s layer %d anchor %" PRIu32 + " size %" PRIu32 "x%" PRIu32 " margin %" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",", layer_surface->namespace, layer_surface->client_pending.layer, - layer_surface->client_pending.layer, + layer_surface->client_pending.anchor, layer_surface->client_pending.desired_width, layer_surface->client_pending.desired_height, layer_surface->client_pending.margin.top, diff --git a/sway/input/libinput.c b/sway/input/libinput.c index 4ec728821..108fc7b24 100644 --- a/sway/input/libinput.c +++ b/sway/input/libinput.c @@ -19,7 +19,7 @@ static bool set_send_events(struct libinput_device *device, uint32_t mode) { if (libinput_device_config_send_events_get_mode(device) == mode) { return false; } - sway_log(SWAY_DEBUG, "send_events_set_mode(%d)", mode); + sway_log(SWAY_DEBUG, "send_events_set_mode(%" PRIu32 ")", mode); log_status(libinput_device_config_send_events_set_mode(device, mode)); return true; } @@ -150,7 +150,7 @@ static bool set_scroll_button(struct libinput_device *dev, uint32_t button) { libinput_device_config_scroll_get_button(dev) == button) { return false; } - sway_log(SWAY_DEBUG, "scroll_set_button(%d)", button); + sway_log(SWAY_DEBUG, "scroll_set_button(%" PRIu32 ")", button); log_status(libinput_device_config_scroll_set_button(dev, button)); return true; } diff --git a/sway/input/seat.c b/sway/input/seat.c index bcf01962f..e16d747cf 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -916,7 +916,7 @@ void seat_configure_xcursor(struct sway_seat *seat) { if (seat == input_manager_get_default_seat()) { char cursor_size_fmt[16]; - snprintf(cursor_size_fmt, sizeof(cursor_size_fmt), "%d", cursor_size); + snprintf(cursor_size_fmt, sizeof(cursor_size_fmt), "%u", cursor_size); setenv("XCURSOR_SIZE", cursor_size_fmt, 1); if (cursor_theme != NULL) { setenv("XCURSOR_THEME", cursor_theme, 1); diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 70b81ad1d..9330de09f 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -160,7 +160,7 @@ json_object *ipc_json_get_version(void) { int major = 0, minor = 0, patch = 0; json_object *version = json_object_new_object(); - sscanf(SWAY_VERSION, "%u.%u.%u", &major, &minor, &patch); + sscanf(SWAY_VERSION, "%d.%d.%d", &major, &minor, &patch); json_object_object_add(version, "human_readable", json_object_new_string(SWAY_VERSION)); json_object_object_add(version, "variant", json_object_new_string("sway")); diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 8ba8b9baa..aad9a7b5b 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -140,7 +140,7 @@ struct sockaddr_un *ipc_user_sockaddr(void) { dir = "/tmp"; } if (path_size <= snprintf(ipc_sockaddr->sun_path, path_size, - "%s/sway-ipc.%i.%i.sock", dir, getuid(), getpid())) { + "%s/sway-ipc.%u.%i.sock", dir, getuid(), getpid())) { sway_abort("Socket path won't fit into ipc_sockaddr->sun_path"); } diff --git a/swaynag/main.c b/swaynag/main.c index c82124156..880078187 100644 --- a/swaynag/main.c +++ b/swaynag/main.c @@ -106,7 +106,7 @@ int main(int argc, char **argv) { } sway_log(SWAY_DEBUG, "Output: %s", swaynag.type->output); - sway_log(SWAY_DEBUG, "Anchors: %d", swaynag.type->anchors); + sway_log(SWAY_DEBUG, "Anchors: %" PRIu32, swaynag.type->anchors); sway_log(SWAY_DEBUG, "Type: %s", swaynag.type->name); sway_log(SWAY_DEBUG, "Message: %s", swaynag.message); sway_log(SWAY_DEBUG, "Font: %s", swaynag.type->font); From 5c67d997948309d881ed94387309865c76ecddcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonin=20D=C3=A9cimo?= Date: Mon, 15 Jun 2020 15:46:58 +0200 Subject: [PATCH 33/33] common/loop: check return of realloc --- common/loop.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/common/loop.c b/common/loop.c index aecad2f3f..80fe18eae 100644 --- a/common/loop.c +++ b/common/loop.c @@ -117,9 +117,15 @@ void loop_add_fd(struct loop *loop, int fd, short mask, struct pollfd pfd = {fd, mask, 0}; if (loop->fd_length == loop->fd_capacity) { - loop->fd_capacity += 10; - loop->fds = realloc(loop->fds, - sizeof(struct pollfd) * loop->fd_capacity); + int capacity = loop->fd_capacity + 10; + struct pollfd *tmp = realloc(loop->fds, + sizeof(struct pollfd) * capacity); + if (!tmp) { + sway_log(SWAY_ERROR, "Unable to allocate memory for pollfd"); + return; + } + loop->fds = tmp; + loop->fd_capacity = capacity; } loop->fds[loop->fd_length++] = pfd;