From 995b6edab6fab33668a9bd320631b6ab65dc10c6 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Fri, 8 Feb 2019 22:29:35 -0500 Subject: [PATCH 01/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 605e515a9324c3e314939d21f1ea13b29881e100 Mon Sep 17 00:00:00 2001 From: Rouven Czerwinski Date: Sun, 10 Feb 2019 17:04:12 +0100 Subject: [PATCH 02/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 3952d4f4f3b76290101e0b82e7359d11e79058bb Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sun, 10 Feb 2019 12:36:30 -0500 Subject: [PATCH 03/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 418c19fe528190918d41aefed46abe02c8b6834f Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sun, 10 Feb 2019 15:23:50 -0500 Subject: [PATCH 04/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 a64a3ee6bbd3b880c32bbd9c9a38420d04748dd2 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sun, 10 Feb 2019 15:37:24 -0500 Subject: [PATCH 05/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 d2c896ed84534f5c4dc7e8c30c3e92be4081fab1 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Mon, 11 Feb 2019 03:26:12 -0500 Subject: [PATCH 06/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 2540e8ea792f7b2a54698aba34b3bf11161fe102 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Mon, 11 Feb 2019 03:59:11 -0500 Subject: [PATCH 07/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 fb4f29289fd8d1f94975e64fded6657222ed5390 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sun, 10 Feb 2019 20:12:51 -0500 Subject: [PATCH 08/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 97c89b24b8e4a8e091f6974333457deb73b7800f Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 12 Feb 2019 22:55:23 +0100 Subject: [PATCH 09/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 cfee167b7bd1c67f8dbed96d69de4050d8860b06 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 12 Feb 2019 23:13:24 +0100 Subject: [PATCH 10/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 98b40d31c1178228dfc476b26d82e99bae338b5f Mon Sep 17 00:00:00 2001 From: athrungithub Date: Mon, 11 Feb 2019 19:10:28 -0300 Subject: [PATCH 11/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 1bccde68a4fadd0b4170faa16b97554a864447d4 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Wed, 13 Feb 2019 03:01:06 -0500 Subject: [PATCH 12/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 d168d65f2c0297bf5662c0f48f5f53705e54a376 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Tue, 12 Feb 2019 23:21:11 -0500 Subject: [PATCH 13/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 9b8249c350a499bb65e50741e8a45e5575ac7d18 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Wed, 13 Feb 2019 14:32:47 -0500 Subject: [PATCH 14/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 ab42874f71bceeaf0357dbf3020f1cb73fb2c738 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Wed, 13 Feb 2019 23:46:20 -0500 Subject: [PATCH 15/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 e8c472aee95ce1cbb6feef04d970327d1717d7fc Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Wed, 13 Feb 2019 22:38:30 -0500 Subject: [PATCH 16/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 96de2b539c00992003664d0de225cc28c2fb9e54 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Fri, 15 Feb 2019 03:01:19 -0500 Subject: [PATCH 17/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 5484f308b9aa53ab9c13d670d84a7fc35d447c1a Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Thu, 14 Feb 2019 15:43:34 +0000 Subject: [PATCH 18/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 d3c527220a445c1f88b892c0e77e801d326541b7 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Fri, 15 Feb 2019 15:15:45 +0000 Subject: [PATCH 19/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 3c59069cb0fae32097f117497f540ed11e0210d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=A1bir=20Benchakhtir?= Date: Sat, 16 Feb 2019 03:57:14 +0100 Subject: [PATCH 20/52] Spanish translation of the README --- README.es.md | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 README.es.md diff --git a/README.es.md b/README.es.md new file mode 100644 index 000000000..1bf96d8cc --- /dev/null +++ b/README.es.md @@ -0,0 +1,70 @@ +# sway + +[**English**](https://github.com/swaywm/sway/blob/master/README.md#sway--) - [日本語](https://github.com/swaywm/sway/blob/master/README.ja.md#sway--) - [Deutsch](https://github.com/swaywm/sway/blob/master/README.de.md#sway--) - [Ελληνικά](https://github.com/swaywm/sway/blob/master/README.el.md#sway--) - [Français](https://github.com/swaywm/sway/blob/master/README.fr.md#sway--) - [Українська](https://github.com/swaywm/sway/blob/master/README.uk.md#sway--) - [Italiano](https://github.com/swaywm/sway/blob/master/README.it.md#sway--) - [Português](https://github.com/swaywm/sway/blob/master/README.pt.md#sway--) - +[Русский](https://github.com/swaywm/sway/blob/master/README.ru.md#sway--) - [Български](https://github.com/swaywm/sway/blob/master/README.bg.md#sway--) - [Español](https://github.com/swaywm/sway/blob/master/README.es.md#sway--) + +sway es un compositor de [Wayland](http://wayland.freedesktop.org/) compatible con i3. +Lea el [FAQ](https://github.com/swaywm/sway/wiki). Unase al [canal de IRC](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on +irc.freenode.net). + +Si quiere apoyar el desarrollo de sway, por favor, contribuya en [la página de Patreon de SirCmpwn](https://patreon.com/sircmpwn). + +## Firmas de las versiones + +Las distintas versiones están firmadas con [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) +y publicadas [en GitHub](https://github.com/swaywm/sway/releases). + +## Instalación + +### Usando paquetes + +Sway está disponible en muchas distribuciones. Pruebe instalando el paquete "sway" desde la suya. +Si no está disponible, puede consultar [esta documentación](https://github.com/swaywm/sway/wiki/Unsupported-packages) +y así obtener información acerca de como instalarlo. + +Si está interesado en crear un paquete para su distribución, unase al canal de IRC o +escriba un email a sir@cmpwn.com + +### Compilando el código fuente + +Instale las dependencias: + +* meson \* +* [wlroots](https://github.com/swaywm/wlroots) +* wayland +* wayland-protocols \* +* pcre +* json-c +* pango +* cairo +* gdk-pixbuf2 \*\* +* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) >= 1.8.1 (optional: man pages) \* +* git \* + +_\*Compile-time dep_ + +_\*\*opcional: necesario para swaybg_ + +Desde su consola, ejecute las ordenes: + + meson build + ninja -C build + sudo ninja -C build install + +En sistemas sin `logind`, necesitará cambiar los permisos del archivo compilado de sway: + + sudo chmod a+s /usr/local/bin/sway + +Sway abandonará los permisos de super-usuario al poco de arrancar. + +## Configuración + +Si ya utiliza i3, copie su archivo de configuración de i3 a `~/.config/sway/config` y +sway funcionará sin tener que configurar nada más. En otro caso, copie el archivo de +configuración basico a `~/.config/sway/config`, normalmente se encuentra en `/etc/sway/config`. +Ejecute `man 5 sway` para obtener información sobre la configuración. + +## Ejecución + +Ejecute `sway` desde su consola. Algunos gestores de pantalla pueden funcionar sin estar +soportados por `sway` (sabemos que gdm funciona bastante bien). From 9e590c4d01e5a85a684028fc7092b34ad115a9d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=A1bir=20Garc=C3=ADa?= Date: Sat, 16 Feb 2019 04:17:18 +0100 Subject: [PATCH 21/52] Add spanish link to the home README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 239e7e3ef..f5173adff 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # sway [**English**](https://github.com/swaywm/sway/blob/master/README.md#sway--) - [日本語](https://github.com/swaywm/sway/blob/master/README.ja.md#sway--) - [Deutsch](https://github.com/swaywm/sway/blob/master/README.de.md#sway--) - [Ελληνικά](https://github.com/swaywm/sway/blob/master/README.el.md#sway--) - [Français](https://github.com/swaywm/sway/blob/master/README.fr.md#sway--) - [Українська](https://github.com/swaywm/sway/blob/master/README.uk.md#sway--) - [Italiano](https://github.com/swaywm/sway/blob/master/README.it.md#sway--) - [Português](https://github.com/swaywm/sway/blob/master/README.pt.md#sway--) - -[Русский](https://github.com/swaywm/sway/blob/master/README.ru.md#sway--) - [Български](https://github.com/swaywm/sway/blob/master/README.bg.md#sway--) +[Русский](https://github.com/swaywm/sway/blob/master/README.ru.md#sway--) - [Български](https://github.com/swaywm/sway/blob/master/README.bg.md#sway--) - [Español](https://github.com/swaywm/sway/blob/master/README.es.md#sway--) sway is an i3-compatible [Wayland](http://wayland.freedesktop.org/) compositor. Read the [FAQ](https://github.com/swaywm/sway/wiki). Join the [IRC From db351dc67022bc25a109addcf0acbfa4e2ba0d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Y=C3=A1bir=20Garc=C3=ADa?= Date: Sat, 16 Feb 2019 04:29:36 +0100 Subject: [PATCH 22/52] Fix accents --- README.es.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.es.md b/README.es.md index 1bf96d8cc..daa1fc093 100644 --- a/README.es.md +++ b/README.es.md @@ -4,7 +4,7 @@ [Русский](https://github.com/swaywm/sway/blob/master/README.ru.md#sway--) - [Български](https://github.com/swaywm/sway/blob/master/README.bg.md#sway--) - [Español](https://github.com/swaywm/sway/blob/master/README.es.md#sway--) sway es un compositor de [Wayland](http://wayland.freedesktop.org/) compatible con i3. -Lea el [FAQ](https://github.com/swaywm/sway/wiki). Unase al [canal de IRC](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on +Lea el [FAQ](https://github.com/swaywm/sway/wiki). Únase al [canal de IRC](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on irc.freenode.net). Si quiere apoyar el desarrollo de sway, por favor, contribuya en [la página de Patreon de SirCmpwn](https://patreon.com/sircmpwn). @@ -22,7 +22,7 @@ Sway está disponible en muchas distribuciones. Pruebe instalando el paquete "sw Si no está disponible, puede consultar [esta documentación](https://github.com/swaywm/sway/wiki/Unsupported-packages) y así obtener información acerca de como instalarlo. -Si está interesado en crear un paquete para su distribución, unase al canal de IRC o +Si está interesado en crear un paquete para su distribución, únase al canal de IRC o escriba un email a sir@cmpwn.com ### Compilando el código fuente @@ -45,7 +45,7 @@ _\*Compile-time dep_ _\*\*opcional: necesario para swaybg_ -Desde su consola, ejecute las ordenes: +Desde su consola, ejecute las órdenes: meson build ninja -C build @@ -61,7 +61,7 @@ Sway abandonará los permisos de super-usuario al poco de arrancar. Si ya utiliza i3, copie su archivo de configuración de i3 a `~/.config/sway/config` y sway funcionará sin tener que configurar nada más. En otro caso, copie el archivo de -configuración basico a `~/.config/sway/config`, normalmente se encuentra en `/etc/sway/config`. +configuración básico a `~/.config/sway/config`, normalmente se encuentra en `/etc/sway/config`. Ejecute `man 5 sway` para obtener información sobre la configuración. ## Ejecución From 859a884e82601044aa4c825cfbfdd53e2b4ef79c Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 16 Feb 2019 11:57:41 +0100 Subject: [PATCH 23/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 cfacf85755849997ae3b25d2fa241378e0ebf0b9 Mon Sep 17 00:00:00 2001 From: Vincent Vanlaer Date: Fri, 15 Feb 2019 18:29:47 +0100 Subject: [PATCH 24/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 26d6360febeb364a9c7e20844ad03c796e4f08c3 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Sat, 16 Feb 2019 11:01:15 +0000 Subject: [PATCH 25/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 f54077dbca2faf3f0d614377a01a215c82ef075e Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Sat, 16 Feb 2019 11:02:15 +0000 Subject: [PATCH 26/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 272ca061714a77597feae1075cdd2d44ebdf5ce3 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sat, 16 Feb 2019 16:14:27 -0500 Subject: [PATCH 27/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 8ab64d3fcc98090fd1a49d0696dff1c9d39aad41 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 16 Feb 2019 23:09:26 +0100 Subject: [PATCH 28/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 f7f5b172a02db8209cd7cd315e397e52b67bfed3 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sat, 16 Feb 2019 17:42:56 -0500 Subject: [PATCH 29/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 806129d3ccef1075e178791c56159e08e868bcaf Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 17 Feb 2019 00:50:53 +0100 Subject: [PATCH 30/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 7baaa3a0f80a28f58a3f95f7c3c832cb109b2aab Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 16 Feb 2019 23:30:19 +0100 Subject: [PATCH 31/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 cd10e755c1b820b15eac448451d6b9dabd339fc0 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sun, 17 Feb 2019 09:51:56 -0500 Subject: [PATCH 32/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 487c83f0de9ca2a7650ad636eed6fd694ddcb82e Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 15 Feb 2019 21:01:54 -0500 Subject: [PATCH 33/52] Add workspace {prev,next}_on_output --create This creates the next workspace if you hit the end. --- include/sway/tree/workspace.h | 6 ++++-- sway/commands/workspace.c | 13 ++++++++----- sway/tree/workspace.c | 29 ++++++++++++++++++++--------- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index 7abfbff13..41b597963 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h @@ -67,11 +67,13 @@ struct sway_workspace *workspace_by_number(const char* name); struct sway_workspace *workspace_by_name(const char*); -struct sway_workspace *workspace_output_next(struct sway_workspace *current); +struct sway_workspace *workspace_output_next( + struct sway_workspace *current, bool create); struct sway_workspace *workspace_next(struct sway_workspace *current); -struct sway_workspace *workspace_output_prev(struct sway_workspace *current); +struct sway_workspace *workspace_output_prev( + struct sway_workspace *current, bool create); struct sway_workspace *workspace_prev(struct sway_workspace *current); diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index 65a3f4075..5fde81299 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c @@ -181,7 +181,9 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { ++argv; } - + bool create = argc > 1 && strcasecmp(argv[1], "--create") == 0; + struct sway_seat *seat = config->handler_context.seat; + struct sway_workspace *current = seat_get_focused_workspace(seat); struct sway_workspace *ws = NULL; if (strcasecmp(argv[0], "number") == 0) { if (argc < 2) { @@ -199,12 +201,13 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { } } else if (strcasecmp(argv[0], "next") == 0 || strcasecmp(argv[0], "prev") == 0 || - strcasecmp(argv[0], "next_on_output") == 0 || - strcasecmp(argv[0], "prev_on_output") == 0 || strcasecmp(argv[0], "current") == 0) { ws = workspace_by_name(argv[0]); + } else if (strcasecmp(argv[0], "next_on_output") == 0) { + ws = workspace_output_next(current, create); + } else if (strcasecmp(argv[0], "prev_on_output") == 0) { + ws = workspace_output_prev(current, create); } else if (strcasecmp(argv[0], "back_and_forth") == 0) { - struct sway_seat *seat = config->handler_context.seat; if (!seat->prev_workspace_name) { return cmd_results_new(CMD_INVALID, "There is no previous workspace"); @@ -220,7 +223,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { free(name); } workspace_switch(ws, no_auto_back_and_forth); - seat_consider_warp_to_focus(config->handler_context.seat); + seat_consider_warp_to_focus(seat); } return cmd_results_new(CMD_SUCCESS, NULL); } diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index cda6caf7c..68f1de502 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -230,8 +230,10 @@ static void workspace_name_from_binding(const struct sway_binding * binding, // not a command about workspaces if (strcmp(_target, "next") == 0 || strcmp(_target, "prev") == 0 || - strcmp(_target, "next_on_output") == 0 || - strcmp(_target, "prev_on_output") == 0 || + strncmp(_target, "next_on_output", + strlen("next_on_output")) == 0 || + strncmp(_target, "prev_on_output", + strlen("next_on_output")) == 0 || strcmp(_target, "number") == 0 || strcmp(_target, "back_and_forth") == 0 || strcmp(_target, "current") == 0) { @@ -372,11 +374,11 @@ struct sway_workspace *workspace_by_name(const char *name) { if (strcmp(name, "prev") == 0) { return workspace_prev(current); } else if (strcmp(name, "prev_on_output") == 0) { - return workspace_output_prev(current); + return workspace_output_prev(current, false); } else if (strcmp(name, "next") == 0) { return workspace_next(current); } else if (strcmp(name, "next_on_output") == 0) { - return workspace_output_next(current); + return workspace_output_next(current, false); } else if (strcmp(name, "current") == 0) { return current; } else if (strcasecmp(name, "back_and_forth") == 0) { @@ -397,11 +399,18 @@ struct sway_workspace *workspace_by_name(const char *name) { * otherwise the next one is returned. */ static struct sway_workspace *workspace_output_prev_next_impl( - struct sway_output *output, int dir) { + struct sway_output *output, int dir, bool create) { struct sway_seat *seat = input_manager_current_seat(); struct sway_workspace *workspace = seat_get_focused_workspace(seat); int index = list_find(output->workspaces, workspace); + if (!workspace_is_empty(workspace) && create && + (index + dir < 0 || index + dir == output->workspaces->length)) { + struct sway_output *output = workspace->output; + char *next = workspace_next_name(output->wlr_output->name); + workspace_create(output, next); + free(next); + } size_t new_index = wrap(index + dir, output->workspaces->length); return output->workspaces->items[new_index]; } @@ -432,16 +441,18 @@ static struct sway_workspace *workspace_prev_next_impl( } } -struct sway_workspace *workspace_output_next(struct sway_workspace *current) { - return workspace_output_prev_next_impl(current->output, 1); +struct sway_workspace *workspace_output_next( + struct sway_workspace *current, bool create) { + return workspace_output_prev_next_impl(current->output, 1, create); } struct sway_workspace *workspace_next(struct sway_workspace *current) { return workspace_prev_next_impl(current, 1); } -struct sway_workspace *workspace_output_prev(struct sway_workspace *current) { - return workspace_output_prev_next_impl(current->output, -1); +struct sway_workspace *workspace_output_prev( + struct sway_workspace *current, bool create) { + return workspace_output_prev_next_impl(current->output, -1, create); } struct sway_workspace *workspace_prev(struct sway_workspace *current) { From faf15ee733681f14797d8b47078854a00f03f8fc Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sun, 17 Feb 2019 13:07:04 -0500 Subject: [PATCH 34/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 68f1de502..73322491b 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -336,16 +336,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 73c8e63438efff8f43271812505f32c829bd4a98 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sun, 17 Feb 2019 20:16:23 -0500 Subject: [PATCH 35/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 041594d2ab4fb6f8de2055d3704da5f54146c44e Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Sun, 17 Feb 2019 20:33:37 -0500 Subject: [PATCH 36/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 From 59f20560223a87c5d23dfa80edcad41fb4eb8d22 Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 18 Feb 2019 13:19:58 +0100 Subject: [PATCH 37/52] Fix drag icon map listener not removed --- sway/input/seat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sway/input/seat.c b/sway/input/seat.c index df48b7518..69b048430 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -287,6 +287,7 @@ static void drag_icon_handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&icon->link); wl_list_remove(&icon->surface_commit.link); wl_list_remove(&icon->unmap.link); + wl_list_remove(&icon->map.link); wl_list_remove(&icon->destroy.link); free(icon); } From fc397f52bbbeca3ef078ae290257329404207071 Mon Sep 17 00:00:00 2001 From: Yorick van Pelt Date: Mon, 18 Feb 2019 13:57:16 +0100 Subject: [PATCH 38/52] Add 'visible' key to view json response --- sway/ipc-json.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 23016dbd5..6d36c7274 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -344,6 +344,9 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object json_object_object_add(object, "app_id", app_id ? json_object_new_string(app_id) : NULL); + bool visible = view_is_visible(c->view); + json_object_object_add(object, "visible", json_object_new_boolean(visible)); + json_object *marks = json_object_new_array(); list_t *con_marks = c->marks; for (int i = 0; i < con_marks->length; ++i) { From b4836ecbcc67cecf42aa2cbc80e5116a78176328 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 19 Feb 2019 12:11:16 +0100 Subject: [PATCH 39/52] ci: add Alpine CI --- .builds/alpine.yml | 38 +++++++++++++++++++++++++++++ .build.yml => .builds/archlinux.yml | 22 ++++++++--------- 2 files changed, 49 insertions(+), 11 deletions(-) create mode 100644 .builds/alpine.yml rename .build.yml => .builds/archlinux.yml (85%) diff --git a/.builds/alpine.yml b/.builds/alpine.yml new file mode 100644 index 000000000..328625a5d --- /dev/null +++ b/.builds/alpine.yml @@ -0,0 +1,38 @@ +image: alpine/edge +packages: + - cairo-dev + - eudev-dev + - gdk-pixbuf-dev + - json-c-dev + - libevdev-dev + - libinput-dev + - libxcb-dev + - libxkbcommon-dev + - mesa-dev + - meson + - pango-dev + - pixman-dev + - scdoc + - wayland-dev + - wayland-protocols + - xcb-util-image-dev + - xorg-server-xwayland +sources: + - https://github.com/swaywm/sway + - https://github.com/swaywm/wlroots +tasks: + - wlroots: | + cd wlroots + meson --prefix=/usr build -Drootston=false -Dexamples=false + ninja -C build + sudo ninja -C build install + - setup: | + cd sway + meson build + - build: | + cd sway + ninja -C build + - build-no-xwayland: | + cd sway + meson configure build -Dxwayland=disabled + ninja -C build diff --git a/.build.yml b/.builds/archlinux.yml similarity index 85% rename from .build.yml rename to .builds/archlinux.yml index 144333118..c8f116e00 100644 --- a/.build.yml +++ b/.builds/archlinux.yml @@ -1,25 +1,25 @@ -# vim: ft=yaml ts=2 sw=2 et : image: archlinux packages: - - meson - - xorg-server-xwayland - - xcb-util-image - - json-c - - pango - cairo + - gdk-pixbuf2 + - json-c + - libinput + - libxcb + - libxkbcommon + - meson + - pango + - scdoc - wayland - wayland-protocols - - gdk-pixbuf2 - - libinput - - libxkbcommon - - scdoc + - xcb-util-image + - xorg-server-xwayland sources: - https://github.com/swaywm/sway - https://github.com/swaywm/wlroots tasks: - wlroots: | cd wlroots - meson --prefix=/usr build + meson --prefix=/usr build -Drootston=false -Dexamples=false ninja -C build sudo ninja -C build install - setup: | From 11bc369301aa6a91ab03666abad8cb358f525027 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Tue, 19 Feb 2019 14:02:36 +0100 Subject: [PATCH 40/52] Add Polish README --- README.md | 3 ++- README.pl.md | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 README.pl.md diff --git a/README.md b/README.md index f5173adff..e11a0dc13 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # sway [**English**](https://github.com/swaywm/sway/blob/master/README.md#sway--) - [日本語](https://github.com/swaywm/sway/blob/master/README.ja.md#sway--) - [Deutsch](https://github.com/swaywm/sway/blob/master/README.de.md#sway--) - [Ελληνικά](https://github.com/swaywm/sway/blob/master/README.el.md#sway--) - [Français](https://github.com/swaywm/sway/blob/master/README.fr.md#sway--) - [Українська](https://github.com/swaywm/sway/blob/master/README.uk.md#sway--) - [Italiano](https://github.com/swaywm/sway/blob/master/README.it.md#sway--) - [Português](https://github.com/swaywm/sway/blob/master/README.pt.md#sway--) - -[Русский](https://github.com/swaywm/sway/blob/master/README.ru.md#sway--) - [Български](https://github.com/swaywm/sway/blob/master/README.bg.md#sway--) - [Español](https://github.com/swaywm/sway/blob/master/README.es.md#sway--) +[Русский](https://github.com/swaywm/sway/blob/master/README.ru.md#sway--) - [Български](https://github.com/swaywm/sway/blob/master/README.bg.md#sway--) - [Español](https://github.com/swaywm/sway/blob/master/README.es.md#sway--) - +[Polski](https://github.com/swaywm/sway/blob/master/README.pl.md#sway--) sway is an i3-compatible [Wayland](http://wayland.freedesktop.org/) compositor. Read the [FAQ](https://github.com/swaywm/sway/wiki). Join the [IRC diff --git a/README.pl.md b/README.pl.md new file mode 100644 index 000000000..843fae605 --- /dev/null +++ b/README.pl.md @@ -0,0 +1,71 @@ +# sway + +[**English**](https://github.com/swaywm/sway/blob/master/README.md#sway--) - [日本語](https://github.com/swaywm/sway/blob/master/README.ja.md#sway--) - [Deutsch](https://github.com/swaywm/sway/blob/master/README.de.md#sway--) - [Ελληνικά](https://github.com/swaywm/sway/blob/master/README.el.md#sway--) - [Français](https://github.com/swaywm/sway/blob/master/README.fr.md#sway--) - [Українська](https://github.com/swaywm/sway/blob/master/README.uk.md#sway--) - [Italiano](https://github.com/swaywm/sway/blob/master/README.it.md#sway--) - [Português](https://github.com/swaywm/sway/blob/master/README.pt.md#sway--) - +[Русский](https://github.com/swaywm/sway/blob/master/README.ru.md#sway--) - [Български](https://github.com/swaywm/sway/blob/master/README.bg.md#sway--) - [Español](https://github.com/swaywm/sway/blob/master/README.es.md#sway--) - +[Polski](https://github.com/swaywm/sway/blob/master/README.pl.md#sway--) + +sway jest kompozytorem [Wayland](http://wayland.freedesktop.org/) kompatybilnym z i3. +Przeczytaj [FAQ](https://github.com/swaywm/sway/wiki). Dołącz do [kanału IRC](http://webchat.freenode.net/?channels=sway&uio=d4) +(#sway na irc.freenode.net). + +Jeśli chcesz wesprzeć rozwój sway, rozważ wsparcie SirCmpwn na jego [stronie Patreon](https://patreon.com/sircmpwn). + +## Podpisy cyfrowe wydań + +Wydania są podpisywane przy pomocy klucza [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) +i publikowane [na GitHubie](https://github.com/swaywm/sway/releases). + +## Instalacja + +### Z pakietów + +Sway jest dostępny w wielu dystybucjach. Spróbuj zainstalować pakiet "sway" w swoim +menedżerze pakietów. Jeśli nie jest dostępny, sprawdź [tę stronę wiki](https://github.com/swaywm/sway/wiki/Unsupported-packages) +aby uzyskać informacje dotyczące instalacji w swojej dystrybucji. + +Jeśli chciałbyś stworzyć pakiet sway dla swojej dystrybucji, odwiedź kanał IRC lub wyślij email na +adres sir@cmpwn.com w celu uzyskania wskazówek. + +### Kompilacja ze Źródła + +Zainstaluj zależności: + +* meson \* +* [wlroots](https://github.com/swaywm/wlroots) +* wayland +* wayland-protocols \* +* pcre +* json-c +* pango +* cairo +* gdk-pixbuf2 \*\* +* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) >= 1.8.1 (opcjonalnie: strony pomocy man) \* +* git \* + +_\*zależności kompilacji_ + +_\*\*opcjonalnie: wymagane dla swaybg_ + +Wykonaj następujące polecenia: + + meson build + ninja -C build + sudo ninja -C build install + +Na systemach bez logind należy wykonać polecenie suid na pliku wykonywalnym sway: + + sudo chmod a+s /usr/local/bin/sway + +Sway pozbędzie się uprawnień roota tuż po wystartowaniu. + +## Konfiguracja + +Jeśli już korzystasz z i3, skopiuj swoją konfigurację i3 do katalogu `~/.config/sway/config` i +zadziała od ręki. W przeciwnym razie skopiuj przykładowy plik konfiguracyjny do folderu +`~/.config/sway/config`; zazwyczaj znajduje się w `/etc/sway/config`. +Wykonaj polecenie `man 5 sway` aby uzyskać informacje dotyczące konfiguracji. + +## Uruchamianie + +Wykonaj polecenie `sway` z poziomu TTY. Niektóre menedżery wyświetlania mogą umożliwiać rozruch z ich +poziomu, ale nie jest to wspierane przez sway (w gdm podobno działa to całkiem nieźle). From a42b5d079a6fa184724caa05e4d577a308c7888e Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 19 Feb 2019 16:09:29 +0100 Subject: [PATCH 41/52] ci: add FreeBSD --- .builds/freebsd.yml | 53 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .builds/freebsd.yml diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml new file mode 100644 index 000000000..8fa760257 --- /dev/null +++ b/.builds/freebsd.yml @@ -0,0 +1,53 @@ +image: freebsd/latest +packages: +- devel/json-c +- devel/libevdev +- devel/meson +- devel/pkgconf +- graphics/cairo +- graphics/gdk-pixbuf2 +- graphics/wayland +- graphics/wayland-protocols +- textproc/scdoc +- x11-toolkits/pango +- x11/libxcb +- x11/libxkbcommon +# wlroots dependencies +- devel/evdev-proto +- devel/libepoll-shim +- devel/libudev-devd +- graphics/libdrm +- graphics/mesa-libs +- x11/libinput +- x11/libX11 +- x11/pixman +- x11/xcb-util-wm +sources: +- https://github.com/swaywm/sway +- https://github.com/swaywm/wlroots +tasks: +- fixup_epoll: | + cat << 'EOF' | sudo tee /usr/local/libdata/pkgconfig/epoll-shim.pc + prefix=/usr/local + exec_prefix=\$\{\$prefix\} + libdir=${prefix}/lib + sharedlibdir=${prefix}/lib + includedir=${prefix}/include/libepoll-shim + Name: epoll-shim + Description: epoll shim implemented using kevent + Version: 0 + Requires: + Libs: -L${libdir} -L${sharedlibdir} -lepoll-shim + Libs.private: -pthread -lrt + Cflags: -I${includedir} + EOF +- setup: | + cd sway + mkdir subprojects + cd subprojects + ln -s ../../wlroots wlroots + cd .. + meson build +- build: | + cd sway + ninja -C build From b799a30962ff1221dc4a32e76a22fd9ddb9e7ece Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 19 Feb 2019 16:18:31 +0100 Subject: [PATCH 42/52] Don't use SOCK_CLOEXEC Manually set the CLOEXEC flag instead, since SOCK_CLOEXEC isn't POSIX. --- sway/config/output.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/sway/config/output.c b/sway/config/output.c index 513d03e0f..e7fbad833 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -175,12 +175,33 @@ static void handle_swaybg_client_destroy(struct wl_listener *listener, output->swaybg_client = NULL; } +static bool set_cloexec(int fd, bool cloexec) { + int flags = fcntl(fd, F_GETFD); + if (flags == -1) { + sway_log_errno(SWAY_ERROR, "fcntl failed"); + return false; + } + if (cloexec) { + flags = flags | FD_CLOEXEC; + } else { + flags = flags & ~FD_CLOEXEC; + } + if (fcntl(fd, F_SETFD, flags) == -1) { + sway_log_errno(SWAY_ERROR, "fcntl failed"); + return false; + } + return true; +} + 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) { + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) != 0) { sway_log_errno(SWAY_ERROR, "socketpair failed"); return false; } + if (!set_cloexec(sockets[0], true) || !set_cloexec(sockets[1], true)) { + return false; + } output->swaybg_client = wl_client_create(server.wl_display, sockets[0]); if (output->swaybg_client == NULL) { @@ -202,14 +223,7 @@ static bool spawn_swaybg(struct sway_output *output, char *const cmd[]) { 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"); + if (!set_cloexec(sockets[1], false)) { exit(EXIT_FAILURE); } @@ -225,6 +239,10 @@ static bool spawn_swaybg(struct sway_output *output, char *const cmd[]) { exit(EXIT_SUCCESS); } + if (close(sockets[1]) != 0) { + sway_log_errno(SWAY_ERROR, "close failed"); + return false; + } if (waitpid(pid, NULL, 0) < 0) { sway_log_errno(SWAY_ERROR, "waitpid failed"); return false; From 9bbf10bdfcec1ed1fecb8c8033211dc8b8b66a66 Mon Sep 17 00:00:00 2001 From: Eric Drechsel Date: Mon, 18 Feb 2019 23:56:12 -0800 Subject: [PATCH 43/52] layout cmd: always operate on parent container, like i3Fixes #3724 --- sway/commands/layout.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sway/commands/layout.c b/sway/commands/layout.c index 2aca31dc5..7d61c3be3 100644 --- a/sway/commands/layout.c +++ b/sway/commands/layout.c @@ -111,10 +111,8 @@ struct cmd_results *cmd_layout(int argc, char **argv) { "Unable to change layout of floating windows"); } - // Typically we change the layout of the current container, but if the - // current container is a view (it usually is) then we'll change the layout - // of the parent instead, as it doesn't make sense for views to have layout. - if (container && container->view) { + // Operate on parent container, like i3. + if (container) { container = container->parent; } From 444e00662cc8e87d4334617904bf3578cb022911 Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 20 Feb 2019 11:16:05 +0100 Subject: [PATCH 44/52] Add wp-primary-selection-unstable-v1 --- sway/server.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sway/server.c b/sway/server.c index 712d8022b..0fcd58003 100644 --- a/sway/server.c +++ b/sway/server.c @@ -10,13 +10,14 @@ #include #include #include -#include #include +#include #include #include #include -#include #include +#include +#include #include #include #include @@ -122,6 +123,7 @@ bool server_init(struct sway_server *server) { wlr_export_dmabuf_manager_v1_create(server->wl_display); wlr_screencopy_manager_v1_create(server->wl_display); wlr_data_control_manager_v1_create(server->wl_display); + wlr_primary_selection_v1_device_manager_create(server->wl_display); server->socket = wl_display_add_socket_auto(server->wl_display); if (!server->socket) { From 546b976baa9989676c2fb2aff8c36f42b3d19810 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Wed, 20 Feb 2019 14:08:20 -0500 Subject: [PATCH 45/52] output_evacuate: call workspace_consider_destroy This calls `workspace_consider_destroy` on the workspace that was visible on an output that a workspace was just evacuated to. This prevents having hidden empty workspaces. --- sway/tree/output.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sway/tree/output.c b/sway/tree/output.c index 60e0af9f4..146bc4231 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -189,10 +189,19 @@ static void output_evacuate(struct sway_output *output) { continue; } + struct sway_workspace *new_output_ws = + output_get_active_workspace(new_output); + workspace_output_add_priority(workspace, new_output); output_add_workspace(new_output, workspace); output_sort_workspaces(new_output); ipc_event_workspace(NULL, workspace, "move"); + + // If there is an old workspace (the noop output may not have one), + // check to see if it is empty and should be destroyed. + if (new_output_ws) { + workspace_consider_destroy(new_output_ws); + } } } From a968a650e26b9f6bba134ee8dfa9865e958c29da Mon Sep 17 00:00:00 2001 From: Rouven Czerwinski Date: Thu, 21 Feb 2019 08:36:58 +0100 Subject: [PATCH 46/52] ipc-client: free payload after sending it over the socket Fixes memory leaks in the form of: Direct leak of 20 byte(s) in 1 object(s) allocated from: #0 0x7f5f7c2f4f30 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xedf30) #1 0x563c7995b36a in join_args ../common/stringop.c:268 #2 0x563c798a6a1a in main ../sway/main.c:348 #3 0x7f5f7b4d609a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2409a) --- sway/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sway/main.c b/sway/main.c index b118a1823..5a65e50cf 100644 --- a/sway/main.c +++ b/sway/main.c @@ -347,6 +347,7 @@ int main(int argc, char **argv) { } char *command = join_args(argv + optind, argc - optind); run_as_ipc_client(command, socket_path); + free(command); return 0; } From aa4ccd845cf93ac2117b12083fed748f4c01e744 Mon Sep 17 00:00:00 2001 From: Rouven Czerwinski Date: Thu, 21 Feb 2019 08:37:23 +0100 Subject: [PATCH 47/52] run_as_ipc_client: free response after running the IPC command Fixes memory leaks in the form of: Direct leak of 24 byte(s) in 1 object(s) allocated from: #0 0x7f5f7c2f4f30 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xedf30) #1 0x563c799569f2 in ipc_recv_response ../common/ipc-client.c:94 #2 0x563c79957062 in ipc_single_command ../common/ipc-client.c:138 #3 0x563c798a56cc in run_as_ipc_client ../sway/main.c:127 #4 0x563c798a6a3a in main ../sway/main.c:349 #5 0x7f5f7b4d609a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2409a) --- sway/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sway/main.c b/sway/main.c index 5a65e50cf..6754190f9 100644 --- a/sway/main.c +++ b/sway/main.c @@ -126,6 +126,7 @@ void run_as_ipc_client(char *command, char *socket_path) { uint32_t len = strlen(command); char *resp = ipc_single_command(socketfd, IPC_COMMAND, command, &len); printf("%s\n", resp); + free(resp); close(socketfd); } From 03dfdb1edbfc445fe30b6456827ae93ef6c18426 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Thu, 21 Feb 2019 08:06:35 -0500 Subject: [PATCH 48/52] output_get_active_workspace: check workspaces length If an output's node was dirty and the transaction was committed before a workspace was moved to or created for the output, the instruction would have a bad value for `state->active_workspace` due to a missing length check in `output_get_active_workspace`. If there was no focus on the output, the first workspace was being returned. If the workspace list was currently empty, the value was either garbage, or in the case of an output being disabled and re-enabled, a workspace that may have been previously freed. This just adds the length check to avoid returning out of bounds value. --- sway/desktop/output.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index c5461ee66..61beb7af3 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -320,6 +320,9 @@ struct sway_workspace *output_get_active_workspace(struct sway_output *output) { struct sway_seat *seat = input_manager_current_seat(); struct sway_node *focus = seat_get_active_tiling_child(seat, &output->node); if (!focus) { + if (!output->workspaces->length) { + return NULL; + } return output->workspaces->items[0]; } return focus->sway_workspace; From d3d7956576341bbbfb60d045175b0e8a44752e0b Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Thu, 21 Feb 2019 13:24:13 -0500 Subject: [PATCH 49/52] Handle NULL from output_get_active_workspace This modifies the places where output_get_active_workspace is called to handle a NULL result. Some places already handled it and did not need a change, some just have guard off code blocks, others return errors, and some have sway_asserts since the case should never happen. A lot of this is probably just safety precautions since they probably will never be called when `output_get_active_workspace` is not fully configured with a workspace. --- sway/commands/focus.c | 3 +++ sway/commands/move.c | 19 ++++++++++++++++++- sway/commands/sticky.c | 6 ++++++ sway/commands/swap.c | 4 ++++ sway/commands/titlebar_border_thickness.c | 7 ++++++- sway/desktop/output.c | 3 +++ sway/input/cursor.c | 3 +++ sway/ipc-json.c | 3 +++ sway/tree/container.c | 2 +- sway/tree/output.c | 3 +++ 10 files changed, 50 insertions(+), 3 deletions(-) diff --git a/sway/commands/focus.c b/sway/commands/focus.c index 79b2f551f..25df51304 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c @@ -37,6 +37,9 @@ static struct sway_node *get_node_in_output_direction( struct sway_output *output, enum wlr_direction dir) { struct sway_seat *seat = config->handler_context.seat; struct sway_workspace *ws = output_get_active_workspace(output); + if (!sway_assert(ws, "Expected output to have a workspace")) { + return NULL; + } if (ws->fullscreen) { return seat_get_focus_inactive(seat, &ws->fullscreen->node); } diff --git a/sway/commands/move.c b/sway/commands/move.c index 16f8cdb6f..d4fb90226 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -283,6 +283,9 @@ static bool container_move_in_direction(struct sway_container *container, return false; } struct sway_workspace *ws = output_get_active_workspace(new_output); + if (!sway_assert(ws, "Expected output to have a workspace")) { + return false; + } container_move_to_workspace(container, ws); return true; } @@ -360,6 +363,9 @@ static bool container_move_in_direction(struct sway_container *container, output_get_in_direction(container->workspace->output, move_dir); if (output) { struct sway_workspace *ws = output_get_active_workspace(output); + if (!sway_assert(ws, "Expected output to have a workspace")) { + return false; + } container_move_to_workspace_from_direction(container, ws, move_dir); return true; } @@ -525,6 +531,10 @@ static struct cmd_results *cmd_move_container(int argc, char **argv) { case N_OUTPUT: { struct sway_output *output = destination->sway_output; struct sway_workspace *ws = output_get_active_workspace(output); + if (!sway_assert(ws, "Expected output to have a workspace")) { + return cmd_results_new(CMD_FAILURE, + "Expected output to have a workspace"); + } container_move_to_workspace(container, ws); } break; @@ -538,7 +548,11 @@ static struct cmd_results *cmd_move_container(int argc, char **argv) { // restore focus on destination output back to its last active workspace struct sway_workspace *new_workspace = output_get_active_workspace(new_output); - if (new_output_last_ws && new_output_last_ws != new_workspace) { + if (!sway_assert(new_workspace, "Expected output to have a workspace")) { + return cmd_results_new(CMD_FAILURE, + "Expected output to have a workspace"); + } + if (new_output_last_ws != new_workspace) { struct sway_node *new_output_last_focus = seat_get_focus_inactive(seat, &new_output_last_ws->node); seat_set_raw_focus(seat, new_output_last_focus); @@ -585,6 +599,9 @@ static void workspace_move_to_output(struct sway_workspace *workspace, workspace_detach(workspace); struct sway_workspace *new_output_old_ws = output_get_active_workspace(output); + if (!sway_assert(new_output_old_ws, "Expected output to have a workspace")) { + return; + } output_add_workspace(output, workspace); diff --git a/sway/commands/sticky.c b/sway/commands/sticky.c index 5b70199cb..9df1fe09d 100644 --- a/sway/commands/sticky.c +++ b/sway/commands/sticky.c @@ -9,6 +9,7 @@ #include "sway/tree/view.h" #include "sway/tree/workspace.h" #include "list.h" +#include "log.h" #include "util.h" struct cmd_results *cmd_sticky(int argc, char **argv) { @@ -29,6 +30,11 @@ struct cmd_results *cmd_sticky(int argc, char **argv) { // move container to active workspace struct sway_workspace *active_workspace = output_get_active_workspace(container->workspace->output); + if (!sway_assert(active_workspace, + "Expected output to have a workspace")) { + return cmd_results_new(CMD_FAILURE, + "Expected output to have a workspace"); + } if (container->workspace != active_workspace) { struct sway_workspace *old_workspace = container->workspace; container_detach(container); diff --git a/sway/commands/swap.c b/sway/commands/swap.c index 0e2c2d105..b978af162 100644 --- a/sway/commands/swap.c +++ b/sway/commands/swap.c @@ -118,6 +118,10 @@ static void container_swap(struct sway_container *con1, output_get_active_workspace(con1->workspace->output); struct sway_workspace *vis2 = output_get_active_workspace(con2->workspace->output); + if (!sway_assert(vis1 && vis2, "con1 or con2 are on an output without a" + "workspace. This should not happen")) { + return; + } char *stored_prev_name = NULL; if (seat->prev_workspace_name) { diff --git a/sway/commands/titlebar_border_thickness.c b/sway/commands/titlebar_border_thickness.c index 3c5e9ba12..7c27c163a 100644 --- a/sway/commands/titlebar_border_thickness.c +++ b/sway/commands/titlebar_border_thickness.c @@ -21,7 +21,12 @@ struct cmd_results *cmd_titlebar_border_thickness(int argc, char **argv) { for (int i = 0; i < root->outputs->length; ++i) { struct sway_output *output = root->outputs->items[i]; - arrange_workspace(output_get_active_workspace(output)); + struct sway_workspace *ws = output_get_active_workspace(output); + if (!sway_assert(ws, "Expected output to have a workspace")) { + return cmd_results_new(CMD_FAILURE, + "Expected output to have a workspace"); + } + arrange_workspace(ws); output_damage_whole(output); } diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 61beb7af3..d7d3fc07e 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -251,6 +251,9 @@ static void output_for_each_surface(struct sway_output *output, }; struct sway_workspace *workspace = output_get_active_workspace(output); + if (!workspace) { + return; + } struct sway_container *fullscreen_con = root->fullscreen_global; if (fullscreen_con && container_is_scratchpad_hidden(fullscreen_con)) { fullscreen_con = NULL; diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 170532bea..3236c74a1 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -104,6 +104,9 @@ struct sway_node *node_at_coords( // find the focused workspace on the output for this seat struct sway_workspace *ws = output_get_active_workspace(output); + if (!ws) { + return NULL; + } if ((*surface = layer_surface_at(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 6d36c7274..a2ab2bba8 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -198,6 +198,9 @@ static void ipc_json_describe_output(struct sway_output *output, ipc_json_output_transform_description(wlr_output->transform))); struct sway_workspace *ws = output_get_active_workspace(output); + if (!sway_assert(ws, "Expected output to have a workspace")) { + return; + } json_object_object_add(object, "current_workspace", json_object_new_string(ws->name)); diff --git a/sway/tree/container.c b/sway/tree/container.c index 9358dad76..933907f4e 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -831,7 +831,7 @@ void container_floating_move_to(struct sway_container *con, } struct sway_workspace *new_workspace = output_get_active_workspace(new_output); - if (old_workspace != new_workspace) { + if (new_workspace && old_workspace != new_workspace) { container_detach(con); workspace_add_floating(new_workspace, con); arrange_workspace(old_workspace); diff --git a/sway/tree/output.c b/sway/tree/output.c index 146bc4231..e0a66e0bd 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -143,6 +143,9 @@ void output_enable(struct sway_output *output, struct output_config *oc) { static void evacuate_sticky(struct sway_workspace *old_ws, struct sway_output *new_output) { struct sway_workspace *new_ws = output_get_active_workspace(new_output); + if (!sway_assert(new_ws, "New output does not have a workspace")) { + return; + } while (old_ws->floating->length) { struct sway_container *sticky = old_ws->floating->items[0]; container_detach(sticky); From 16ddd00102c7713b7d1c404393768eb06c829751 Mon Sep 17 00:00:00 2001 From: Rouven Czerwinski Date: Fri, 22 Feb 2019 06:42:40 +0100 Subject: [PATCH 50/52] commands/move: reintroduce wrongly removed NULL check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit d3d7956576341bbbfb60d045175b0e8a44752e0b removed this NULL check, which leads to the following backtrace: #0 0x0000557bd201df46 in node_is_view (node=0x0) at ../sway/sway/tree/node.c:41 #1 0x0000557bd1ff5d4e in seat_get_focus_inactive (seat=0x557bd3fc7580, node=0x0) at ../sway/sway/input/seat.c:968 current = 0x557bd2033485 #2 0x0000557bd2009f24 in cmd_move_container (argc=3, argv=0x557bd46b19c0) at ../sway/sway/commands/move.c:557 new_output_last_focus = 0x0 error = 0x0 node = 0x557bd469f360 workspace = 0x557bd4572ee0 container = 0x557bd469f360 no_auto_back_and_forth = false seat = 0x557bd3fc7580 old_parent = 0x0 old_ws = 0x557bd4572ee0 old_output = 0x557bd411f740 destination = 0x557bd46a0cc0 new_output = 0x557bd411f740 new_output_last_ws = 0x0 focus = 0x557bd469f360 __PRETTY_FUNCTION__ = "cmd_move_container" new_workspace = 0x557bd4572ee0 […] Reintroduce the NULL check to fix the bug. Fixes #3746 --- sway/commands/move.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/commands/move.c b/sway/commands/move.c index d4fb90226..b593138af 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -552,7 +552,7 @@ static struct cmd_results *cmd_move_container(int argc, char **argv) { return cmd_results_new(CMD_FAILURE, "Expected output to have a workspace"); } - if (new_output_last_ws != new_workspace) { + if (new_output_last_ws && new_output_last_ws != new_workspace) { struct sway_node *new_output_last_focus = seat_get_focus_inactive(seat, &new_output_last_ws->node); seat_set_raw_focus(seat, new_output_last_focus); From 7252ca09a7ccd09673a2903509cde6dcb077bfb7 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Fri, 22 Feb 2019 00:10:02 -0500 Subject: [PATCH 51/52] move scratchpad: hide visible scratchpad container This makes it so running `move [to] scratchpad` on a container already in the scratchpad does not return an error. To match i3's behavior, a visible scratchpad container will be hidden and a hidden scratchpad container will be treated as a noop. --- sway/commands/move.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sway/commands/move.c b/sway/commands/move.c index b593138af..4306aac86 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -854,11 +854,11 @@ static struct cmd_results *cmd_move_to_scratchpad(void) { } } - if (con->scratchpad) { - return cmd_results_new(CMD_INVALID, - "Container is already in the scratchpad"); + if (!con->scratchpad) { + root_scratchpad_add_container(con); + } else if (con->workspace) { + root_scratchpad_hide(con); } - root_scratchpad_add_container(con); return cmd_results_new(CMD_SUCCESS, NULL); } From f078a1ccb899e04d24ba76418bdf574aa45c9c7e Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Fri, 22 Feb 2019 02:48:57 -0500 Subject: [PATCH 52/52] input/cursor: allow whole-window bindings on ws To match i3's behavior, this allows mouse bindings to be triggered over a workspace when `--whole-window` is given. --- sway/input/cursor.c | 23 +++++++++++++++-------- sway/sway.5.scd | 6 +++--- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 3236c74a1..fb1edd0b0 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -552,10 +552,11 @@ static void state_add_button(struct sway_cursor *cursor, uint32_t button) { static struct sway_binding* get_active_mouse_binding( const struct sway_cursor *cursor, list_t *bindings, uint32_t modifiers, bool release, bool on_titlebar, bool on_border, bool on_content, - const char *identifier) { - uint32_t click_region = (on_titlebar ? BINDING_TITLEBAR : 0) | - (on_border ? BINDING_BORDER : 0) | - (on_content ? BINDING_CONTENTS : 0); + bool on_workspace, const char *identifier) { + uint32_t click_region = + ((on_titlebar || on_workspace) ? BINDING_TITLEBAR : 0) | + ((on_border || on_workspace) ? BINDING_BORDER : 0) | + ((on_content || on_workspace) ? BINDING_CONTENTS : 0); struct sway_binding *current = NULL; for (int i = 0; i < bindings->length; ++i) { @@ -564,6 +565,8 @@ static struct sway_binding* get_active_mouse_binding( cursor->pressed_button_count != (size_t)binding->keys->length || release != (binding->flags & BINDING_RELEASE) || !(click_region & binding->flags) || + (on_workspace && + (click_region & binding->flags) != click_region) || (strcmp(binding->input, identifier) != 0 && strcmp(binding->input, "*") != 0)) { continue; @@ -629,6 +632,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, find_resize_edge(cont, cursor) : WLR_EDGE_NONE; bool on_border = edge != WLR_EDGE_NONE; bool on_contents = cont && !on_border && surface; + bool on_workspace = node && node->type == N_WORKSPACE; bool on_titlebar = cont && !on_border && !surface; // Handle mouse bindings @@ -642,11 +646,13 @@ void dispatch_cursor_button(struct sway_cursor *cursor, state_add_button(cursor, button); binding = get_active_mouse_binding(cursor, config->current_mode->mouse_bindings, modifiers, false, - on_titlebar, on_border, on_contents, device_identifier); + on_titlebar, on_border, on_contents, on_workspace, + device_identifier); } else { binding = get_active_mouse_binding(cursor, config->current_mode->mouse_bindings, modifiers, true, - on_titlebar, on_border, on_contents, device_identifier); + on_titlebar, on_border, on_contents, on_workspace, + device_identifier); state_erase_button(cursor, button); } free(device_identifier); @@ -836,6 +842,7 @@ void dispatch_cursor_axis(struct sway_cursor *cursor, bool on_titlebar_border = cont && on_border && cursor->cursor->y < cont->content_y; bool on_contents = cont && !on_border && surface; + bool on_workspace = node && node->type == N_WORKSPACE; float scroll_factor = (ic == NULL || ic->scroll_factor == FLT_MIN) ? 1.0f : ic->scroll_factor; @@ -854,7 +861,7 @@ void dispatch_cursor_axis(struct sway_cursor *cursor, state_add_button(cursor, button); binding = get_active_mouse_binding(cursor, config->current_mode->mouse_bindings, modifiers, false, - on_titlebar, on_border, on_contents, dev_id); + on_titlebar, on_border, on_contents, on_workspace, dev_id); if (binding) { seat_execute_command(seat, binding); handled = true; @@ -895,7 +902,7 @@ void dispatch_cursor_axis(struct sway_cursor *cursor, // Handle mouse bindings - x11 mouse buttons 4-7 - release event binding = get_active_mouse_binding(cursor, config->current_mode->mouse_bindings, modifiers, true, - on_titlebar, on_border, on_contents, dev_id); + on_titlebar, on_border, on_contents, on_workspace, dev_id); state_erase_button(cursor, button); if (binding) { seat_execute_command(seat, binding); diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 76467d23a..1affca5fe 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -310,9 +310,9 @@ runtime. conjunction with any other option to specify that the titlebar should be excluded from the region of consideration. - There is currently, however, no way to execute a mouse binding over a layer - surface (which includes the background of an empty workspace). This behaviour - is carried over from i3. + If _--whole-window_ is given, the command can be triggered when the cursor + is over an empty workspace. Using a mouse binding over a layer surface's + exclusive region is not currently possible. Example: ```