From 743d34538333e4111a71fad32668335dff9a4822 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sun, 3 Feb 2019 14:00:37 -0500 Subject: [PATCH 01/52] Merge pull request #3563 from vilhalmer/fix-wildcard-seat-constrain-crashes-during-reconfig Fix wildcard seat constrain crashes during reconfig --- sway/config.c | 5 +++++ sway/input/cursor.c | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/sway/config.c b/sway/config.c index 7cb27d955..54d29fc90 100644 --- a/sway/config.c +++ b/sway/config.c @@ -141,6 +141,11 @@ static void destroy_removed_seats(struct sway_config *old_config, int i; for (i = 0; i < old_config->seat_configs->length; i++) { seat_config = old_config->seat_configs->items[i]; + // Skip the wildcard seat config, it won't have a matching real seat. + if (strcmp(seat_config->name, "*") == 0) { + continue; + } + /* Also destroy seats that aren't present in new config */ if (new_config && list_seq_find(new_config->seat_configs, seat_name_cmp, seat_config->name) < 0) { diff --git a/sway/input/cursor.c b/sway/input/cursor.c index c38d8d3a1..01aae79d4 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -1459,7 +1459,11 @@ void handle_pointer_constraint(struct wl_listener *listener, void *data) { void sway_cursor_constrain(struct sway_cursor *cursor, struct wlr_pointer_constraint_v1 *constraint) { struct seat_config *config = seat_get_config(cursor->seat); - if (config->allow_constrain == CONSTRAIN_DISABLE) { + if (!config) { + config = seat_get_config_by_name("*"); + } + + if (!config || config->allow_constrain == CONSTRAIN_DISABLE) { return; } From 130626a5db87c43a38b300700d013313f99ef4c6 Mon Sep 17 00:00:00 2001 From: vilhalmer Date: Sun, 3 Feb 2019 12:12:40 -0500 Subject: [PATCH 02/52] Focus ws inactive node with focus_follows_mouse --- sway/input/cursor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 01aae79d4..1bf548db7 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -362,7 +362,7 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, struct sway_output *focused_output = node_get_output(focus); struct sway_output *output = node_get_output(node); if (output != focused_output) { - seat_set_focus(seat, node); + seat_set_focus(seat, seat_get_focus_inactive(seat, node)); } } else if (node->type == N_CONTAINER && node->sway_container->view) { // Focus node if the following are true: From 4272bf127439a2d8515e934821a9744537260b9d Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sun, 3 Feb 2019 13:56:05 -0500 Subject: [PATCH 03/52] seat_cmd_cursor: do not create non-existing seat If a seat does not exist in seat_cmd_cursor, do not create it. A seat without any attachments is useless since it will have no capabilities. This changes `input_manager_get_seat` to have an additional argument that dictates whether or not to create the seat if it does not exist. --- include/sway/input/input-manager.h | 2 +- sway/commands/seat/cursor.c | 5 +++-- sway/config.c | 6 ++++-- sway/input/input-manager.c | 9 +++++---- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index 8e8bf1f20..e166a2377 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h @@ -45,7 +45,7 @@ void input_manager_apply_seat_config(struct seat_config *seat_config); struct sway_seat *input_manager_get_default_seat(void); -struct sway_seat *input_manager_get_seat(const char *seat_name); +struct sway_seat *input_manager_get_seat(const char *seat_name, bool create); /** * If none of the seat configs have a fallback setting (either true or false), diff --git a/sway/commands/seat/cursor.c b/sway/commands/seat/cursor.c index 4f805b227..0c7609eaf 100644 --- a/sway/commands/seat/cursor.c +++ b/sway/commands/seat/cursor.c @@ -61,9 +61,10 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) { } if (strcmp(sc->name, "*") != 0) { - struct sway_seat *seat = input_manager_get_seat(sc->name); + struct sway_seat *seat = input_manager_get_seat(sc->name, false); if (!seat) { - return cmd_results_new(CMD_FAILURE, "Failed to get seat"); + return cmd_results_new(CMD_FAILURE, + "Seat %s does not exist", sc->name); } error = handle_command(seat->cursor, argc, argv); } else { diff --git a/sway/config.c b/sway/config.c index 54d29fc90..ee1c42df3 100644 --- a/sway/config.c +++ b/sway/config.c @@ -149,8 +149,10 @@ static void destroy_removed_seats(struct sway_config *old_config, /* Also destroy seats that aren't present in new config */ if (new_config && list_seq_find(new_config->seat_configs, seat_name_cmp, seat_config->name) < 0) { - seat = input_manager_get_seat(seat_config->name); - seat_destroy(seat); + seat = input_manager_get_seat(seat_config->name, false); + if (seat) { + seat_destroy(seat); + } } } } diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 8d263e06b..f99fc395b 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -31,10 +31,10 @@ struct sway_seat *input_manager_current_seat(void) { } struct sway_seat *input_manager_get_default_seat(void) { - return input_manager_get_seat(DEFAULT_SEAT); + return input_manager_get_seat(DEFAULT_SEAT, true); } -struct sway_seat *input_manager_get_seat(const char *seat_name) { +struct sway_seat *input_manager_get_seat(const char *seat_name, bool create) { struct sway_seat *seat = NULL; wl_list_for_each(seat, &server.input->seats, link) { if (strcmp(seat->wlr_seat->name, seat_name) == 0) { @@ -42,7 +42,7 @@ struct sway_seat *input_manager_get_seat(const char *seat_name) { } } - return seat_create(seat_name); + return create ? seat_create(seat_name) : NULL; } char *input_device_get_identifier(struct wlr_input_device *device) { @@ -674,7 +674,8 @@ void input_manager_apply_seat_config(struct seat_config *seat_config) { seat_apply_config(seat, sc); } } else { - struct sway_seat *seat = input_manager_get_seat(seat_config->name); + struct sway_seat *seat = + input_manager_get_seat(seat_config->name, true); if (!seat) { return; } From df3ea6a55f4a163ce5d1f241060a1308198ff27a Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Tue, 5 Feb 2019 01:59:40 -0500 Subject: [PATCH 04/52] load_include_configs: fix wordexp fail condition This fixes the failure condition for the wordexp call in load_include_configs. The only success value is zero. Since the error codes are positive, having the check be less than zero was causing segfaults on failure when accessing the words. --- sway/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/config.c b/sway/config.c index ee1c42df3..0c23fad84 100644 --- a/sway/config.c +++ b/sway/config.c @@ -557,7 +557,7 @@ bool load_include_configs(const char *path, struct sway_config *config, wordexp_t p; - if (wordexp(path, &p, 0) < 0) { + if (wordexp(path, &p, 0) != 0) { free(parent_path); free(wd); return false; From 66062f53de5685eaf9ba28de6e08f236372f04b1 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Tue, 5 Feb 2019 00:31:06 -0500 Subject: [PATCH 05/52] swaynag: remove trailing newlines in config Now that swaynag uses getline (instead of the old readline), the trailing newline characters have to be removed when reading the config --- swaynag/config.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/swaynag/config.c b/swaynag/config.c index 40f3f65e8..200611f4b 100644 --- a/swaynag/config.c +++ b/swaynag/config.c @@ -348,6 +348,10 @@ int swaynag_load_config(char *path, struct swaynag *swaynag, list_t *types) { continue; } + if (line[nread - 1] == '\n') { + line[nread - 1] = '\0'; + } + if (line[0] == '[') { char *close = strchr(line, ']'); if (!close) { From 5d770d028a0fa29861ef07e04d66ae28cbe9c6a4 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Mon, 4 Feb 2019 23:39:37 -0500 Subject: [PATCH 06/52] execute_command: dont strip quotes for exec_always This removes quote stripping for `exec_always` in `execute_command`. Since `exec_always` commands will be deferred in the config and processed by `execute_command`, the quotes need to be left intact like they are for `exec`. --- sway/commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/commands.c b/sway/commands.c index dd994fa15..82f41545d 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -254,7 +254,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat, //TODO better handling of argv int argc; char **argv = split_args(cmd, &argc); - if (strcmp(argv[0], "exec") != 0) { + if (!strcmp(argv[0], "exec") && !strcmp(argv[0], "exec_always")) { int i; for (i = 1; i < argc; ++i) { if (*argv[i] == '\"' || *argv[i] == '\'') { From 610794d4e3b2d8434f4ea3ef518bcdfc8a2dc28c Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 5 Feb 2019 12:52:02 +0100 Subject: [PATCH 07/52] Fix quote stripping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's not use !strcmp(…) anymore. --- sway/commands.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sway/commands.c b/sway/commands.c index 82f41545d..3fc4f86e4 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -254,7 +254,8 @@ list_t *execute_command(char *_exec, struct sway_seat *seat, //TODO better handling of argv int argc; char **argv = split_args(cmd, &argc); - if (!strcmp(argv[0], "exec") && !strcmp(argv[0], "exec_always")) { + if (strcmp(argv[0], "exec") != 0 && + strcmp(argv[0], "exec_always") != 0) { int i; for (i = 1; i < argc; ++i) { if (*argv[i] == '\"' || *argv[i] == '\'') { From 41e10db0de243c903e28ae8f0b669ff681974e69 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Tue, 5 Feb 2019 07:39:21 -0500 Subject: [PATCH 08/52] IPC_COMMAND: split on newline This splits commands given in IPC_COMMAND on newline to match i3's behavior. --- sway/ipc-server.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sway/ipc-server.c b/sway/ipc-server.c index d1920cfd4..eb6f159d6 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -595,6 +595,16 @@ void ipc_client_handle_command(struct ipc_client *client) { switch (client->current_command) { case IPC_COMMAND: { + char *line = strtok(buf, "\n"); + while (line) { + size_t line_length = strlen(line); + if (line + line_length >= buf + client->payload_length) { + break; + } + line[line_length] = ';'; + line = strtok(NULL, "\n"); + } + list_t *res_list = execute_command(buf, NULL, NULL); transaction_commit_dirty(); char *json = cmd_results_to_json(res_list); From 9346ed1805dab798fe9f6edcb47e003081722d79 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Tue, 5 Feb 2019 14:32:05 +0100 Subject: [PATCH 09/52] Set version in project file Let's set the version in the meson file instead of declaring it outside. In case git is installed we use the git hash as version. Instead it isn't (like on a clean build system), let's use the version defined in the project. --- meson.build | 12 ++++-------- meson_options.txt | 1 - 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/meson.build b/meson.build index 766bf012f..c50fab176 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,7 @@ project( 'sway', 'c', + version: '1.0', license: 'MIT', meson_version: '>=0.48.0', default_options: [ @@ -127,17 +128,12 @@ endif add_project_arguments('-DSYSCONFDIR="/@0@"'.format(join_paths(prefix, sysconfdir)), language : 'c') -version = get_option('sway-version') -if version != '' - version = '"@0@"'.format(version) -else - if not git.found() - error('git is required to make the version string') - endif - +if git.found() git_commit_hash = run_command([git.path(), 'describe', '--always', '--tags']).stdout().strip() git_branch = run_command([git.path(), 'rev-parse', '--abbrev-ref', 'HEAD']).stdout().strip() version = '"@0@ (" __DATE__ ", branch \'@1@\')"'.format(git_commit_hash, git_branch) +else + version = '"@0@"'.format(meson.project_version()) endif add_project_arguments('-DSWAY_VERSION=@0@'.format(version), language: 'c') diff --git a/meson_options.txt b/meson_options.txt index 04b29e17a..d3667acfd 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,4 +1,3 @@ -option('sway-version', type : 'string', description: 'The version string reported in `sway --version`.') option('default-wallpaper', type: 'boolean', value: true, description: 'Install the default wallpaper.') option('zsh-completions', type: 'boolean', value: true, description: 'Install zsh shell completions.') option('bash-completions', type: 'boolean', value: true, description: 'Install bash shell completions.') From 0c091bed769b43089191d5f62cdd81ef399cfd98 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Tue, 5 Feb 2019 08:35:00 -0500 Subject: [PATCH 10/52] cmd_workspace_gaps: fix double free on bad amount This fixes a double free in cmd_workspace_gaps when the amount given is invalid. The end pointer from strtol is part of the argument and should not be freed. Freeing the end pointer could result in a double free or bad free depending on whether or not the end pointer was at the start of the argument --- sway/commands/workspace.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index c5d6435a4..65a3f4075 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c @@ -76,7 +76,6 @@ static struct cmd_results *cmd_workspace_gaps(int argc, char **argv, char *end; int amount = strtol(argv[gaps_location + 2], &end, 10); if (strlen(end)) { - free(end); return cmd_results_new(CMD_FAILURE, expected); } From 2112f0aa2fcdf278dd3dccecc1a8261d3c97b44b Mon Sep 17 00:00:00 2001 From: Connor E <38229097+c-edw@users.noreply.github.com> Date: Tue, 5 Feb 2019 14:37:22 +0000 Subject: [PATCH 11/52] If validating the config, do it as early as possible. --- sway/main.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/sway/main.c b/sway/main.c index a3198af10..b3ffdd833 100644 --- a/sway/main.c +++ b/sway/main.c @@ -312,6 +312,18 @@ int main(int argc, char **argv) { wlr_log_init(WLR_ERROR, NULL); } + log_kernel(); + log_distro(); + log_env(); + detect_proprietary(allow_unsupported_gpu); + detect_raspi(); + + if (validate) { + bool valid = load_main_config(config_path, false, true); + free(config_path); + return valid ? 0 : 1; + } + if (optind < argc) { // Behave as IPC client if (optind != 1) { sway_log(SWAY_ERROR, "Don't use options with the IPC client"); @@ -334,11 +346,6 @@ int main(int argc, char **argv) { return 1; } - log_kernel(); - log_distro(); - detect_proprietary(allow_unsupported_gpu); - detect_raspi(); - if (!drop_permissions()) { server_fini(&server); exit(EXIT_FAILURE); @@ -359,12 +366,6 @@ int main(int argc, char **argv) { } ipc_init(&server); - log_env(); - - if (validate) { - bool valid = load_main_config(config_path, false, true); - return valid ? 0 : 1; - } setenv("WAYLAND_DISPLAY", server.socket, true); if (!load_main_config(config_path, false, false)) { From cc5139d52ace3bbfa8fd706fe408551c11766f4c Mon Sep 17 00:00:00 2001 From: Connor E <38229097+c-edw@users.noreply.github.com> Date: Tue, 5 Feb 2019 15:39:22 +0000 Subject: [PATCH 12/52] Initialize server so input manager is available. --- sway/main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sway/main.c b/sway/main.c index b3ffdd833..67d0f7992 100644 --- a/sway/main.c +++ b/sway/main.c @@ -318,12 +318,6 @@ int main(int argc, char **argv) { detect_proprietary(allow_unsupported_gpu); detect_raspi(); - if (validate) { - bool valid = load_main_config(config_path, false, true); - free(config_path); - return valid ? 0 : 1; - } - if (optind < argc) { // Behave as IPC client if (optind != 1) { sway_log(SWAY_ERROR, "Don't use options with the IPC client"); @@ -365,6 +359,12 @@ int main(int argc, char **argv) { return 1; } + if (validate) { + bool valid = load_main_config(config_path, false, true); + free(config_path); + return valid ? 0 : 1; + } + ipc_init(&server); setenv("WAYLAND_DISPLAY", server.socket, true); From d4e49a49ebea61b2e078a494eb94f02b03a6a1cf Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Tue, 5 Feb 2019 14:13:27 -0500 Subject: [PATCH 13/52] output_cmd_background: fix no file + valid mode If output_cmd_background is given a valid mode as the first argument, then there is no file given and an error should be returned. join_args should not be called with an argc of zero since it sets the last character to the null terminator. With an argc of zero, the length is zero causing a heap buffer overflow when setting the byte before the start of argv to '\0'. This probably will not ever generate a segfault, but may cause data corruption to whatever is directly before it in memory. To make other such cases easier to detect, this also adds a sway_assert in join_args when argc is zero. --- common/stringop.c | 3 +++ sway/commands/output/background.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/common/stringop.c b/common/stringop.c index 8af0d60fa..709be6842 100644 --- a/common/stringop.c +++ b/common/stringop.c @@ -258,6 +258,9 @@ int unescape_string(char *string) { } char *join_args(char **argv, int argc) { + if (!sway_assert(argc > 0, "argc should be positive")) { + return NULL; + } int len = 0, i; for (i = 0; i < argc; ++i) { len += strlen(argv[i]) + 1; diff --git a/sway/commands/output/background.c b/sway/commands/output/background.c index f65904bb8..5a15ed0fc 100644 --- a/sway/commands/output/background.c +++ b/sway/commands/output/background.c @@ -61,6 +61,9 @@ struct cmd_results *output_cmd_background(int argc, char **argv) { return cmd_results_new(CMD_INVALID, "Missing background scaling mode."); } + if (j == 0) { + return cmd_results_new(CMD_INVALID, "Missing background file"); + } wordexp_t p = {0}; char *src = join_args(argv, j); From 48511c3b35be8251517ab50ceea6dd2b33c32b86 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 5 Feb 2019 19:07:01 +0100 Subject: [PATCH 14/52] Fix close_popups for xdg-shell wlr_xdg_popup_destroy will destroy popups, so we need to walk the tree carefully. It's enough to just destroy all direct children, since destroying the parent will also destroy all children. --- sway/desktop/xdg_shell.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 152bd26f0..ce6fe41a1 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -236,19 +236,11 @@ static void _close(struct sway_view *view) { } } -static void close_popups_iterator(struct wlr_surface *surface, - int sx, int sy, void *data) { - struct wlr_xdg_surface *xdg_surface = - wlr_xdg_surface_from_wlr_surface(surface); - if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP - && xdg_surface->popup) { - wlr_xdg_popup_destroy(xdg_surface); - } -} - static void close_popups(struct sway_view *view) { - wlr_xdg_surface_for_each_popup(view->wlr_xdg_surface, - close_popups_iterator, NULL); + struct wlr_xdg_popup *popup, *tmp; + wl_list_for_each_safe(popup, tmp, &view->wlr_xdg_surface->popups, link) { + wlr_xdg_popup_destroy(popup->base); + } } static void destroy(struct sway_view *view) { From d2d2fc545ac706683a2da0118ec1c4842ed87d7f Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Tue, 5 Feb 2019 22:06:42 -0500 Subject: [PATCH 15/52] load_main_config: add realpath to config_chain Since `load_include_config` compares against the realpath of a config file when checking if a config has already been added, the main config's realpath has to be added to the config_chain. --- sway/config.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sway/config.c b/sway/config.c index 0c23fad84..18fb69d97 100644 --- a/sway/config.c +++ b/sway/config.c @@ -379,6 +379,14 @@ bool load_main_config(const char *file, bool is_active, bool validating) { path = get_config_path(); } + char *real_path = realpath(path, NULL); + if (real_path == NULL) { + sway_log(SWAY_DEBUG, "%s not found.", path); + free(path); + return false; + } + free(path); + struct sway_config *old_config = config; config = calloc(1, sizeof(struct sway_config)); if (!config) { @@ -401,8 +409,8 @@ bool load_main_config(const char *file, bool is_active, bool validating) { input_manager_reset_all_inputs(); } - config->current_config_path = path; - list_add(config->config_chain, path); + config->current_config_path = real_path; + list_add(config->config_chain, real_path); config->reading = true; @@ -454,7 +462,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) { } */ - success = success && load_config(path, config, + success = success && load_config(real_path, config, &config->swaynag_config_errors); if (validating) { From 6ade4bd7dd1cc5eed68842b407aa3f690b1f8e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 6 Feb 2019 15:16:30 +0100 Subject: [PATCH 16/52] ipc_has_event_listeners: fix inverted check of subscribed_events subscribed_events is a bit mask, with each *set* bit representing an event the client has subscribed to. --- sway/ipc-server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/ipc-server.c b/sway/ipc-server.c index eb6f159d6..df57cba51 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -264,7 +264,7 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { static bool ipc_has_event_listeners(enum ipc_command_type event) { for (int i = 0; i < ipc_client_list->length; i++) { struct ipc_client *client = ipc_client_list->items[i]; - if ((client->subscribed_events & event_mask(event)) == 0) { + if ((client->subscribed_events & event_mask(event)) != 0) { return true; } } From a2f661dceb5baa20bd5d329fbb6fb2d75a4a09f8 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Wed, 6 Feb 2019 13:18:46 -0500 Subject: [PATCH 17/52] Clarify error for options and positional args When both options and positional arguments are given, sway would print the error `Don't use options with the IPC client`. Over the past several months, it seems like users are including this error message in issues instead of a debug log due to not understanding that the error message means there is an issue with their command. This makes the error message more verbose and will hopefully make it so more users understand that the message is not a bug in sway, but with the command used. --- sway/main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sway/main.c b/sway/main.c index 67d0f7992..12f92bd80 100644 --- a/sway/main.c +++ b/sway/main.c @@ -320,7 +320,13 @@ int main(int argc, char **argv) { if (optind < argc) { // Behave as IPC client if (optind != 1) { - sway_log(SWAY_ERROR, "Don't use options with the IPC client"); + sway_log(SWAY_ERROR, + "Detected both options and positional arguments. If you " + "are trying to use the IPC client, options are not " + "supported. Otherwise, check the provided arguments for " + "issues. See `man 1 sway` or `sway -h` for usage. If you " + "are trying to generate a debug log, use " + "`sway -d 2>sway.log`."); exit(EXIT_FAILURE); } if (!drop_permissions()) { From 8229814e7a8122b022e5f92fb4d925b00d0d4b1c Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Thu, 7 Feb 2019 02:16:38 -0500 Subject: [PATCH 18/52] load_main_config: use given path, store realpath Since `load_include_config` compares against the realpath of a config file when checking if a config has already been added, the main config's realpath has to be added to the config_chain. However, includes from the main config should be processed relative to the path given to allow for symbolic links. This stores the realpath in `config->config_chain`, but uses the given path for all other operations. --- sway/config.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sway/config.c b/sway/config.c index 18fb69d97..ae8d11e35 100644 --- a/sway/config.c +++ b/sway/config.c @@ -385,7 +385,6 @@ bool load_main_config(const char *file, bool is_active, bool validating) { free(path); return false; } - free(path); struct sway_config *old_config = config; config = calloc(1, sizeof(struct sway_config)); @@ -409,7 +408,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) { input_manager_reset_all_inputs(); } - config->current_config_path = real_path; + config->current_config_path = path; list_add(config->config_chain, real_path); config->reading = true; @@ -462,7 +461,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) { } */ - success = success && load_config(real_path, config, + success = success && load_config(path, config, &config->swaynag_config_errors); if (validating) { From 32f790bd15e1a96f214ac2783bf66837dc0e9682 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Thu, 7 Feb 2019 01:52:58 -0500 Subject: [PATCH 19/52] seat_configure_tablet_tool: configure xcursor Since a tablet tool provides the WL_SEAT_CAPABILITY_POINTER capability, sway will attempt to use the xcursor manager to set a cursor image. If the tablet tool was the first (and possibly only) device to provide the capability for the seat, the xcursor manager was not being configured before attempting to set a cursor image. This was due to `seat_configure_xcursor` only being called in `seat_configure_pointer`. Since the xcursor manager was NULL in this case, it would cause a segfault when attempting to set a cursor image. This adds a call to `seat_configure_xcursor` in `seat_configure_tablet_tool` to ensure that the seat has a xcursor manager. --- sway/input/seat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sway/input/seat.c b/sway/input/seat.c index d159da224..18664d7cb 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -525,6 +525,7 @@ static void seat_configure_touch(struct sway_seat *seat, static void seat_configure_tablet_tool(struct sway_seat *seat, struct sway_seat_device *sway_device) { + seat_configure_xcursor(seat); wlr_cursor_attach_input_device(seat->cursor->cursor, sway_device->input_device->wlr_device); seat_apply_input_config(seat, sway_device); From 4339ba6424ddb41e16a4a0674ecdd0dabbf68ab4 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Wed, 6 Feb 2019 22:00:29 -0500 Subject: [PATCH 20/52] bar_cmd_modifier: add support for none sway-bar(5) documents `modifier none`, which comes from i3. This implements the functionality for `modifier none` since it was not previously implemented. The bar modifier toggles visibility of the bar when the bar mode is set to hide. When the bar modifier is set to `none`, the ability to toggle visibility of the bar will be disabled. --- sway/commands/bar/modifier.c | 29 ++++++++++++++++++----------- sway/input/keyboard.c | 3 ++- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/sway/commands/bar/modifier.c b/sway/commands/bar/modifier.c index c95250d11..d25d01d4b 100644 --- a/sway/commands/bar/modifier.c +++ b/sway/commands/bar/modifier.c @@ -15,19 +15,26 @@ struct cmd_results *bar_cmd_modifier(int argc, char **argv) { } uint32_t mod = 0; - list_t *split = split_string(argv[0], "+"); - for (int i = 0; i < split->length; ++i) { - uint32_t tmp_mod; - if ((tmp_mod = get_modifier_mask_by_name(split->items[i])) > 0) { - mod |= tmp_mod; - } else { - error = cmd_results_new(CMD_INVALID, - "Unknown modifier '%s'", (char *)split->items[i]); - list_free_items_and_destroy(split); - return error; + if (strcmp(argv[0], "none") != 0) { + list_t *split = split_string(argv[0], "+"); + for (int i = 0; i < split->length; ++i) { + uint32_t tmp_mod; + if ((tmp_mod = get_modifier_mask_by_name(split->items[i])) > 0) { + mod |= tmp_mod; + } else if (strcmp(split->items[i], "none") == 0) { + error = cmd_results_new(CMD_INVALID, + "none cannot be used along with other modifiers"); + list_free_items_and_destroy(split); + return error; + } else { + error = cmd_results_new(CMD_INVALID, + "Unknown modifier '%s'", (char *)split->items[i]); + list_free_items_and_destroy(split); + return error; + } } + list_free_items_and_destroy(split); } - list_free_items_and_destroy(split); config->current_bar->modifier = mod; sway_log(SWAY_DEBUG, "Show/Hide the bar when pressing '%s' in hide mode.", argv[0]); diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 12c57366c..efd27f70d 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -425,7 +425,8 @@ static void determine_bar_visibility(uint32_t modifiers) { for (int i = 0; i < config->bars->length; ++i) { struct bar_config *bar = config->bars->items[i]; if (strcmp(bar->mode, bar->hidden_state) == 0) { // both are "hide" - bool should_be_visible = (~modifiers & bar->modifier) == 0; + bool should_be_visible = + bar->modifier != 0 && (~modifiers & bar->modifier) == 0; if (bar->visible_by_modifier != should_be_visible) { bar->visible_by_modifier = should_be_visible; ipc_event_bar_state_update(bar); From 243d5a3a435c2786ecfa305e30fbca658e1861ff Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Fri, 8 Feb 2019 22:29:35 -0500 Subject: [PATCH 21/52] container_at_stacked: skip titles when zero pixels It is possible to make the title bars have a zero pixel height while stacked, by using a blank font and no padding. This causes a division by zero when attempting to calculate the child index in container_at_stacked, which then results in a segfault when attempting to access the child at that bad index (INT_MIN). This just skips the check to see if the cursor is over a title bar of a child of a stacked container when the title bar height is zero since there will be no title bars. --- sway/tree/container.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sway/tree/container.c b/sway/tree/container.c index 0ebdc51de..9358dad76 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -251,10 +251,12 @@ static struct sway_container *container_at_stacked(struct sway_node *parent, // Title bars int title_height = container_titlebar_height(); - int child_index = (ly - box.y) / title_height; - if (child_index < children->length) { - struct sway_container *child = children->items[child_index]; - return child; + if (title_height > 0) { + int child_index = (ly - box.y) / title_height; + if (child_index < children->length) { + struct sway_container *child = children->items[child_index]; + return child; + } } // Surfaces From 95e16bb744679296aaab5c0e9b8f3995fb2b4be4 Mon Sep 17 00:00:00 2001 From: Rouven Czerwinski Date: Sun, 10 Feb 2019 17:04:12 +0100 Subject: [PATCH 22/52] fix double free for mode toggle if bar was invisible If the bar was set to "invisible" and subsequently "toggle" was send twice, the new mode was never set and the bar->mode was double freed. Fix this by not requiring the bar->mode to be "hide" and instead show it unconditionally, because it was either hidden or invisible. Fixes #3637 --- sway/commands/bar/mode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/commands/bar/mode.c b/sway/commands/bar/mode.c index d89ddf24e..68a80abf6 100644 --- a/sway/commands/bar/mode.c +++ b/sway/commands/bar/mode.c @@ -11,7 +11,7 @@ static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *mode if (strcasecmp("toggle", mode) == 0 && !config->reading) { if (strcasecmp("dock", bar->mode) == 0) { bar->mode = strdup("hide"); - } else if (strcasecmp("hide", bar->mode) == 0) { + } else{ bar->mode = strdup("dock"); } } else if (strcasecmp("dock", mode) == 0) { From 062da8eae76710e7766dceef7556261429123585 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sun, 10 Feb 2019 12:36:30 -0500 Subject: [PATCH 23/52] input/keyboard: respect solo repeat_{rate,delay} If `repeat_rate` or `repeat_delay` is set without the other being set, the default was being used for both. This changes the logic to respect the value given and use the default for the other when only one is set. --- sway/input/keyboard.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index efd27f70d..00fc6a13f 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -549,13 +549,17 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) { wlr_keyboard_led_update(wlr_device->keyboard, leds); } - if (input_config && input_config->repeat_delay != INT_MIN - && input_config->repeat_rate != INT_MIN) { - wlr_keyboard_set_repeat_info(wlr_device->keyboard, - input_config->repeat_rate, input_config->repeat_delay); - } else { - wlr_keyboard_set_repeat_info(wlr_device->keyboard, 25, 600); + int repeat_rate = 25; + if (input_config && input_config->repeat_rate != INT_MIN) { + repeat_rate = input_config->repeat_rate; } + int repeat_delay = 600; + if (input_config && input_config->repeat_delay != INT_MIN) { + repeat_delay = input_config->repeat_delay; + } + wlr_keyboard_set_repeat_info(wlr_device->keyboard, repeat_rate, + repeat_delay); + xkb_context_unref(context); struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat; wlr_seat_set_keyboard(seat, wlr_device); From 4e27785980d2d4bb342019e5e31c4441076bf603 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sun, 10 Feb 2019 15:23:50 -0500 Subject: [PATCH 24/52] view: remove pointer constraints on unmap If the view has any pointer constraints, ensure they are removed before the view is unmapped and the surface is no longer tied to the view. --- sway/tree/view.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sway/tree/view.c b/sway/tree/view.c index 612cf96ae..943734dc7 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -664,6 +664,13 @@ void view_unmap(struct sway_view *view) { struct sway_seat *seat; wl_list_for_each(seat, &server.input->seats, link) { seat->cursor->image_surface = NULL; + if (seat->cursor->active_constraint) { + struct wlr_surface *constrain_surface = + seat->cursor->active_constraint->surface; + if (view_from_wlr_surface(constrain_surface) == view) { + sway_cursor_constrain(seat->cursor, NULL); + } + } seat_consider_warp_to_focus(seat); } From a4d7ee1923e5847829367d741bea8c954034c312 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sun, 10 Feb 2019 15:37:24 -0500 Subject: [PATCH 25/52] ipc: handle unnamed xkb_active_layout_name If the active xkb_layout does not have a name, use `NULL` instead of `json_object_new_string(NULL)`. This also makes it so swaymsg will pretty print this as `(unnamed)`. --- sway/ipc-json.c | 2 +- swaymsg/main.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sway/ipc-json.c b/sway/ipc-json.c index e10989420..23016dbd5 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -597,7 +597,7 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) { const char *layout = xkb_keymap_layout_get_name(keymap, layout_idx); json_object_object_add(object, "xkb_active_layout_name", - json_object_new_string(layout)); + layout ? json_object_new_string(layout) : NULL); break; } } diff --git a/swaymsg/main.c b/swaymsg/main.c index c84f5671f..716d2d2ed 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -135,8 +135,8 @@ static void pretty_print_input(json_object *i) { json_object_get_int(vendor)); if (json_object_object_get_ex(i, "xkb_active_layout_name", &kbdlayout)) { - printf(" Active Keyboard Layout: %s\n", - json_object_get_string(kbdlayout)); + const char *layout = json_object_get_string(kbdlayout); + printf(" Active Keyboard Layout: %s\n", layout ? layout : "(unnamed)"); } if (json_object_object_get_ex(i, "libinput_send_events", &events)) { From a5a189cc73941c41f7486ba6bb561ca80dcea601 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Mon, 11 Feb 2019 03:26:12 -0500 Subject: [PATCH 26/52] fix misc memory leaks This fixes a few misc memory leaks reported by asan: - Items of `config->config_chain` are now freed instead of just the list itself - `bar->swaybar_command` is now freed - The result returned by a seat subcommand is now returned instead of leaked --- sway/commands/seat.c | 2 +- sway/config.c | 2 +- sway/config/bar.c | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sway/commands/seat.c b/sway/commands/seat.c index 5b23dcc6a..aa36ba955 100644 --- a/sway/commands/seat.c +++ b/sway/commands/seat.c @@ -50,5 +50,5 @@ struct cmd_results *cmd_seat(int argc, char **argv) { } config->handler_context.seat_config = NULL; - return cmd_results_new(CMD_SUCCESS, NULL); + return res ? res : cmd_results_new(CMD_SUCCESS, NULL); } diff --git a/sway/config.c b/sway/config.c index ae8d11e35..cd2d18a27 100644 --- a/sway/config.c +++ b/sway/config.c @@ -118,7 +118,7 @@ void free_config(struct sway_config *config) { } list_free(config->no_focus); list_free(config->active_bar_modifiers); - list_free(config->config_chain); + list_free_items_and_destroy(config->config_chain); list_free(config->command_policies); list_free(config->feature_policies); list_free(config->ipc_policies); diff --git a/sway/config/bar.c b/sway/config/bar.c index bafef307c..2e28fa1ef 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c @@ -46,6 +46,7 @@ void free_bar_config(struct bar_config *bar) { free(bar->position); free(bar->hidden_state); free(bar->status_command); + free(bar->swaybar_command); free(bar->font); free(bar->separator_symbol); for (int i = 0; i < bar->bindings->length; i++) { From 40023d45a18abb0e177818fa60b8a359680eb3c3 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Mon, 11 Feb 2019 03:59:11 -0500 Subject: [PATCH 27/52] Abort early when XDG_RUNTIME_DIR is not set This aborts sway and displays an error message about XDG_RUNTIME_DIR not being set without initializing the wl_display or logging any other information. --- sway/main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sway/main.c b/sway/main.c index 12f92bd80..b118a1823 100644 --- a/sway/main.c +++ b/sway/main.c @@ -299,6 +299,14 @@ int main(int argc, char **argv) { } } + // Since wayland requires XDG_RUNTIME_DIR to be set, abort with just the + // clear error message (when not running as an IPC client). + if (!getenv("XDG_RUNTIME_DIR") && optind == argc) { + fprintf(stderr, + "XDG_RUNTIME_DIR is not set in the environment. Aborting.\n"); + exit(EXIT_FAILURE); + } + // As the 'callback' function for wlr_log is equivalent to that for // sway, we do not need to override it. if (debug) { From e4e579ea3687342d06915be0df0093987e0e0314 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sun, 10 Feb 2019 20:12:51 -0500 Subject: [PATCH 28/52] workspace_get_initial_output: handle focused layer When a layer surface is focused, `seat_get_focused_workspace` will be NULL. This changes `workspace_get_initial_output` to use output of the focus inactive. If the focus inactive is also NULL, then either the first output or the noop output will be used as fallbacks. --- sway/tree/workspace.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 8b3eb2ad2..b97809223 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -42,10 +42,16 @@ struct sway_output *workspace_get_initial_output(const char *name) { } } } - // Otherwise put it on the focused output + // Otherwise try to put it on the focused output struct sway_seat *seat = input_manager_current_seat(); - struct sway_workspace *focus = seat_get_focused_workspace(seat); - return focus->output; + struct sway_node *focus = seat_get_focus_inactive(seat, &root->node); + if (focus && focus->type == N_WORKSPACE) { + return focus->sway_workspace->output; + } else if (focus && focus->type == N_CONTAINER) { + return focus->sway_container->workspace->output; + } + // Fallback to the first output or noop output for headless + return root->outputs->length ? root->outputs->items[0] : root->noop_output; } static void prevent_invalid_outer_gaps(struct sway_workspace *ws) { From 06e03ed8784fe2048e48909af47c80a55d201a81 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 12 Feb 2019 22:55:23 +0100 Subject: [PATCH 29/52] Rebase cursor when a layer surface maps Also removes an extraneous arrange_outputs call, it's already called if necessary in arrange_layers. Updates https://github.com/swaywm/sway/issues/3080 --- include/sway/input/cursor.h | 1 + sway/desktop/layer_shell.c | 7 +++++-- sway/desktop/transaction.c | 9 +-------- sway/input/cursor.c | 13 +++++++++++++ 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index 072a56ca1..98eb4679b 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h @@ -72,6 +72,7 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat); * This chooses a cursor icon and sends a motion event to the surface. */ void cursor_rebase(struct sway_cursor *cursor); +void cursor_rebase_all(void); void cursor_handle_activity(struct sway_cursor *cursor); void cursor_unhide(struct sway_cursor *cursor); diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index de8db75df..0767247c4 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -6,7 +6,9 @@ #include #include #include +#include "log.h" #include "sway/desktop/transaction.h" +#include "sway/input/cursor.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "sway/layers.h" @@ -14,7 +16,6 @@ #include "sway/server.h" #include "sway/tree/arrange.h" #include "sway/tree/workspace.h" -#include "log.h" static void apply_exclusive(struct wlr_box *usable_area, uint32_t anchor, int32_t exclusive, @@ -302,6 +303,8 @@ static void unmap(struct sway_layer_surface *sway_layer) { if (seat->focused_layer == sway_layer->layer_surface) { seat_set_focus_layer(seat, NULL); } + + cursor_rebase_all(); } static void handle_destroy(struct wl_listener *listener, void *data) { @@ -321,7 +324,6 @@ static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_output *output = sway_layer->layer_surface->output->data; if (output != NULL) { arrange_layers(output); - arrange_output(output); transaction_commit_dirty(); } wl_list_remove(&sway_layer->output_destroy.link); @@ -339,6 +341,7 @@ static void handle_map(struct wl_listener *listener, void *data) { // TODO: send enter to subsurfaces and popups wlr_surface_send_enter(sway_layer->layer_surface->surface, sway_layer->layer_surface->output); + cursor_rebase_all(); } static void handle_unmap(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index e0c3a5d1e..4098ed22c 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -314,14 +314,7 @@ static void transaction_apply(struct sway_transaction *transaction) { node->instruction = NULL; } - if (root->outputs->length) { - struct sway_seat *seat; - wl_list_for_each(seat, &server.input->seats, link) { - if (!seat_doing_seatop(seat)) { - cursor_rebase(seat->cursor); - } - } - } + cursor_rebase_all(); } static void transaction_commit(struct sway_transaction *transaction); diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 1bf548db7..263b6758b 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -283,6 +283,19 @@ void cursor_rebase(struct sway_cursor *cursor) { cursor_do_rebase(cursor, time_msec, cursor->previous.node, surface, sx, sy); } +void cursor_rebase_all(void) { + if (!root->outputs->length) { + return; + } + + struct sway_seat *seat; + wl_list_for_each(seat, &server.input->seats, link) { + if (!seat_doing_seatop(seat)) { + cursor_rebase(seat->cursor); + } + } +} + static int hide_notify(void *data) { struct sway_cursor *cursor = data; wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0); From e50e1fe058f51ac14d4e9130ca1270e3b569cc47 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 12 Feb 2019 23:13:24 +0100 Subject: [PATCH 30/52] Fix --version when building from tarball --- meson.build | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index c50fab176..2336a1489 100644 --- a/meson.build +++ b/meson.build @@ -128,12 +128,13 @@ endif add_project_arguments('-DSYSCONFDIR="/@0@"'.format(join_paths(prefix, sysconfdir)), language : 'c') +version = '"@0@"'.format(meson.project_version()) if git.found() - git_commit_hash = run_command([git.path(), 'describe', '--always', '--tags']).stdout().strip() - git_branch = run_command([git.path(), 'rev-parse', '--abbrev-ref', 'HEAD']).stdout().strip() - version = '"@0@ (" __DATE__ ", branch \'@1@\')"'.format(git_commit_hash, git_branch) -else - version = '"@0@"'.format(meson.project_version()) + git_commit_hash = run_command([git.path(), 'describe', '--always', '--tags']) + git_branch = run_command([git.path(), 'rev-parse', '--abbrev-ref', 'HEAD']) + if git_commit_hash.returncode() == 0 and git_branch.returncode() == 0 + version = '"@0@ (" __DATE__ ", branch \'@1@\')"'.format(git_commit_hash.stdout().strip(), git_branch.stdout().strip()) + endif endif add_project_arguments('-DSWAY_VERSION=@0@'.format(version), language: 'c') From 59b3c4d06e2941f08ca60e25a223c0e52b83a00e Mon Sep 17 00:00:00 2001 From: athrungithub Date: Mon, 11 Feb 2019 19:10:28 -0300 Subject: [PATCH 31/52] Don't remove from scratchpad on move to workspace on move container window to another workspace, not remove from scratchpad. --- sway/commands/move.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sway/commands/move.c b/sway/commands/move.c index 8c3afae97..16f8cdb6f 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -516,7 +516,6 @@ static struct cmd_results *cmd_move_container(int argc, char **argv) { // move container if (container->scratchpad) { - root_scratchpad_remove_container(container); root_scratchpad_show(container); } switch (destination->type) { From d126410de18aaacf83ea72753e5eb066fc338997 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Wed, 13 Feb 2019 03:01:06 -0500 Subject: [PATCH 32/52] cursor: relative-pointer-v1 time is usec In handle_cursor_motion, the timestamp passed to `wlr_relative_pointer_manager_v1_send_relative_motion` should be microseconds (not milliseconds) according to relative-pointer-v1 spec. --- sway/input/cursor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 263b6758b..5ede6e74f 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -421,8 +421,8 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) { wlr_relative_pointer_manager_v1_send_relative_motion( server.relative_pointer_manager, - cursor->seat->wlr_seat, event->time_msec, dx, dy, - dx_unaccel, dy_unaccel); + cursor->seat->wlr_seat, (uint64_t)event->time_msec * 1000, + dx, dy, dx_unaccel, dy_unaccel); struct wlr_surface *surface = NULL; double sx, sy; From ad34837ddaab418fc4d5aed61370227d634912cc Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Tue, 12 Feb 2019 23:21:11 -0500 Subject: [PATCH 33/52] subsurface_get_root_coords: break on NULL It is possible for `wlr_surface_is_subsurface` to return true, but `wlr_surface_from_wlr_surface` to be NULL. This adds a NULL check to the value returned by `wlr_surface_from_wlr_surface` and breaks out of the while loop in `subsurface_get_root_coords`. --- sway/tree/view.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sway/tree/view.c b/sway/tree/view.c index 943734dc7..ca13def72 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -708,6 +708,9 @@ static void subsurface_get_root_coords(struct sway_view_child *child, while (surface && wlr_surface_is_subsurface(surface)) { struct wlr_subsurface *subsurface = wlr_subsurface_from_wlr_surface(surface); + if (subsurface == NULL) { + break; + } *root_sx += subsurface->current.x; *root_sy += subsurface->current.y; surface = subsurface->parent; From 1d4b995c0f290c392c8a0d3e1e293c76bf82c3d9 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Wed, 13 Feb 2019 14:32:47 -0500 Subject: [PATCH 34/52] seatop_move_tiling: use tab/stack parent not self When moving a descendant of a tabbed or stacked container, it is possible for the target node to be the node being moved. This causes a segfault in `handle_finish` since the node will be detached and then attempted to be attached to it own parent, which is NULL due to the detach. In this case, the target node should not be set to the node being moved, but the parent of the node. This also allows for a descendant of a tabbed or stacked container to be dragged out of the tabs/stacks and to be a sibling of the tabbbed/stacked container, which was not previously possible. --- sway/input/seatop_move_tiling.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sway/input/seatop_move_tiling.c b/sway/input/seatop_move_tiling.c index 8b541f80d..422a4aa2c 100644 --- a/sway/input/seatop_move_tiling.c +++ b/sway/input/seatop_move_tiling.c @@ -150,6 +150,9 @@ static void handle_motion_postthreshold(struct sway_seat *seat) { } if (edge) { e->target_node = node_get_parent(&con->node); + if (e->target_node == &e->con->node) { + e->target_node = node_get_parent(e->target_node); + } e->target_edge = edge; node_get_box(e->target_node, &e->drop_box); resize_box(&e->drop_box, edge, DROP_LAYOUT_BORDER); From ee236afb43c8da4a65b31edad0b470d4099b3cd6 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Wed, 13 Feb 2019 23:46:20 -0500 Subject: [PATCH 35/52] seat: allow tree focus changes while layer focused This allows the focused inactive tree node and visible workspaces to be changed while a surface layer has focus. The layer temporarily loses focus, the tree focus changes, and the layer gets refocused. --- sway/input/seat.c | 4 ++++ sway/tree/workspace.c | 14 ++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/sway/input/seat.c b/sway/input/seat.c index 18664d7cb..df48b7518 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -725,6 +725,10 @@ void seat_set_raw_focus(struct sway_seat *seat, struct sway_node *node) { void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { if (seat->focused_layer) { + struct wlr_layer_surface_v1 *layer = seat->focused_layer; + seat_set_focus_layer(seat, NULL); + seat_set_focus(seat, node); + seat_set_focus_layer(seat, layer); return; } diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index b97809223..cda6caf7c 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -451,9 +451,15 @@ struct sway_workspace *workspace_prev(struct sway_workspace *current) { bool workspace_switch(struct sway_workspace *workspace, bool no_auto_back_and_forth) { struct sway_seat *seat = input_manager_current_seat(); - struct sway_workspace *active_ws = seat_get_focused_workspace(seat); + struct sway_workspace *active_ws = NULL; + struct sway_node *focus = seat_get_focus_inactive(seat, &root->node); + if (focus && focus->type == N_WORKSPACE) { + active_ws = focus->sway_workspace; + } else if (focus && focus->type == N_CONTAINER) { + active_ws = focus->sway_container->workspace; + } - if (!no_auto_back_and_forth && config->auto_back_and_forth + if (!no_auto_back_and_forth && config->auto_back_and_forth && active_ws && active_ws == workspace && seat->prev_workspace_name) { struct sway_workspace *new_ws = workspace_by_name(seat->prev_workspace_name); @@ -462,9 +468,9 @@ bool workspace_switch(struct sway_workspace *workspace, workspace_create(NULL, seat->prev_workspace_name); } - if (!seat->prev_workspace_name || + if (active_ws && (!seat->prev_workspace_name || (strcmp(seat->prev_workspace_name, active_ws->name) - && active_ws != workspace)) { + && active_ws != workspace))) { free(seat->prev_workspace_name); seat->prev_workspace_name = malloc(strlen(active_ws->name) + 1); if (!seat->prev_workspace_name) { From f0e8c68ca77698f741d2117f6391946b5266c1ff Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Wed, 13 Feb 2019 22:38:30 -0500 Subject: [PATCH 36/52] seatop_move_tiling: do not move to descendant In seatop_move_tiling, it is possible to cause a stack overflow by dragging a container into one of its descendants. This disables the ability to move into a descendant. --- sway/input/seatop_move_tiling.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sway/input/seatop_move_tiling.c b/sway/input/seatop_move_tiling.c index 422a4aa2c..1e548f5ae 100644 --- a/sway/input/seatop_move_tiling.c +++ b/sway/input/seatop_move_tiling.c @@ -164,7 +164,8 @@ 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->surface || node == &e->con->node + || node_has_ancestor(node, &e->con->node)) { e->target_node = NULL; e->target_edge = WLR_EDGE_NONE; return; From 8d708b8e1d804198a2c6a53342def6d1505845db Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Fri, 15 Feb 2019 03:01:19 -0500 Subject: [PATCH 37/52] apply_output_config: dpms on before modeset On the DRM backend, if an output is dpms'd off and a different output is hotplugged, the CRTC for the output is reclaimed. When modesetting an output without a CRTC, a CRTC will not be given to an output that is not desired to be enabled. This splits setting the dpms state in apply_output_config. If the output should be dpms on, the it is enabled before attempting to modeset. Otherwise, it is dpms'd off after setting everything else. This also adds DPMS_ON to the default output configs. --- sway/config/output.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/sway/config/output.c b/sway/config/output.c index 970764b03..f1a06379b 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -199,6 +199,11 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { return true; } + if (oc && oc->dpms_state == DPMS_ON) { + sway_log(SWAY_DEBUG, "Turning on screen"); + wlr_output_enable(wlr_output, true); + } + bool modeset_success; if (oc && oc->width > 0 && oc->height > 0) { sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f GHz)", oc->name, oc->width, @@ -263,19 +268,9 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { } } - if (oc) { - switch (oc->dpms_state) { - case DPMS_ON: - sway_log(SWAY_DEBUG, "Turning on screen"); - wlr_output_enable(wlr_output, true); - break; - case DPMS_OFF: - sway_log(SWAY_DEBUG, "Turning off screen"); - wlr_output_enable(wlr_output, false); - break; - case DPMS_IGNORE: - break; - } + if (oc && oc->dpms_state == DPMS_OFF) { + sway_log(SWAY_DEBUG, "Turning off screen"); + wlr_output_enable(wlr_output, false); } return true; @@ -294,6 +289,7 @@ static void default_output_config(struct output_config *oc, oc->x = oc->y = -1; oc->scale = 1; oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; + oc->dpms_state = DPMS_ON; } static struct output_config *get_output_config(char *identifier, From 47abc45e867043b9144cc7a7181d08203d7ec4f2 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Thu, 14 Feb 2019 15:43:34 +0000 Subject: [PATCH 38/52] swaybar: prevent signal handler from firing during termination This prevents a heap-use-after-free crash when sway terminates. --- include/swaybar/bar.h | 2 ++ swaybar/bar.c | 6 +++--- swaybar/main.c | 14 +++++--------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h index 2d9ba0d9b..2518d5aa8 100644 --- a/include/swaybar/bar.h +++ b/include/swaybar/bar.h @@ -46,6 +46,8 @@ struct swaybar { #if HAVE_TRAY struct swaybar_tray *tray; #endif + + bool running; }; struct swaybar_output { diff --git a/swaybar/bar.c b/swaybar/bar.c index a1f7bfdb9..db1c12228 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -403,8 +404,7 @@ bool bar_setup(struct swaybar *bar, const char *socket_path) { static void display_in(int fd, short mask, void *data) { struct swaybar *bar = data; if (wl_display_dispatch(bar->display) == -1) { - bar_teardown(bar); - exit(0); + bar->running = false; } } @@ -439,7 +439,7 @@ void bar_run(struct swaybar *bar) { loop_add_fd(bar->eventloop, bar->tray->fd, POLLIN, tray_in, bar->tray->bus); } #endif - while (1) { + while (bar->running) { errno = 0; if (wl_display_flush(bar->display) == -1 && errno != EAGAIN) { break; diff --git a/swaybar/main.c b/swaybar/main.c index 4ef746290..108b16e91 100644 --- a/swaybar/main.c +++ b/swaybar/main.c @@ -11,13 +11,7 @@ static struct swaybar swaybar; void sig_handler(int signal) { - bar_teardown(&swaybar); - exit(0); -} - -void sway_terminate(int code) { - bar_teardown(&swaybar); - exit(code); + swaybar.running = false; } int main(int argc, char **argv) { @@ -93,8 +87,6 @@ int main(int argc, char **argv) { } } - signal(SIGTERM, sig_handler); - if (!bar_setup(&swaybar, socket_path)) { free(socket_path); return 1; @@ -102,6 +94,10 @@ int main(int argc, char **argv) { free(socket_path); + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + + swaybar.running = true; bar_run(&swaybar); bar_teardown(&swaybar); return 0; From 1a46da7fcfd4c6022a71a4466a9637d0a338aa62 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Fri, 15 Feb 2019 15:15:45 +0000 Subject: [PATCH 39/52] tray: use correct parameter to set bus slot to floating Counter-intuitively, `sd_bus_slot_set_floating` expects 0 to set it to floating. --- swaybar/tray/host.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/swaybar/tray/host.c b/swaybar/tray/host.c index 215e1e722..451b08967 100644 --- a/swaybar/tray/host.c +++ b/swaybar/tray/host.c @@ -189,9 +189,9 @@ bool init_host(struct swaybar_host *host, char *protocol, goto error; } - sd_bus_slot_set_floating(reg_slot, 1); - sd_bus_slot_set_floating(unreg_slot, 1); - sd_bus_slot_set_floating(watcher_slot, 1); + sd_bus_slot_set_floating(reg_slot, 0); + sd_bus_slot_set_floating(unreg_slot, 0); + sd_bus_slot_set_floating(watcher_slot, 0); sway_log(SWAY_DEBUG, "Registered %s", host->service); return true; From b02198a0d14d8d58a85d357d94c801bad4c56764 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 16 Feb 2019 11:57:41 +0100 Subject: [PATCH 40/52] Disable unneeded wlroots subproject features --- meson.build | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 2336a1489..cfd77ce7e 100644 --- a/meson.build +++ b/meson.build @@ -60,7 +60,11 @@ rt = cc.find_library('rt') git = find_program('git', required: false) # Try first to find wlroots as a subproject, then as a system dependency -wlroots_proj = subproject('wlroots', required: false) +wlroots_proj = subproject( + 'wlroots', + default_options: ['rootston=disabled', 'examples=disabled'], + required: false, +) if wlroots_proj.found() wlroots = wlroots_proj.get_variable('wlroots') wlroots_conf = wlroots_proj.get_variable('conf_data') From c07d91ca96d9362f2dfe2757ddba31f3c812b63c Mon Sep 17 00:00:00 2001 From: Vincent Vanlaer Date: Fri, 15 Feb 2019 18:29:47 +0100 Subject: [PATCH 41/52] Check layout before getting pointer surface coords This fixes issues of clients at the edge of the screen, like swaybar, ignoring buttons. --- sway/input/cursor.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 5ede6e74f..170532bea 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -425,11 +425,12 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) { dx, dy, dx_unaccel, dy_unaccel); struct wlr_surface *surface = NULL; + struct sway_node *node = NULL; double sx, sy; - struct sway_node *node = node_at_coords(cursor->seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - if (cursor->active_constraint) { + node = node_at_coords(cursor->seat, + cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + if (cursor->active_constraint->surface != surface) { return; } @@ -445,8 +446,13 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) { } wlr_cursor_move(cursor->cursor, event->device, dx, dy); + + // Recalculate pointer location after layout checks + node = node_at_coords(cursor->seat, + cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + cursor_send_pointer_motion(cursor, event->time_msec, node, surface, - sx + dx, sy + dy); + sx, sy); transaction_commit_dirty(); } From 8dbd4b98f7b0c8c1c15fc7045b49a2957b993165 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Sat, 16 Feb 2019 11:01:15 +0000 Subject: [PATCH 42/52] tray: when a service is lost, remove all matching items Before, only the first matching item would be removed, which could leave stale items. --- swaybar/tray/watcher.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/swaybar/tray/watcher.c b/swaybar/tray/watcher.c index 381510717..432837d07 100644 --- a/swaybar/tray/watcher.c +++ b/swaybar/tray/watcher.c @@ -18,10 +18,6 @@ static int cmp_id(const void *item, const void *cmp_to) { return strcmp(item, cmp_to); } -static int cmp_service(const void *item, const void *cmp_to) { - return strncmp(item, cmp_to, strlen(cmp_to)); -} - static int handle_lost_service(sd_bus_message *msg, void *data, sd_bus_error *error) { char *service, *old_owner, *new_owner; @@ -33,18 +29,23 @@ static int handle_lost_service(sd_bus_message *msg, if (!*new_owner) { struct swaybar_watcher *watcher = data; - int idx = list_seq_find(watcher->items, - using_standard_protocol(watcher) ? cmp_id : cmp_service, service); - if (idx != -1) { + for (int idx = 0; idx < watcher->items->length; ++idx) { char *id = watcher->items->items[idx]; - sway_log(SWAY_DEBUG, "Unregistering Status Notifier Item '%s'", id); - list_del(watcher->items, idx); - sd_bus_emit_signal(watcher->bus, obj_path, watcher->interface, - "StatusNotifierItemUnregistered", "s", id); - free(id); + int cmp_res = using_standard_protocol(watcher) ? + cmp_id(id, service) : strncmp(id, service, strlen(service)); + if (cmp_res == 0) { + sway_log(SWAY_DEBUG, "Unregistering Status Notifier Item '%s'", id); + list_del(watcher->items, idx--); + sd_bus_emit_signal(watcher->bus, obj_path, watcher->interface, + "StatusNotifierItemUnregistered", "s", id); + free(id); + if (using_standard_protocol(watcher)) { + break; + } + } } - idx = list_seq_find(watcher->hosts, cmp_id, service); + int idx = list_seq_find(watcher->hosts, cmp_id, service); if (idx != -1) { sway_log(SWAY_DEBUG, "Unregistering Status Notifier Host '%s'", service); free(watcher->hosts->items[idx]); From 9ff59b7c6bbd46dcbaf5f516705f349a9138261c Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Sat, 16 Feb 2019 11:02:15 +0000 Subject: [PATCH 43/52] tray: fix memory leaks --- swaybar/tray/item.c | 6 +++++- swaybar/tray/watcher.c | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index 4262d6877..4fa6c97b5 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c @@ -299,6 +299,8 @@ void destroy_sni(struct swaybar_sni *sni) { return; } + cairo_surface_destroy(sni->icon); + sd_bus_slot_unref(sni->new_icon_slot); sd_bus_slot_unref(sni->new_attention_icon_slot); sd_bus_slot_unref(sni->new_status_slot); @@ -308,9 +310,11 @@ void destroy_sni(struct swaybar_sni *sni) { free(sni->path); free(sni->status); free(sni->icon_name); - free(sni->icon_pixmap); + list_free_items_and_destroy(sni->icon_pixmap); free(sni->attention_icon_name); + list_free_items_and_destroy(sni->attention_icon_pixmap); free(sni->menu); + free(sni->icon_theme_path); free(sni); } diff --git a/swaybar/tray/watcher.c b/swaybar/tray/watcher.c index 432837d07..951a05890 100644 --- a/swaybar/tray/watcher.c +++ b/swaybar/tray/watcher.c @@ -186,8 +186,8 @@ struct swaybar_watcher *create_watcher(char *protocol, sd_bus *bus) { goto error; } - sd_bus_slot_set_floating(signal_slot, 1); - sd_bus_slot_set_floating(vtable_slot, 1); + sd_bus_slot_set_floating(signal_slot, 0); + sd_bus_slot_set_floating(vtable_slot, 0); watcher->bus = bus; watcher->hosts = create_list(); From 19586ab768ad2a79cb8342d34e16b25105bc36bd Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sat, 16 Feb 2019 16:14:27 -0500 Subject: [PATCH 44/52] Fix reload freeze when not modsetting current mode This fixes the issue of the display freezing on reload with wlroots#1545. On master, all output configs are applied on reload. This may cause an output to have its config applied up to three times, instead of just once. The three cases are: output name, output identifier, and wildcard. Not only is this inefficient, but it can cause swaybg to be spawned and immediately killed. However, swaybg requires two roundtrips of wl_display (to obtain needed globals) before it enters its normal event loop. Modesetting will roundtrip the wl_display. Without modesetting, waitpid for killing swaybg could block infinitely due to swaybg being blocked by wl_display_roundtrip. This only configured an output once. It either uses the wildcard config or creates an empty wildcard config and applies that. This also fixes a bug where an output would not be reset when there is no output config to apply to it. --- include/sway/config.h | 2 ++ sway/config.c | 5 ++--- sway/config/output.c | 11 +++++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index 43ea77788..54cdcc908 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -586,6 +586,8 @@ struct output_config *store_output_config(struct output_config *oc); void apply_output_config_to_outputs(struct output_config *oc); +void reset_outputs(void); + void free_output_config(struct output_config *oc); int workspace_output_cmp_workspace(const void *a, const void *b); diff --git a/sway/config.c b/sway/config.c index cd2d18a27..206ca95cb 100644 --- a/sway/config.c +++ b/sway/config.c @@ -471,9 +471,8 @@ bool load_main_config(const char *file, bool is_active, bool validating) { } if (is_active) { - for (int i = 0; i < config->output_configs->length; i++) { - apply_output_config_to_outputs(config->output_configs->items[i]); - } + reset_outputs(); + config->reloading = false; if (config->swaynag_config_errors.pid > 0) { swaynag_show(&config->swaynag_config_errors); diff --git a/sway/config/output.c b/sway/config/output.c index f1a06379b..0f238715f 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -391,6 +391,17 @@ void apply_output_config_to_outputs(struct output_config *oc) { } } +void reset_outputs(void) { + struct output_config *oc = NULL; + int i = list_seq_find(config->output_configs, output_name_cmp, "*"); + if (i >= 0) { + oc = config->output_configs->items[i]; + } else { + oc = store_output_config(new_output_config("*")); + } + apply_output_config_to_outputs(oc); +} + void free_output_config(struct output_config *oc) { if (!oc) { return; From d2456c3b370a4b9206b3b05cdadc087265506f8a Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 16 Feb 2019 23:09:26 +0100 Subject: [PATCH 45/52] Remove unused header include/sway/tree/output.h --- include/sway/tree/output.h | 0 sway/tree/output.c | 1 - 2 files changed, 1 deletion(-) delete mode 100644 include/sway/tree/output.h diff --git a/include/sway/tree/output.h b/include/sway/tree/output.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/sway/tree/output.c b/sway/tree/output.c index 5a992f2db..138144a77 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -8,7 +8,6 @@ #include "sway/layers.h" #include "sway/output.h" #include "sway/tree/arrange.h" -#include "sway/tree/output.h" #include "sway/tree/workspace.h" #include "log.h" #include "util.h" From f120f70f5a1137358a5baf111fd77c0164849a47 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sat, 16 Feb 2019 17:42:56 -0500 Subject: [PATCH 46/52] sway-input.5: document wildcard and identifier troubleshooting This documents the wildcard character for both inputs and seats. There is also a tip added on trying the wildcard to verify a setting if the identifier does not appear to be working. --- sway/sway-input.5.scd | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd index 376e18338..8c3a8225f 100644 --- a/sway/sway-input.5.scd +++ b/sway/sway-input.5.scd @@ -8,6 +8,13 @@ sway-input - input configuration file and commands Sway allows for configuration of devices within the sway configuration file. To obtain a list of available device identifiers, run *swaymsg -t get_inputs*. +Settings can also be applied to all input devices by using the wildcard, _\*_, +in place of _\_ in the commands below. + +Tip: If the configuration settings do not appear to be taking effect, you could +try using _\*_ instead of _\_. If it works with the wildcard, try +using a different identifier from *swaymsg -t get_inputs* until you find the +correct input device. # INPUT COMMANDS @@ -144,7 +151,13 @@ configured. While sway is running, _-_ (hyphen) can be used as an alias for the current seat. Each seat has an independent keyboard focus and a separate cursor that is controlled by the pointer devices of the seat. This is useful for multiple people using the desktop at the same time with their own devices (each -sitting in their own "seat"). +sitting in their own "seat"). The wildcard character, _\*_, can also be used in +place of _\_ to change settings for all seats. + +Tip: If the configuration settings do not appear to be taking effect, you could +try using _\*_ instead of _\_. If it works with the wildcard, try +using a different identifier from *swaymsg -t get_seats* until you find the +correct seat. *seat* attach Attach an input device to this seat by its input identifier. A special From c6b43359e774ce1422e9d469c5081d6a7193dedb Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 17 Feb 2019 00:50:53 +0100 Subject: [PATCH 47/52] Fix Meson subproject boolean default options --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index cfd77ce7e..d3172bdd8 100644 --- a/meson.build +++ b/meson.build @@ -62,7 +62,7 @@ git = find_program('git', required: false) # Try first to find wlroots as a subproject, then as a system dependency wlroots_proj = subproject( 'wlroots', - default_options: ['rootston=disabled', 'examples=disabled'], + default_options: ['rootston=false', 'examples=false'], required: false, ) if wlroots_proj.found() From eaec82abd20ebe847bdf17f28b0667b449a3f0bc Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 16 Feb 2019 23:30:19 +0100 Subject: [PATCH 48/52] Disconnect swaybg instead of killing it This is much more reliable. This also fixes race conditions when killing swaybg while it's doing a wl_display_roundtrip. --- include/sway/output.h | 8 ++-- sway/config/output.c | 91 ++++++++++++++++++++++++++++++++++--------- sway/desktop/output.c | 2 + sway/tree/output.c | 5 +-- 4 files changed, 80 insertions(+), 26 deletions(-) diff --git a/include/sway/output.h b/include/sway/output.h index 479897ef2..ea7a21741 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -21,6 +21,7 @@ struct sway_output { struct sway_node node; struct wlr_output *wlr_output; struct sway_server *server; + struct wl_list link; struct wl_list layers[4]; // sway_layer_surface::link struct wlr_box usable_area; @@ -36,6 +37,8 @@ struct sway_output { struct sway_output_state current; + struct wl_client *swaybg_client; + struct wl_listener destroy; struct wl_listener mode; struct wl_listener transform; @@ -43,10 +46,7 @@ struct sway_output { struct wl_listener present; struct wl_listener damage_destroy; struct wl_listener damage_frame; - - struct wl_list link; - - pid_t bg_pid; + struct wl_listener swaybg_client_destroy; struct { struct wl_signal destroy; diff --git a/sway/config/output.c b/sway/config/output.c index 0f238715f..513d03e0f 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -1,16 +1,17 @@ #define _POSIX_C_SOURCE 200809L #include +#include #include #include -#include +#include #include #include -#include #include +#include +#include "log.h" #include "sway/config.h" #include "sway/output.h" #include "sway/tree/root.h" -#include "log.h" int output_name_cmp(const void *item, const void *data) { const struct output_config *output = item; @@ -165,14 +166,71 @@ static bool set_mode(struct wlr_output *output, int width, int height, return wlr_output_set_mode(output, best); } -void terminate_swaybg(pid_t pid) { - int ret = kill(pid, SIGTERM); - if (ret != 0) { - sway_log(SWAY_ERROR, "Unable to terminate swaybg [pid: %d]", pid); - } else { - int status; - waitpid(pid, &status, 0); +static void handle_swaybg_client_destroy(struct wl_listener *listener, + void *data) { + struct sway_output *output = + wl_container_of(listener, output, swaybg_client_destroy); + wl_list_remove(&output->swaybg_client_destroy.link); + wl_list_init(&output->swaybg_client_destroy.link); + output->swaybg_client = NULL; +} + +static bool spawn_swaybg(struct sway_output *output, char *const cmd[]) { + int sockets[2]; + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sockets) != 0) { + sway_log_errno(SWAY_ERROR, "socketpair failed"); + return false; } + + output->swaybg_client = wl_client_create(server.wl_display, sockets[0]); + if (output->swaybg_client == NULL) { + sway_log_errno(SWAY_ERROR, "wl_client_create failed"); + return false; + } + + output->swaybg_client_destroy.notify = handle_swaybg_client_destroy; + wl_client_add_destroy_listener(output->swaybg_client, + &output->swaybg_client_destroy); + + pid_t pid = fork(); + if (pid < 0) { + sway_log_errno(SWAY_ERROR, "fork failed"); + return false; + } else if (pid == 0) { + pid = fork(); + if (pid < 0) { + sway_log_errno(SWAY_ERROR, "fork failed"); + exit(EXIT_FAILURE); + } else if (pid == 0) { + // Remove the CLOEXEC flag + int flags = fcntl(sockets[1], F_GETFD); + if (flags == -1) { + sway_log_errno(SWAY_ERROR, "fcntl() failed"); + exit(EXIT_FAILURE); + } + if (fcntl(sockets[1], F_SETFD, flags & ~FD_CLOEXEC) == -1) { + sway_log_errno(SWAY_ERROR, "fcntl() failed"); + exit(EXIT_FAILURE); + } + + char wayland_socket_str[16]; + snprintf(wayland_socket_str, sizeof(wayland_socket_str), + "%d", sockets[1]); + setenv("WAYLAND_SOCKET", wayland_socket_str, true); + + execvp(cmd[0], cmd); + sway_log_errno(SWAY_ERROR, "execvp failed"); + exit(EXIT_FAILURE); + } + exit(EXIT_SUCCESS); + } + + if (waitpid(pid, NULL, 0) < 0) { + sway_log_errno(SWAY_ERROR, "waitpid failed"); + return false; + } + + return true; } bool apply_output_config(struct output_config *oc, struct sway_output *output) { @@ -243,8 +301,8 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { wlr_output_layout_add_auto(root->output_layout, wlr_output); } - if (output->bg_pid != 0) { - terminate_swaybg(output->bg_pid); + if (output->swaybg_client != NULL) { + wl_client_destroy(output->swaybg_client); } if (oc && oc->background && config->swaybg_command) { sway_log(SWAY_DEBUG, "Setting background for output %s to %s", @@ -258,13 +316,8 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { oc->background_fallback ? oc->background_fallback : NULL, NULL, }; - - output->bg_pid = fork(); - if (output->bg_pid < 0) { - sway_log_errno(SWAY_ERROR, "fork failed"); - } else if (output->bg_pid == 0) { - execvp(cmd[0], cmd); - sway_log_errno(SWAY_ERROR, "Failed to execute swaybg"); + if (!spawn_swaybg(output, cmd)) { + return false; } } diff --git a/sway/desktop/output.c b/sway/desktop/output.c index ad75bb35a..c5461ee66 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -506,6 +506,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&output->present.link); wl_list_remove(&output->damage_destroy.link); wl_list_remove(&output->damage_frame.link); + wl_list_remove(&output->swaybg_client_destroy.link); transaction_commit_dirty(); } @@ -612,6 +613,7 @@ void handle_new_output(struct wl_listener *listener, void *data) { output->damage_frame.notify = damage_handle_frame; wl_signal_add(&output->damage->events.destroy, &output->damage_destroy); output->damage_destroy.notify = damage_handle_destroy; + wl_list_init(&output->swaybg_client_destroy.link); struct output_config *oc = output_find_config(output); if (!oc || oc->enabled) { diff --git a/sway/tree/output.c b/sway/tree/output.c index 138144a77..60e0af9f4 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -233,9 +233,8 @@ void output_disable(struct sway_output *output) { root_for_each_container(untrack_output, output); - if (output->bg_pid) { - terminate_swaybg(output->bg_pid); - output->bg_pid = 0; + if (output->swaybg_client != NULL) { + wl_client_destroy(output->swaybg_client); } int index = list_find(root->outputs, output); From f22aef018ba1f2ff50d35676ec6aa2e18e2a4ad5 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sun, 17 Feb 2019 09:51:56 -0500 Subject: [PATCH 49/52] Remove refs to unimplemented debuglog command Closes #3695 --- include/sway/commands.h | 1 - sway/sway.5.scd | 4 ---- 2 files changed, 5 deletions(-) diff --git a/include/sway/commands.h b/include/sway/commands.h index 3ed007635..764821a0e 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -112,7 +112,6 @@ sway_cmd cmd_client_placeholder; sway_cmd cmd_client_background; sway_cmd cmd_commands; sway_cmd cmd_create_output; -sway_cmd cmd_debuglog; sway_cmd cmd_default_border; sway_cmd cmd_default_floating_border; sway_cmd cmd_default_orientation; diff --git a/sway/sway.5.scd b/sway/sway.5.scd index fd0a22dc7..b6955acd5 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -413,10 +413,6 @@ The default colors are: : #0c0c0c -*debuglog* on|off|toggle - Enables, disables or toggles debug logging. _toggle_ cannot be used in the - configuration file. - *default_border* normal|none|pixel [] Set default border style for new tiled windows. From 34f5c1e7c40d479a00b384ac0849c0cf0a6c3f5e Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sun, 17 Feb 2019 13:07:04 -0500 Subject: [PATCH 50/52] workspace_next_name: fallback to next available number This changes `workspace_next_name` to use the next available number as the workspace name instead of the number of outputs. This fixes the case where a number that is already in use could be returned. The workspace numbers in use have no relation to the number of outputs so it makes more sense to use the lowest available number --- sway/tree/workspace.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index cda6caf7c..9b7c5112d 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -334,16 +334,13 @@ char *workspace_next_name(const char *output_name) { if (target != NULL) { return target; } - // As a fall back, get the current number of active workspaces - // and return that + 1 for the next workspace's name - int ws_num = root->outputs->length; - int l = snprintf(NULL, 0, "%d", ws_num); - char *name = malloc(l + 1); - if (!sway_assert(name, "Could not allocate workspace name")) { - return NULL; - } - sprintf(name, "%d", ws_num++); - return name; + // As a fall back, use the next available number + char name[12] = ""; + unsigned int ws_num = 1; + do { + snprintf(name, sizeof(name), "%u", ws_num++); + } while (workspace_by_number(name)); + return strdup(name); } static bool _workspace_by_number(struct sway_workspace *ws, void *data) { From 0940a46c114cef62e1d666a3038bf5e18d81ba95 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sun, 17 Feb 2019 20:16:23 -0500 Subject: [PATCH 51/52] seat_cmd_cursor: fix typo in expected syntax This just fixes a typo in the expected syntax for seat_cmd_cursor --- sway/commands/seat/cursor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/commands/seat/cursor.c b/sway/commands/seat/cursor.c index 0c7609eaf..085e6a33f 100644 --- a/sway/commands/seat/cursor.c +++ b/sway/commands/seat/cursor.c @@ -12,7 +12,7 @@ static struct cmd_results *press_or_release(struct sway_cursor *cursor, static const char expected_syntax[] = "Expected 'cursor ' or " "'cursor ' or " - "'curor '"; + "'cursor '"; static struct cmd_results *handle_command(struct sway_cursor *cursor, int argc, char **argv) { From a1b9aa11d12a5b0a2a521d6b9b89d487be2eedd3 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sun, 17 Feb 2019 20:33:37 -0500 Subject: [PATCH 52/52] Use container under cursor for mouse bindings This matches i3's behavior of executing mouse bindings in regards to the container under the cursor instead of what is focused. --- sway/commands/bind.c | 20 +++++++++++++++++--- sway/sway.5.scd | 13 +++++++------ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 59116d67f..172e6b8ae 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c @@ -1,10 +1,11 @@ #define _POSIX_C_SOURCE 200809L #include #include -#include -#include #include #include +#include +#include +#include #include "sway/commands.h" #include "sway/config.h" #include "sway/input/cursor.h" @@ -330,7 +331,20 @@ struct cmd_results *cmd_bindcode(int argc, char **argv) { void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) { sway_log(SWAY_DEBUG, "running command for binding: %s", binding->command); - list_t *res_list = execute_command(binding->command, seat, NULL); + struct sway_container *con = NULL; + if (binding->type == BINDING_MOUSESYM + || binding->type == BINDING_MOUSECODE) { + struct wlr_surface *surface = NULL; + double sx, sy; + struct sway_node *node = node_at_coords(seat, + seat->cursor->cursor->x, seat->cursor->cursor->y, + &surface, &sx, &sy); + if (node && node->type == N_CONTAINER) { + con = node->sway_container; + } + } + + list_t *res_list = execute_command(binding->command, seat, con); bool success = true; for (int i = 0; i < res_list->length; ++i) { struct cmd_results *results = res_list->items[i]; diff --git a/sway/sway.5.scd b/sway/sway.5.scd index b6955acd5..76467d23a 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -293,12 +293,13 @@ runtime. overwrite a binding, swaynag will give you a warning. To silence this, use the _--no-warn_ flag. - Mouse buttons can either be specified in the form _button[1-9]_ or by using - the name of the event code (ex _BTN\_LEFT_ or _BTN\_RIGHT_). For the former - option, the buttons will be mapped to their values in X11 (1=left, 2=middle, - 3=right, 4=scroll up, 5=scroll down, 6=scroll left, 7=scroll right, 8=back, - 9=forward). For the latter option, you can find the event names using - _libinput debug-events_. + Mouse bindings operate on the container under the cursor instead of the + container that has focus. Mouse buttons can either be specified in the form + _button[1-9]_ or by using the name of the event code (ex _BTN\_LEFT_ or + _BTN\_RIGHT_). For the former option, the buttons will be mapped to their + values in X11 (1=left, 2=middle, 3=right, 4=scroll up, 5=scroll down, + 6=scroll left, 7=scroll right, 8=back, 9=forward). For the latter option, + you can find the event names using _libinput debug-events_. _--whole-window_, _--border_, and _--exclude-titlebar_ are mouse-only options which affect the region in which the mouse bindings can be triggered. By