From 1c992d847d66161a28f12bfc7028966433fb249c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 13 Jul 2024 13:01:46 +0200 Subject: [PATCH 01/71] ci: pin wlroots to v0.18.x --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 2 +- .builds/freebsd.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 7a1fa58e0..c3b80390d 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -25,7 +25,7 @@ packages: - hwdata-dev sources: - https://github.com/swaywm/sway - - https://gitlab.freedesktop.org/wlroots/wlroots.git + - https://gitlab.freedesktop.org/wlroots/wlroots.git#0.18 tasks: - wlroots: | cd wlroots diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index e249571ee..cbc4e545b 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -22,7 +22,7 @@ packages: - hwdata sources: - https://github.com/swaywm/sway - - https://gitlab.freedesktop.org/wlroots/wlroots.git + - https://gitlab.freedesktop.org/wlroots/wlroots.git#0.18 tasks: - wlroots: | cd wlroots diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 8084574c2..f7d35cfb4 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -31,7 +31,7 @@ packages: - misc/hwdata sources: - https://github.com/swaywm/sway -- https://gitlab.freedesktop.org/wlroots/wlroots.git +- https://gitlab.freedesktop.org/wlroots/wlroots.git#0.18 tasks: - setup: | cd sway From 6320aef295ef82613c54c5b1519f64a8a4e25cb3 Mon Sep 17 00:00:00 2001 From: Bill Li Date: Mon, 15 Jul 2024 05:16:40 +0800 Subject: [PATCH 02/71] ci: use package x11-servers/xwayland instead of x11-servers/xwayland-devel (cherry picked from commit 50073dc579fffffda8a4de903719b9bbb9d5ac3d) --- .builds/freebsd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index f7d35cfb4..5276ee8e2 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -27,7 +27,7 @@ packages: - x11/libX11 - x11/pixman - x11/xcb-util-wm -- x11-servers/xwayland-devel +- x11-servers/xwayland - misc/hwdata sources: - https://github.com/swaywm/sway From 19ca790a9f304bb138e531719a8a42f145f835f9 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 15 Jul 2024 00:12:39 +0200 Subject: [PATCH 03/71] desktop/output: Stop repaint loop when not needed 1e0031781fc9 refactored repaint to accumulate all changes in a single wlr_output_state and commit them at the end of the repaint loop, replacing a call to wlr_scene_output_commit. wlr_scene_output_commit contains an early bail-out when no frame has been requested and no damage has accumulated, which was not replicated as part of this refactor, causing the repaint loop to never pause. Replicate the logic to stop the repaint loop as needed. Fixes: 1e0031781fc9 ("desktop/output: unify page-flip codepath") (cherry picked from commit 3f327b3db0c1fc6985c0ed3231e1bd6296584dad) --- sway/desktop/output.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index f936b2a8d..27ede68ee 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -247,6 +247,13 @@ static int output_repaint_timer_handler(void *data) { .color_transform = output->color_transform, }; + struct wlr_output *wlr_output = output->wlr_output; + struct wlr_scene_output *scene_output = output->scene_output; + if (!wlr_output->needs_frame && !output->gamma_lut_changed && + !pixman_region32_not_empty(&scene_output->pending_commit_damage)) { + return 0; + } + struct wlr_output_state pending; wlr_output_state_init(&pending); if (!wlr_scene_output_build_state(output->scene_output, &pending, &opts)) { From 100f92a189b89e3c3199c87d4884a101e5c99742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joan=20Bruguera=20Mic=C3=B3?= Date: Sat, 20 Jul 2024 22:34:01 +0000 Subject: [PATCH 04/71] layer-shell: Restore interactive layer focus code Commit 188811f80861 ("scene_graph: Port layer_shell") accidentally removed code in `arrange_layers` to handle focus on layer shell surfaces with keyboard interactivity. Due to this, layer shell surfaces requesting exclusive keyboard interactivity may not get automatically focused, and layer shell surfaces giving up exclusive keyboard interactivity can remain focused. Add the previous code back to fix the problem. Note the non-rename change included in b4d7e84d3852 ("desktop: Rename layers to shell_layers") is not included as it also seems accidental. Fixes: #7936 (cherry picked from commit 4d4c88f0a73f6ee3da1c99355f04362ef2ad68c9) --- sway/desktop/layer_shell.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 6221b7b97..b136a24e7 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -90,6 +90,43 @@ void arrange_layers(struct sway_output *output) { } else { arrange_popups(root->layers.popup); } + + // Find topmost keyboard interactive layer, if such a layer exists + struct wlr_scene_tree *layers_above_shell[] = { + output->layers.shell_overlay, + output->layers.shell_top, + }; + size_t nlayers = sizeof(layers_above_shell) / sizeof(layers_above_shell[0]); + struct wlr_scene_node *node; + struct sway_layer_surface *topmost = NULL; + for (size_t i = 0; i < nlayers; ++i) { + wl_list_for_each_reverse(node, + &layers_above_shell[i]->children, link) { + struct sway_layer_surface *surface = scene_descriptor_try_get(node, + SWAY_SCENE_DESC_LAYER_SHELL); + if (surface && surface->layer_surface->current.keyboard_interactive + == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE && + surface->layer_surface->surface->mapped) { + topmost = surface; + break; + } + } + if (topmost != NULL) { + break; + } + } + + struct sway_seat *seat; + wl_list_for_each(seat, &server.input->seats, link) { + seat->has_exclusive_layer = false; + if (topmost != NULL) { + seat_set_focus_layer(seat, topmost->layer_surface); + } else if (seat->focused_layer && + seat->focused_layer->current.keyboard_interactive + != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) { + seat_set_focus_layer(seat, NULL); + } + } } static struct wlr_scene_tree *sway_layer_get_scene(struct sway_output *output, From 53ffc1119a540134119e2094018d8a376d07aeaf Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 29 Jul 2024 20:14:18 +0200 Subject: [PATCH 05/71] desktop/xwayland: don't restack when marking window as inactive daaec72ac01f ("desktop/xwayland: restack surface upon activation") has updated Sway for wlroots commit bfc69decdd04 ("xwm: do not restack surfaces on activation"). However, it unconditionally restacks the window above all other windows even if marking the window as inactive. Closes: https://github.com/swaywm/sway/issues/7974 (cherry picked from commit 7e74a4914261cf32c45017521960adf7ff6dac8f) --- sway/desktop/xwayland.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 270cf08f8..9a6614056 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -289,7 +289,9 @@ static void set_activated(struct sway_view *view, bool activated) { } wlr_xwayland_surface_activate(surface, activated); - wlr_xwayland_surface_restack(surface, NULL, XCB_STACK_MODE_ABOVE); + if (activated) { + wlr_xwayland_surface_restack(surface, NULL, XCB_STACK_MODE_ABOVE); + } } static void set_tiled(struct sway_view *view, bool tiled) { From 8b923a3623a0ea678894e70b6595a8ac52f5c17e Mon Sep 17 00:00:00 2001 From: James Knight Date: Sat, 3 Aug 2024 12:30:17 -0400 Subject: [PATCH 06/71] build: avoid git repository discovery when determining version When attempting to use Git to populate commit/branch information in a version string, it is possible through repository discovery that it uses Git information not relevant to project. For example, if repository content is extract into an interim build location when using an embedded build framework (e.g. Buildroot), the project will not have its Git repository to refer to. When it cannot find its repository, it will look into its parent folders and may find the Git repository of another project and use its branch/commit information. This commit provides an explicit path to the project's Git repository when consider commit/branch information. This will prevent any repository discovery from occurring. Signed-off-by: James Knight (cherry picked from commit 6e4ccb99c3a2197468f8f34c290b7cd5612ff80b) --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index c602d008b..6999e199c 100644 --- a/meson.build +++ b/meson.build @@ -160,8 +160,8 @@ add_project_arguments('-DSYSCONFDIR="/@0@"'.format(join_paths(prefix, sysconfdir version = '"@0@"'.format(meson.project_version()) git = find_program('git', native: true, required: false) if git.found() - git_commit = run_command([git, 'rev-parse', '--short', 'HEAD'], check: false) - git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD'], check: false) + git_commit = run_command([git, '--git-dir=.git', 'rev-parse', '--short', 'HEAD'], check: false) + git_branch = run_command([git, '--git-dir=.git', 'rev-parse', '--abbrev-ref', 'HEAD'], check: false) if git_commit.returncode() == 0 and git_branch.returncode() == 0 version = '"@0@-@1@ (" __DATE__ ", branch \'@2@\')"'.format( meson.project_version(), From b4ab8182b7f3f9c2c0ac0c28719f6f71808a36d8 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 10 Jul 2024 12:20:53 -0400 Subject: [PATCH 07/71] transaction: Reparent all container children when disabling for scratchpad Fixes: #8205 (cherry picked from commit b881c2e84c4be3c7b996f85200cfe391a7979267) --- sway/desktop/transaction.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 7568990bf..2ee5a5dff 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -632,6 +632,15 @@ static void arrange_root(struct sway_root *root) { for (int i = 0; i < root->scratchpad->length; i++) { struct sway_container *con = root->scratchpad->items[i]; + // When a container is moved to a scratchpad, it's possible that it + // was moved into a floating container as part of the same transaction. + // In this case, we need to make sure we reparent all the container's + // children so that disabling the container will disable all descendants. + if (!con->view) for (int ii = 0; ii < con->current.children->length; ii++) { + struct sway_container *child = con->current.children->items[ii]; + wlr_scene_node_reparent(&child->scene_tree->node, con->content_tree); + } + wlr_scene_node_set_enabled(&con->scene_tree->node, false); } From 01f5c50438ba660f28b8f7707e53f4d4dc74ef01 Mon Sep 17 00:00:00 2001 From: Ricardo Steijn <61013287+RicArch97@users.noreply.github.com> Date: Mon, 5 Aug 2024 02:13:49 +0200 Subject: [PATCH 08/71] Add support for tearing-control-v1 References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3871 Adds option to allow tearing per output, as well as an option to force enable or disable tearing for a specific application using a window rule. Only works with fullscreen applications. (cherry picked from commit 9a1c411abd8261c121dcd50dfe54132718768084) --- include/sway/commands.h | 2 + include/sway/config.h | 1 + include/sway/output.h | 1 + include/sway/server.h | 6 +++ include/sway/tree/view.h | 12 ++++++ protocols/meson.build | 1 + sway/commands.c | 1 + sway/commands/allow_tearing.c | 24 +++++++++++ sway/commands/output.c | 1 + sway/commands/output/allow_tearing.c | 23 +++++++++++ sway/config/output.c | 16 ++++++- sway/desktop/output.c | 28 +++++++++++++ sway/desktop/tearing.c | 62 ++++++++++++++++++++++++++++ sway/ipc-json.c | 4 ++ sway/meson.build | 3 ++ sway/server.c | 7 ++++ sway/sway-output.5.scd | 20 +++++++++ sway/sway.5.scd | 14 +++++++ sway/tree/view.c | 14 +++++++ swaymsg/main.c | 6 ++- 20 files changed, 243 insertions(+), 3 deletions(-) create mode 100644 sway/commands/allow_tearing.c create mode 100644 sway/commands/output/allow_tearing.c create mode 100644 sway/desktop/tearing.c diff --git a/include/sway/commands.h b/include/sway/commands.h index 15cd86982..5210d3ba7 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -104,6 +104,7 @@ struct sway_container *container_find_resize_parent(struct sway_container *con, sway_cmd cmd_exec_validate; sway_cmd cmd_exec_process; +sway_cmd cmd_allow_tearing; sway_cmd cmd_assign; sway_cmd cmd_bar; sway_cmd cmd_bindcode; @@ -283,6 +284,7 @@ sway_cmd input_cmd_xkb_switch_layout; sway_cmd input_cmd_xkb_variant; sway_cmd output_cmd_adaptive_sync; +sway_cmd output_cmd_allow_tearing; sway_cmd output_cmd_background; sway_cmd output_cmd_color_profile; sway_cmd output_cmd_disable; diff --git a/include/sway/config.h b/include/sway/config.h index dfa3c1b7b..d9f561571 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -289,6 +289,7 @@ struct output_config { enum render_bit_depth render_bit_depth; bool set_color_transform; struct wlr_color_transform *color_transform; + int allow_tearing; char *background; char *background_option; diff --git a/include/sway/output.h b/include/sway/output.h index 2189c6e87..7e2d58927 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -73,6 +73,7 @@ struct sway_output { int max_render_time; // In milliseconds struct wl_event_source *repaint_timer; bool gamma_lut_changed; + bool allow_tearing; }; struct sway_output_non_desktop { diff --git a/include/sway/server.h b/include/sway/server.h index abf1b6b4e..460f9e17f 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -115,6 +115,10 @@ struct sway_server { struct wl_listener xdg_activation_v1_new_token; struct wl_listener request_set_cursor_shape; + + struct wlr_tearing_control_manager_v1 *tearing_control_v1; + struct wl_listener tearing_control_new_object; + struct wl_list tearing_controllers; // sway_tearing_controller::link struct wl_list pending_launcher_ctxs; // launcher_ctx::link @@ -182,4 +186,6 @@ void xdg_activation_v1_handle_new_token(struct wl_listener *listener, void set_rr_scheduling(void); +void handle_new_tearing_hint(struct wl_listener *listener, void *data); + #endif diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 3ae8cf224..14aad1a18 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "sway/config.h" #if WLR_HAS_XWAYLAND #include @@ -34,6 +35,12 @@ enum sway_view_prop { #endif }; +enum sway_view_tearing_mode { + TEARING_OVERRIDE_FALSE, + TEARING_OVERRIDE_TRUE, + TEARING_WINDOW_HINT, +}; + struct sway_view_impl { void (*get_constraints)(struct sway_view *view, double *min_width, double *max_width, double *min_height, double *max_height); @@ -111,6 +118,9 @@ struct sway_view { int max_render_time; // In milliseconds enum seat_config_shortcuts_inhibit shortcuts_inhibit; + + enum sway_view_tearing_mode tearing_mode; + enum wp_tearing_control_v1_presentation_hint tearing_hint; }; struct sway_xdg_shell_view { @@ -335,4 +345,6 @@ void view_assign_ctx(struct sway_view *view, struct launcher_ctx *ctx); void view_send_frame_done(struct sway_view *view); +bool view_can_tear(struct sway_view *view); + #endif diff --git a/protocols/meson.build b/protocols/meson.build index 6eac8542c..d96f87575 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -14,6 +14,7 @@ protocols = [ wl_protocol_dir / 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml', wl_protocol_dir / 'staging/content-type/content-type-v1.xml', wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml', + wl_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml', 'wlr-layer-shell-unstable-v1.xml', 'idle.xml', 'wlr-output-power-management-unstable-v1.xml', diff --git a/sway/commands.c b/sway/commands.c index 8d003dfa6..c2c12ee65 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -112,6 +112,7 @@ static const struct cmd_handler config_handlers[] = { /* Runtime-only commands. Keep alphabetized */ static const struct cmd_handler command_handlers[] = { + { "allow_tearing", cmd_allow_tearing }, { "border", cmd_border }, { "create_output", cmd_create_output }, { "exit", cmd_exit }, diff --git a/sway/commands/allow_tearing.c b/sway/commands/allow_tearing.c new file mode 100644 index 000000000..ee5941381 --- /dev/null +++ b/sway/commands/allow_tearing.c @@ -0,0 +1,24 @@ +#include +#include "sway/config.h" +#include "sway/tree/view.h" +#include "util.h" + +struct cmd_results *cmd_allow_tearing(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "allow_tearing", EXPECTED_AT_LEAST, 1))) { + return error; + } + + struct sway_container *container = config->handler_context.container; + if (!container || !container->view) { + return cmd_results_new(CMD_INVALID, "Tearing can only be allowed on views"); + } + + bool wants_tearing = parse_boolean(argv[0], true); + + struct sway_view *view = container->view; + view->tearing_mode = wants_tearing ? TEARING_OVERRIDE_TRUE : + TEARING_OVERRIDE_FALSE; + + return cmd_results_new(CMD_SUCCESS, NULL); +} diff --git a/sway/commands/output.c b/sway/commands/output.c index b822e770a..9478e0bad 100644 --- a/sway/commands/output.c +++ b/sway/commands/output.c @@ -8,6 +8,7 @@ // must be in order for the bsearch static const struct cmd_handler output_handlers[] = { { "adaptive_sync", output_cmd_adaptive_sync }, + { "allow_tearing", output_cmd_allow_tearing }, { "background", output_cmd_background }, { "bg", output_cmd_background }, { "color_profile", output_cmd_color_profile }, diff --git a/sway/commands/output/allow_tearing.c b/sway/commands/output/allow_tearing.c new file mode 100644 index 000000000..9a183b96c --- /dev/null +++ b/sway/commands/output/allow_tearing.c @@ -0,0 +1,23 @@ +#include "sway/commands.h" +#include "sway/config.h" +#include "util.h" + +struct cmd_results *output_cmd_allow_tearing(int argc, char **argv) { + if (!config->handler_context.output_config) { + return cmd_results_new(CMD_FAILURE, "Missing output config"); + } + if (argc == 0) { + return cmd_results_new(CMD_INVALID, "Missing allow_tearing argument"); + } + + if (parse_boolean(argv[0], + (config->handler_context.output_config->allow_tearing == 1))) { + config->handler_context.output_config->allow_tearing = 1; + } else { + config->handler_context.output_config->allow_tearing = 0; + } + + config->handler_context.leftovers.argc = argc - 1; + config->handler_context.leftovers.argv = argv + 1; + return NULL; +} diff --git a/sway/config/output.c b/sway/config/output.c index e64efb7ff..940c75fe3 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -79,6 +79,7 @@ struct output_config *new_output_config(const char *name) { oc->set_color_transform = false; oc->color_transform = NULL; oc->power = -1; + oc->allow_tearing = -1; return oc; } @@ -216,6 +217,9 @@ static void merge_output_config(struct output_config *dst, struct output_config if (src->power != -1) { dst->power = src->power; } + if (src->allow_tearing != -1) { + dst->allow_tearing = src->allow_tearing; + } } void store_output_config(struct output_config *oc) { @@ -258,11 +262,11 @@ void store_output_config(struct output_config *oc) { sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz " "position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (power %d) " - "(max render time: %d)", + "(max render time: %d) (allow tearing: %d)", oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate, oc->x, oc->y, oc->scale, sway_wl_output_subpixel_to_string(oc->subpixel), oc->transform, oc->background, oc->background_option, oc->power, - oc->max_render_time); + oc->max_render_time, oc->allow_tearing); // If the configuration was not merged into an existing configuration, add // it to the list. Otherwise we're done with it and can free it. @@ -574,6 +578,13 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output wlr_color_transform_unref(output->color_transform); output->color_transform = oc->color_transform; } + + if (oc && oc->allow_tearing >= 0) { + sway_log(SWAY_DEBUG, "Set %s allow tearing to %d", + oc->name, oc->allow_tearing); + output->allow_tearing = oc->allow_tearing; + } + return true; } @@ -594,6 +605,7 @@ static void default_output_config(struct output_config *oc, oc->subpixel = output->detected_subpixel; oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; oc->max_render_time = 0; + oc->allow_tearing = 0; } // find_output_config returns a merged output_config containing all stored diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 27ede68ee..f1e08eff8 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -232,6 +232,23 @@ static void output_configure_scene(struct sway_output *output, } } +static bool output_can_tear(struct sway_output *output) { + struct sway_workspace *workspace = output->current.active_workspace; + if (!workspace) { + return false; + } + + struct sway_container *fullscreen_con = root->fullscreen_global; + if (!fullscreen_con) { + fullscreen_con = workspace->current.fullscreen; + } + if (fullscreen_con && fullscreen_con->view) { + return (output->allow_tearing && view_can_tear(fullscreen_con->view)); + } + + return false; +} + static int output_repaint_timer_handler(void *data) { struct sway_output *output = data; @@ -275,6 +292,17 @@ static int output_repaint_timer_handler(void *data) { wlr_output_state_set_gamma_lut(&pending, 0, NULL, NULL, NULL); } } + + if (output_can_tear(output)) { + pending.tearing_page_flip = true; + + if (!wlr_output_test_state(output->wlr_output, &pending)) { + sway_log(SWAY_DEBUG, "Output test failed on '%s', retrying without tearing page-flip", + output->wlr_output->name); + + pending.tearing_page_flip = false; + } + } if (!wlr_output_commit_state(output->wlr_output, &pending)) { sway_log(SWAY_ERROR, "Page-flip failed on output %s", output->wlr_output->name); diff --git a/sway/desktop/tearing.c b/sway/desktop/tearing.c new file mode 100644 index 000000000..36cc48bfe --- /dev/null +++ b/sway/desktop/tearing.c @@ -0,0 +1,62 @@ +#include +#include +#include "sway/server.h" +#include "sway/tree/view.h" +#include "sway/output.h" +#include "log.h" + +struct sway_tearing_controller { + struct wlr_tearing_control_v1 *tearing_control; + struct wl_listener set_hint; + struct wl_listener destroy; + + struct wl_list link; // sway_server::tearing_controllers +}; + +static void handle_tearing_controller_set_hint(struct wl_listener *listener, + void *data) { + struct sway_tearing_controller *controller = + wl_container_of(listener, controller, set_hint); + + struct sway_view *view = view_from_wlr_surface( + controller->tearing_control->surface); + if (view) { + view->tearing_hint = controller->tearing_control->current; + } +} + +static void handle_tearing_controller_destroy(struct wl_listener *listener, + void *data) { + struct sway_tearing_controller *controller = + wl_container_of(listener, controller, destroy); + wl_list_remove(&controller->link); + free(controller); +} + +void handle_new_tearing_hint(struct wl_listener *listener, + void *data) { + struct sway_server *server = + wl_container_of(listener, server, tearing_control_new_object); + struct wlr_tearing_control_v1 *tearing_control = data; + + enum wp_tearing_control_v1_presentation_hint hint = + wlr_tearing_control_manager_v1_surface_hint_from_surface( + server->tearing_control_v1, tearing_control->surface); + sway_log(SWAY_DEBUG, "New presentation hint %d received for surface %p", + hint, tearing_control->surface); + + struct sway_tearing_controller *controller = + calloc(1, sizeof(struct sway_tearing_controller)); + if (!controller) { + return; + } + + controller->tearing_control = tearing_control; + controller->set_hint.notify = handle_tearing_controller_set_hint; + wl_signal_add(&tearing_control->events.set_hint, &controller->set_hint); + controller->destroy.notify = handle_tearing_controller_destroy; + wl_signal_add(&tearing_control->events.destroy, &controller->destroy); + wl_list_init(&controller->link); + + wl_list_insert(&server->tearing_controllers, &controller->link); +} diff --git a/sway/ipc-json.c b/sway/ipc-json.c index e512a2239..8eaa8324a 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -399,6 +399,8 @@ static void ipc_json_describe_enabled_output(struct sway_output *output, } json_object_object_add(object, "max_render_time", json_object_new_int(output->max_render_time)); + + json_object_object_add(object, "allow_tearing", json_object_new_boolean(output->allow_tearing)); } json_object *ipc_json_describe_disabled_output(struct sway_output *output) { @@ -593,6 +595,8 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object json_object_object_add(object, "max_render_time", json_object_new_int(c->view->max_render_time)); + json_object_object_add(object, "allow_tearing", json_object_new_boolean(view_can_tear(c->view))); + json_object_object_add(object, "shell", json_object_new_string(view_get_shell(c->view))); json_object_object_add(object, "inhibit_idle", diff --git a/sway/meson.build b/sway/meson.build index 2f4406abb..8042c89be 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -18,6 +18,7 @@ sway_sources = files( 'desktop/idle_inhibit_v1.c', 'desktop/layer_shell.c', 'desktop/output.c', + 'desktop/tearing.c', 'desktop/transaction.c', 'desktop/xdg_shell.c', 'desktop/launcher.c', @@ -41,6 +42,7 @@ sway_sources = files( 'config/seat.c', 'config/input.c', + 'commands/allow_tearing.c', 'commands/assign.c', 'commands/bar.c', 'commands/bind.c', @@ -188,6 +190,7 @@ sway_sources = files( 'commands/input/xkb_variant.c', 'commands/output/adaptive_sync.c', + 'commands/output/allow_tearing.c', 'commands/output/background.c', 'commands/output/disable.c', 'commands/output/dpms.c', diff --git a/sway/server.c b/sway/server.c index edbc1a4b1..bb895377b 100644 --- a/sway/server.c +++ b/sway/server.c @@ -371,6 +371,13 @@ bool server_init(struct sway_server *server) { server->content_type_manager_v1 = wlr_content_type_manager_v1_create(server->wl_display, 1); wlr_fractional_scale_manager_v1_create(server->wl_display, 1); + + server->tearing_control_v1 = + wlr_tearing_control_manager_v1_create(server->wl_display, 1); + server->tearing_control_new_object.notify = handle_new_tearing_hint; + wl_signal_add(&server->tearing_control_v1->events.new_object, + &server->tearing_control_new_object); + wl_list_init(&server->tearing_controllers); struct wlr_xdg_foreign_registry *foreign_registry = wlr_xdg_foreign_registry_create(server->wl_display); diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd index 6d7c08604..d9a28807a 100644 --- a/sway/sway-output.5.scd +++ b/sway/sway-output.5.scd @@ -190,6 +190,26 @@ must be separated by one space. For example: may have no effect or produce unexpected output when used together with future HDR support features. +*output* allow_tearing yes|no + Allows or disallows screen tearing as a result of immediate page flips, + and an immediate presentation mode from a client. The default is that no + screen tearing is allowed. + + With immediate page flips, frames from the client are presented as soon + as possible instead of synchronizing with the monitor's vblank interval + (VSync). + + It is recommended to set *max_render_time* to *off*. In that case a page flip + happens as soon as a client updates. Otherwise, tearing will only happen if + rendering takes longer than the configured milliseconds before the next + display refresh. + + To adjust whether tearing is allowed for specific applications, see + *allow_tearing* in *sway*(5). Note that tearing will only be enabled + when it's allowed for both the output and the application. + + This setting only has effect when a window is fullscreen on the output. + # SEE ALSO *sway*(5) *sway-input*(5) diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 9f8239473..0b36a7572 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -215,6 +215,20 @@ set|plus|minus|toggle effect on the output the window is currently on. See *sway-output*(5) for further details. +*allow_tearing* yes|no + Allows or disallows screen tearing as a result of immediate page flips + for a fullscreen application. + + When this option is not set, the tearing hints provided by the application + determine whether tearing is allowed. When _yes_ is specified, + the application allows tearing regardless of the tearing hints. + When _no_ is specified, tearing will never be allowed on the application, + regardless of the tearing hints. + + This setting only has an effect if tearing is allowed on the output through + the per-output *allow_tearing* setting. See *sway-output*(5) + for further details. + *move* left|right|up|down [ px] Moves the focused container in the direction specified. The optional _px_ argument specifies how many pixels to move the container. If unspecified, diff --git a/sway/tree/view.c b/sway/tree/view.c index 4f757acf1..84a25f9cf 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -58,6 +58,7 @@ bool view_init(struct sway_view *view, enum sway_view_type type, view->executed_criteria = create_list(); view->allow_request_urgent = true; view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT; + view->tearing_mode = TEARING_WINDOW_HINT; wl_signal_init(&view->events.unmap); return true; } @@ -1260,6 +1261,19 @@ bool view_is_transient_for(struct sway_view *child, child->impl->is_transient_for(child, ancestor); } +bool view_can_tear(struct sway_view *view) { + switch (view->tearing_mode) { + case TEARING_OVERRIDE_FALSE: + return false; + case TEARING_OVERRIDE_TRUE: + return true; + case TEARING_WINDOW_HINT: + return view->tearing_hint == + WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC; + } + return false; +} + static void send_frame_done_iterator(struct wlr_scene_buffer *scene_buffer, int x, int y, void *data) { struct timespec *when = data; diff --git a/swaymsg/main.c b/swaymsg/main.c index 573a7b166..5c57171e7 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -193,7 +193,7 @@ static void pretty_print_output(json_object *o) { json_object_object_get_ex(o, "current_workspace", &ws); json_object_object_get_ex(o, "non_desktop", &non_desktop); json_object *make, *model, *serial, *scale, *scale_filter, *subpixel, - *transform, *max_render_time, *adaptive_sync_status; + *transform, *max_render_time, *adaptive_sync_status, *allow_tearing; json_object_object_get_ex(o, "make", &make); json_object_object_get_ex(o, "model", &model); json_object_object_get_ex(o, "serial", &serial); @@ -203,6 +203,7 @@ static void pretty_print_output(json_object *o) { json_object_object_get_ex(o, "transform", &transform); json_object_object_get_ex(o, "max_render_time", &max_render_time); json_object_object_get_ex(o, "adaptive_sync_status", &adaptive_sync_status); + json_object_object_get_ex(o, "allow_tearing", &allow_tearing); json_object *x, *y; json_object_object_get_ex(rect, "x", &x); json_object_object_get_ex(rect, "y", &y); @@ -256,6 +257,9 @@ static void pretty_print_output(json_object *o) { printf(" Adaptive sync: %s\n", json_object_get_string(adaptive_sync_status)); + + printf(" Allow tearing: %s\n", + json_object_get_boolean(allow_tearing) ? "yes" : "no"); } else { printf( "Output %s '%s %s %s' (disabled)\n", From fa4912b1f967d0a8887cf196ff6955c34c638b72 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Wed, 7 Aug 2024 15:26:49 +0300 Subject: [PATCH 09/71] tearing: remove trailing whitespace (cherry picked from commit 3e956b922958b182912775497812cd42439b2955) --- sway/config/output.c | 4 ++-- sway/desktop/output.c | 5 ++--- sway/desktop/tearing.c | 16 ++++++++-------- sway/server.c | 4 ++-- sway/tree/view.c | 2 +- 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/sway/config/output.c b/sway/config/output.c index 940c75fe3..1b378078e 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -578,9 +578,9 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output wlr_color_transform_unref(output->color_transform); output->color_transform = oc->color_transform; } - + if (oc && oc->allow_tearing >= 0) { - sway_log(SWAY_DEBUG, "Set %s allow tearing to %d", + sway_log(SWAY_DEBUG, "Set %s allow tearing to %d", oc->name, oc->allow_tearing); output->allow_tearing = oc->allow_tearing; } diff --git a/sway/desktop/output.c b/sway/desktop/output.c index f1e08eff8..c1aa4483e 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -292,14 +292,13 @@ static int output_repaint_timer_handler(void *data) { wlr_output_state_set_gamma_lut(&pending, 0, NULL, NULL, NULL); } } - + if (output_can_tear(output)) { pending.tearing_page_flip = true; - + if (!wlr_output_test_state(output->wlr_output, &pending)) { sway_log(SWAY_DEBUG, "Output test failed on '%s', retrying without tearing page-flip", output->wlr_output->name); - pending.tearing_page_flip = false; } } diff --git a/sway/desktop/tearing.c b/sway/desktop/tearing.c index 36cc48bfe..b74c74d25 100644 --- a/sway/desktop/tearing.c +++ b/sway/desktop/tearing.c @@ -17,7 +17,7 @@ static void handle_tearing_controller_set_hint(struct wl_listener *listener, void *data) { struct sway_tearing_controller *controller = wl_container_of(listener, controller, set_hint); - + struct sway_view *view = view_from_wlr_surface( controller->tearing_control->surface); if (view) { @@ -25,27 +25,27 @@ static void handle_tearing_controller_set_hint(struct wl_listener *listener, } } -static void handle_tearing_controller_destroy(struct wl_listener *listener, +static void handle_tearing_controller_destroy(struct wl_listener *listener, void *data) { - struct sway_tearing_controller *controller = + struct sway_tearing_controller *controller = wl_container_of(listener, controller, destroy); wl_list_remove(&controller->link); free(controller); } -void handle_new_tearing_hint(struct wl_listener *listener, +void handle_new_tearing_hint(struct wl_listener *listener, void *data) { - struct sway_server *server = + struct sway_server *server = wl_container_of(listener, server, tearing_control_new_object); struct wlr_tearing_control_v1 *tearing_control = data; - - enum wp_tearing_control_v1_presentation_hint hint = + + enum wp_tearing_control_v1_presentation_hint hint = wlr_tearing_control_manager_v1_surface_hint_from_surface( server->tearing_control_v1, tearing_control->surface); sway_log(SWAY_DEBUG, "New presentation hint %d received for surface %p", hint, tearing_control->surface); - struct sway_tearing_controller *controller = + struct sway_tearing_controller *controller = calloc(1, sizeof(struct sway_tearing_controller)); if (!controller) { return; diff --git a/sway/server.c b/sway/server.c index bb895377b..2922cc10f 100644 --- a/sway/server.c +++ b/sway/server.c @@ -371,8 +371,8 @@ bool server_init(struct sway_server *server) { server->content_type_manager_v1 = wlr_content_type_manager_v1_create(server->wl_display, 1); wlr_fractional_scale_manager_v1_create(server->wl_display, 1); - - server->tearing_control_v1 = + + server->tearing_control_v1 = wlr_tearing_control_manager_v1_create(server->wl_display, 1); server->tearing_control_new_object.notify = handle_new_tearing_hint; wl_signal_add(&server->tearing_control_v1->events.new_object, diff --git a/sway/tree/view.c b/sway/tree/view.c index 84a25f9cf..a825bc922 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -1268,7 +1268,7 @@ bool view_can_tear(struct sway_view *view) { case TEARING_OVERRIDE_TRUE: return true; case TEARING_WINDOW_HINT: - return view->tearing_hint == + return view->tearing_hint == WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC; } return false; From 04943bc6ac4872a1ad5fa56cb9cadd20beeefa92 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Wed, 7 Aug 2024 15:27:02 +0300 Subject: [PATCH 10/71] tearing: fix UAF on destroy Fixes: 9a1c411abd8261c121dcd50dfe54132718768084 (cherry picked from commit 32e5e5232d1b0b5a34b4296a79a4e8cfa32b5090) --- sway/desktop/tearing.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sway/desktop/tearing.c b/sway/desktop/tearing.c index b74c74d25..d8d276451 100644 --- a/sway/desktop/tearing.c +++ b/sway/desktop/tearing.c @@ -29,6 +29,8 @@ static void handle_tearing_controller_destroy(struct wl_listener *listener, void *data) { struct sway_tearing_controller *controller = wl_container_of(listener, controller, destroy); + wl_list_remove(&controller->set_hint.link); + wl_list_remove(&controller->destroy.link); wl_list_remove(&controller->link); free(controller); } From e6c3612b72b0bd2d0ae5ec31964d986e90ae356a Mon Sep 17 00:00:00 2001 From: JingMatrix Date: Fri, 9 Aug 2024 00:26:03 +0200 Subject: [PATCH 11/71] Add null-safety check for virtual keyboard keymaps Note that in the `sway_keyboard_configure` function of sway/input/keyboard.c, we have skipped the `sway_keyboard_set_layout` function for virtual keyboards, which then have null keymaps. Hence, a null-safety check is needed at runtime. (cherry picked from commit f344e9d5a5afe6ba1aeaf781be3bd18dbf8596f1) --- sway/commands/input/xkb_switch_layout.c | 10 +++++++++- sway/ipc-json.c | 4 +++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/sway/commands/input/xkb_switch_layout.c b/sway/commands/input/xkb_switch_layout.c index 8d600fcad..623dfa186 100644 --- a/sway/commands/input/xkb_switch_layout.c +++ b/sway/commands/input/xkb_switch_layout.c @@ -95,10 +95,18 @@ struct cmd_results *input_cmd_xkb_switch_layout(int argc, char **argv) { continue; } + struct wlr_keyboard *keyboard = + wlr_keyboard_from_input_device(dev->wlr_device); + if (keyboard->keymap == NULL && dev->is_virtual) { + // The `sway_keyboard_set_layout` function is by default skipped + // when configuring virtual keyboards. + continue; + } + struct xkb_switch_layout_action *action = &actions[actions_len++]; + action->keyboard = keyboard; - action->keyboard = wlr_keyboard_from_input_device(dev->wlr_device); if (relative) { action->layout = get_layout_relative(action->keyboard, relative); } else { diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 8eaa8324a..571338a4f 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -1133,7 +1133,9 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) { json_object *layouts_arr = json_object_new_array(); json_object_object_add(object, "xkb_layout_names", layouts_arr); - xkb_layout_index_t num_layouts = xkb_keymap_num_layouts(keymap); + xkb_layout_index_t num_layouts = + keymap ? xkb_keymap_num_layouts(keymap) : 0; + // Virtual keyboards might have null keymap xkb_layout_index_t layout_idx; for (layout_idx = 0; layout_idx < num_layouts; layout_idx++) { const char *layout = xkb_keymap_layout_get_name(keymap, layout_idx); From 3fba40da50a9d049d5ddffeb24d222993396b8cb Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 29 Feb 2024 01:03:11 +0100 Subject: [PATCH 12/71] Bind a few utilities to special keys in default config (cherry picked from commit 9ba1beee580d07adfba903257ce8762b96ea3833) --- config.in | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/config.in b/config.in index a5173165b..811365e1a 100644 --- a/config.in +++ b/config.in @@ -195,6 +195,19 @@ mode "resize" { bindsym Escape mode "default" } bindsym $mod+r mode "resize" +# +# Utilities: +# + # Special keys to adjust volume via PulseAudio + bindsym --locked XF86AudioMute exec pactl set-sink-mute \@DEFAULT_SINK@ toggle + bindsym --locked XF86AudioLowerVolume exec pactl set-sink-volume \@DEFAULT_SINK@ -5% + bindsym --locked XF86AudioRaiseVolume exec pactl set-sink-volume \@DEFAULT_SINK@ +5% + bindsym --locked XF86AudioMicMute exec pactl set-source-mute \@DEFAULT_SOURCE@ toggle + # Special keys to adjust brightness via brightnessctl + bindsym --locked XF86MonBrightnessDown exec brightnessctl set 5%- + bindsym --locked XF86MonBrightnessUp exec brightnessctl set 5%+ + # Special key to take a screenshot with grim + bindsym Print exec grim # # Status Bar: From fb0f2add19fdc5b62838770f697ff70544bfe940 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 11 Aug 2024 19:03:19 +0200 Subject: [PATCH 13/71] Switch default config to wmenu-run This removes the last dependency bit on dmenu. No need for "swaymsg exec" anymore: wmenu-run handles the xdg-activation shenanigans. (cherry picked from commit b44015578a3d53cdd9436850202d4405696c1f52) --- config.in | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/config.in b/config.in index 811365e1a..a2a01dda9 100644 --- a/config.in +++ b/config.in @@ -16,9 +16,7 @@ set $right l # Your preferred terminal emulator set $term foot # Your preferred application launcher -# Note: pass the final command to swaymsg so that the resulting window can be opened -# on the original workspace that the command was run on. -set $menu dmenu_path | wmenu | xargs swaymsg exec -- +set $menu wmenu-run ### Output configuration # From d100835485eed804c9300f3a855b11f79892210c Mon Sep 17 00:00:00 2001 From: Felix Pehla <74104874+FelixPehla@users.noreply.github.com> Date: Wed, 7 Aug 2024 18:34:59 +0200 Subject: [PATCH 14/71] commands/output/color_profile: allows use of relative path for ICC profile (cherry picked from commit 6576b99c243e2b66d077db0a99ec9683747e3fe9) --- sway/commands/output/color_profile.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/sway/commands/output/color_profile.c b/sway/commands/output/color_profile.c index 792bd55fb..98481329b 100644 --- a/sway/commands/output/color_profile.c +++ b/sway/commands/output/color_profile.c @@ -5,6 +5,7 @@ #include #include "sway/commands.h" #include "sway/config.h" +#include "stringop.h" static bool read_file_into_buf(const char *path, void **buf, size_t *size) { /* Why not use fopen/fread directly? glibc will succesfully open directories, @@ -70,12 +71,23 @@ struct cmd_results *output_cmd_color_profile(int argc, char **argv) { return cmd_results_new(CMD_INVALID, "Invalid color profile specification: icc type requires a file"); } + + char *icc_path = strdup(argv[1]); + if (!expand_path(&icc_path)) { + struct cmd_results *cmd_res = cmd_results_new(CMD_INVALID, + "Invalid color profile specification: invalid file path"); + free(icc_path); + return cmd_res; + } + void *data = NULL; size_t size = 0; - if (!read_file_into_buf(argv[1], &data, &size)) { + if (!read_file_into_buf(icc_path, &data, &size)) { + free(icc_path); return cmd_results_new(CMD_FAILURE, "Failed to load color profile: could not read ICC file"); } + free(icc_path); struct wlr_color_transform *tmp = wlr_color_transform_init_linear_to_icc(data, size); From 234f18d357875c2baee083f6a7ca85ff3abdaae9 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 18 Aug 2024 14:50:48 +0200 Subject: [PATCH 15/71] config/output: Do not set adaptive_sync if not supported After 4e38f93f367d ("config/output: Skip VRR tests when not supported"), the configuration search no longer touches VRR state for outputs that are known to not support it. This also means that it will not remove VRR if already set, which could cause output configuration to fail. Ensure that VRR state is never set for outputs that do not support it by adding the same test for support to queue_output_config. Fixes: 4e38f93f367d ("config/output: Skip VRR tests when not supported") Fixes: https://github.com/swaywm/sway/issues/8296 (cherry picked from commit ae7c1b139a3c71d3e11fe2477d8b21c36de6770e) --- sway/config/output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/config/output.c b/sway/config/output.c index 1b378078e..cc3bf457f 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -491,7 +491,7 @@ static void queue_output_config(struct output_config *oc, wlr_output_state_set_scale(pending, scale); } - if (oc && oc->adaptive_sync != -1) { + if (oc && oc->adaptive_sync != -1 && wlr_output->adaptive_sync_supported) { sway_log(SWAY_DEBUG, "Set %s adaptive sync to %d", wlr_output->name, oc->adaptive_sync); wlr_output_state_set_adaptive_sync_enabled(pending, oc->adaptive_sync == 1); From b1c2155a8ec86e042bc23b949e07066fe8eacf56 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 19 Aug 2024 13:02:55 +0200 Subject: [PATCH 16/71] config/output: Skip search if config has a mode When doing an output configuration search, the intent is to only look for modes if the output's configuration does not contain a specific mode. This was done by testing if config_has_auto_mode returned false. config_has_auto_mode had its return values backwards, leading to other modes being tested if the output configuration had specified modes or modelines, leading to unwanted modes being selected. Invert the function to config_has_manual_mode to give it a clearer name, and fix the return values in the process. (cherry picked from commit f9c0f043e5ec39574c9d9b0fb3dece6169a0e67d) --- sway/config/output.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sway/config/output.c b/sway/config/output.c index cc3bf457f..d33ea11a9 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -651,9 +651,9 @@ struct output_config *find_output_config(struct sway_output *sway_output) { return result; } -static bool config_has_auto_mode(struct output_config *oc) { +static bool config_has_manual_mode(struct output_config *oc) { if (!oc) { - return true; + return false; } if (oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t)-1) { return true; @@ -754,7 +754,8 @@ static bool search_mode(struct search_context *ctx, size_t output_idx) { struct wlr_output_state *state = &backend_state->base; struct wlr_output *wlr_output = backend_state->output; - if (!config_has_auto_mode(cfg->config)) { + // We only search for mode if one is not explicitly specified in the config + if (config_has_manual_mode(cfg->config)) { return search_adaptive_sync(ctx, output_idx); } From a4927e4cb2d26e78e76ad11f7eefaa3ee32bbcac Mon Sep 17 00:00:00 2001 From: "Anna (navi) Figueiredo Gomes" Date: Sat, 29 Jun 2024 11:00:09 +0200 Subject: [PATCH 17/71] sway/commands/move.c: arrange new workspace When moving a container to a new workspace, the workspace's dimension are left unset. Usually this doesn't matter, but when moving a floating container to a new workspace on a different output, this leads to the position of the container being calculated with 0, so the container ends up halfway offscreen on the leftmost topmost monitor. Signed-off-by: Anna (navi) Figueiredo Gomes (cherry picked from commit f00f964abf0eae36a1cce03c532115319499e570) --- sway/commands/move.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sway/commands/move.c b/sway/commands/move.c index ff656cfbd..ad106c648 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -510,6 +510,7 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth, } } ws = workspace_create(NULL, ws_name); + arrange_workspace(ws); } free(ws_name); struct sway_container *dst = seat_get_focus_inactive_tiling(seat, ws); From 9cdd57a032d3a672abb02b97f9da78920abbcce4 Mon Sep 17 00:00:00 2001 From: llyyr Date: Fri, 23 Aug 2024 01:55:42 +0530 Subject: [PATCH 18/71] sway/tree/container: don't trunc coords in `floating_fix_coordinates` This can cause issues such as the window not being shown at the exact same coordinates when the old and new wlr_box aren't the same dimensions and the container is being moved back-and-forth between them. For example, in the case where a floating window gets moved from one output to another but the outputs aren't the same resolution. For e.g. have two displays that aren't the same resolution then: 1. Open a floating window and set it to pos 0,0 on output 2 2. Send it to scratchpad then `scratchpad show` on output 1 3. `scratchpad show` on output 2 again Observe that the window isn't at 0,0 on output 2 anymore. (cherry picked from commit 77b9ddabe2a97c5d04c30929b0f8cbde3470fdd7) --- sway/tree/container.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sway/tree/container.c b/sway/tree/container.c index 80ef34fe9..46c388b3e 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -773,11 +773,11 @@ void floating_fix_coordinates(struct sway_container *con, struct wlr_box *old, s // Fall back to centering on the workspace. container_floating_move_to_center(con); } else { - int rel_x = con->pending.x - old->x + (con->pending.width / 2); - int rel_y = con->pending.y - old->y + (con->pending.height / 2); + double rel_x = con->pending.x - old->x + (con->pending.width / 2); + double rel_y = con->pending.y - old->y + (con->pending.height / 2); - con->pending.x = new->x + (double)(rel_x * new->width) / old->width - (con->pending.width / 2); - con->pending.y = new->y + (double)(rel_y * new->height) / old->height - (con->pending.height / 2); + con->pending.x = new->x + (rel_x * new->width) / old->width - (con->pending.width / 2); + con->pending.y = new->y + (rel_y * new->height) / old->height - (con->pending.height / 2); sway_log(SWAY_DEBUG, "Transformed container %p to coords (%f, %f)", con, con->pending.x, con->pending.y); } From 401a84bf21393cc375cc55421b3f955c724d64e7 Mon Sep 17 00:00:00 2001 From: Jon Wallace Date: Mon, 26 Aug 2024 22:15:55 -0700 Subject: [PATCH 19/71] Use heading markdown to demarcate sections of commands Its a little tought to notice that the COMMANDS section is actually 3 sections. Use markdown to make this easier to see for the user. (cherry picked from commit f2b2a8114900060f667d7ddd55ef9f8a1e74c1b4) --- sway/sway.5.scd | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 0b36a7572..c867c5f7d 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -52,7 +52,7 @@ Throughout the documentation, *|* is used to distinguish between arguments for which you may only select one. *[...]* is used for optional arguments, and *<...>* for arguments where you are expected to supply some value. -# COMMANDS +# COMMANDS - CONFIG ONLY This section only lists general commands. For input and output commands, refer to *sway-input*(5) and *sway-output*(5). @@ -98,6 +98,8 @@ The following commands may only be used in the configuration file. machines, it may be desirable to have Xwayland started immediately by using _force_ instead of _enable_. +# COMMANDS - RUNTIME ONLY + The following commands cannot be used directly in the configuration file. They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). @@ -385,6 +387,8 @@ set|plus|minus|toggle The default format is "%title". +# COMMANDS - CONFIG OR RUNTIME + The following commands may be used either in the configuration file or at runtime. From d2fceae37974191aca4e11b76cb38a033bb47fc5 Mon Sep 17 00:00:00 2001 From: Jon Wallace Date: Tue, 27 Aug 2024 10:42:58 -0700 Subject: [PATCH 20/71] use subheadings instead (cherry picked from commit 980a4e02113789d0cca94aa023557c6f6e87ec73) --- sway/sway.5.scd | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sway/sway.5.scd b/sway/sway.5.scd index c867c5f7d..bb958ebfd 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -52,11 +52,12 @@ Throughout the documentation, *|* is used to distinguish between arguments for which you may only select one. *[...]* is used for optional arguments, and *<...>* for arguments where you are expected to supply some value. -# COMMANDS - CONFIG ONLY +# COMMANDS This section only lists general commands. For input and output commands, refer to *sway-input*(5) and *sway-output*(5). +## Config only commands The following commands may only be used in the configuration file. *bar* [] @@ -98,8 +99,7 @@ The following commands may only be used in the configuration file. machines, it may be desirable to have Xwayland started immediately by using _force_ instead of _enable_. -# COMMANDS - RUNTIME ONLY - +## Runtime only commands The following commands cannot be used directly in the configuration file. They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). @@ -387,8 +387,7 @@ set|plus|minus|toggle The default format is "%title". -# COMMANDS - CONFIG OR RUNTIME - +## Config or runtime commands The following commands may be used either in the configuration file or at runtime. From 7246bf909c12e7ec973a0e18ecb08254929c6a2c Mon Sep 17 00:00:00 2001 From: Norbert Bolanowski Date: Mon, 2 Sep 2024 20:02:42 +0200 Subject: [PATCH 21/71] move title_format to container (cherry picked from commit be840f730e747a24106c8366ecb89e6b982cfa38) --- include/sway/tree/container.h | 4 ++ include/sway/tree/view.h | 2 - sway/commands/title_format.c | 18 ++++--- sway/tree/container.c | 89 +++++++++++++++++++++++++++++++++-- sway/tree/view.c | 78 +----------------------------- 5 files changed, 102 insertions(+), 89 deletions(-) diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 8bf1955d7..4608b8ac2 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -102,6 +102,8 @@ struct sway_container { char *title; // The view's title (unformatted) char *formatted_title; // The title displayed in the title bar int title_width; + + char *title_format; enum sway_container_layout prev_split_layout; @@ -183,6 +185,8 @@ void container_update_title_bar(struct sway_container *container); void container_update_marks(struct sway_container *container); +size_t parse_title_format(struct sway_container *container, char *buffer); + size_t container_build_representation(enum sway_container_layout layout, list_t *children, char *buffer); diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 14aad1a18..f60322212 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -80,8 +80,6 @@ struct sway_view { // Used when changing a view from tiled to floating. int natural_width, natural_height; - char *title_format; - bool using_csd; struct timespec urgent; diff --git a/sway/commands/title_format.c b/sway/commands/title_format.c index 0b2ea2659..fbade4731 100644 --- a/sway/commands/title_format.c +++ b/sway/commands/title_format.c @@ -1,3 +1,4 @@ +#define _POSIX_C_SOURCE 200809L #include #include "sway/commands.h" #include "sway/config.h" @@ -11,16 +12,19 @@ struct cmd_results *cmd_title_format(int argc, char **argv) { return error; } struct sway_container *container = config->handler_context.container; - if (!container || !container->view) { + if (!container) { return cmd_results_new(CMD_INVALID, - "Only views can have a title_format"); + "Only valid containers can have a title_format"); } - struct sway_view *view = container->view; char *format = join_args(argv, argc); - if (view->title_format) { - free(view->title_format); + if (container->title_format) { + free(container->title_format); + } + container->title_format = format; + if (container->view) { + view_update_title(container->view, true); + } else { + container_update_representation(container); } - view->title_format = format; - view_update_title(view, true); return cmd_results_new(CMD_SUCCESS, NULL); } diff --git a/sway/tree/container.c b/sway/tree/container.c index 46c388b3e..188d3223a 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -22,6 +22,7 @@ #include "sway/tree/workspace.h" #include "sway/xdg_decoration.h" #include "list.h" +#include "pango.h" #include "log.h" #include "stringop.h" @@ -499,6 +500,7 @@ void container_destroy(struct sway_container *con) { } free(con->title); free(con->formatted_title); + free(con->title_format); list_free(con->pending.children); list_free(con->current.children); @@ -645,6 +647,87 @@ bool container_has_ancestor(struct sway_container *descendant, return false; } +static char *escape_pango_markup(const char *buffer) { + size_t length = escape_markup_text(buffer, NULL); + char *escaped_title = calloc(length + 1, sizeof(char)); + escape_markup_text(buffer, escaped_title); + return escaped_title; +} + +static size_t append_prop(char *buffer, const char *value) { + if (!value) { + return 0; + } + // If using pango_markup in font, we need to escape all markup chars + // from values to make sure tags are not inserted by clients + if (config->pango_markup) { + char *escaped_value = escape_pango_markup(value); + lenient_strcat(buffer, escaped_value); + size_t len = strlen(escaped_value); + free(escaped_value); + return len; + } else { + lenient_strcat(buffer, value); + return strlen(value); + } +} + +/** + * Calculate and return the length of the formatted title. + * If buffer is not NULL, also populate the buffer with the formatted title. + */ +size_t parse_title_format(struct sway_container *container, char *buffer) { + if (!container->title_format || strcmp(container->title_format, "%title") == 0) { + if (container->view) { + return append_prop(buffer, view_get_title(container->view)); + } else { + return container_build_representation(container->pending.layout, container->pending.children, buffer); + } + } + + size_t len = 0; + char *format = container->title_format; + char *next = strchr(format, '%'); + while (next) { + // Copy everything up to the % + lenient_strncat(buffer, format, next - format); + len += next - format; + format = next; + + if (strncmp(next, "%title", 6) == 0) { + if (container->view) { + len += append_prop(buffer, view_get_title(container->view)); + } else { + len += container_build_representation(container->pending.layout, container->pending.children, buffer); + } + format += 6; + } else if (container->view) { + if (strncmp(next, "%app_id", 7) == 0) { + len += append_prop(buffer, view_get_app_id(container->view)); + format += 7; + } else if (strncmp(next, "%class", 6) == 0) { + len += append_prop(buffer, view_get_class(container->view)); + format += 6; + } else if (strncmp(next, "%instance", 9) == 0) { + len += append_prop(buffer, view_get_instance(container->view)); + format += 9; + } else if (strncmp(next, "%shell", 6) == 0) { + len += append_prop(buffer, view_get_shell(container->view)); + format += 6; + } + } else { + lenient_strcat(buffer, "%"); + ++format; + ++len; + } + next = strchr(format, '%'); + } + lenient_strcat(buffer, format); + len += strlen(format); + + return len; +} + /** * Calculate and return the length of the tree representation. * An example tree representation is: V[Terminal, Firefox] @@ -700,16 +783,14 @@ size_t container_build_representation(enum sway_container_layout layout, void container_update_representation(struct sway_container *con) { if (!con->view) { - size_t len = container_build_representation(con->pending.layout, - con->pending.children, NULL); + size_t len = parse_title_format(con, NULL); free(con->formatted_title); con->formatted_title = calloc(len + 1, sizeof(char)); if (!sway_assert(con->formatted_title, "Unable to allocate title string")) { return; } - container_build_representation(con->pending.layout, con->pending.children, - con->formatted_title); + parse_title_format(con, con->formatted_title); if (con->title_bar.title_text) { sway_text_node_set_text(con->title_bar.title_text, con->formatted_title); diff --git a/sway/tree/view.c b/sway/tree/view.c index a825bc922..ebf98faaa 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -34,7 +34,6 @@ #include "sway/tree/workspace.h" #include "sway/config.h" #include "sway/xdg_decoration.h" -#include "pango.h" #include "stringop.h" bool view_init(struct sway_view *view, enum sway_view_type type, @@ -81,8 +80,6 @@ void view_destroy(struct sway_view *view) { view_assign_ctx(view, NULL); wlr_scene_node_destroy(&view->scene_tree->node); - free(view->title_format); - if (view->impl->destroy) { view->impl->destroy(view); } else { @@ -991,77 +988,6 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) { return NULL; } -static char *escape_pango_markup(const char *buffer) { - size_t length = escape_markup_text(buffer, NULL); - char *escaped_title = calloc(length + 1, sizeof(char)); - escape_markup_text(buffer, escaped_title); - return escaped_title; -} - -static size_t append_prop(char *buffer, const char *value) { - if (!value) { - return 0; - } - // If using pango_markup in font, we need to escape all markup chars - // from values to make sure tags are not inserted by clients - if (config->pango_markup) { - char *escaped_value = escape_pango_markup(value); - lenient_strcat(buffer, escaped_value); - size_t len = strlen(escaped_value); - free(escaped_value); - return len; - } else { - lenient_strcat(buffer, value); - return strlen(value); - } -} - -/** - * Calculate and return the length of the formatted title. - * If buffer is not NULL, also populate the buffer with the formatted title. - */ -static size_t parse_title_format(struct sway_view *view, char *buffer) { - if (!view->title_format || strcmp(view->title_format, "%title") == 0) { - return append_prop(buffer, view_get_title(view)); - } - - size_t len = 0; - char *format = view->title_format; - char *next = strchr(format, '%'); - while (next) { - // Copy everything up to the % - lenient_strncat(buffer, format, next - format); - len += next - format; - format = next; - - if (strncmp(next, "%title", 6) == 0) { - len += append_prop(buffer, view_get_title(view)); - format += 6; - } else if (strncmp(next, "%app_id", 7) == 0) { - len += append_prop(buffer, view_get_app_id(view)); - format += 7; - } else if (strncmp(next, "%class", 6) == 0) { - len += append_prop(buffer, view_get_class(view)); - format += 6; - } else if (strncmp(next, "%instance", 9) == 0) { - len += append_prop(buffer, view_get_instance(view)); - format += 9; - } else if (strncmp(next, "%shell", 6) == 0) { - len += append_prop(buffer, view_get_shell(view)); - format += 6; - } else { - lenient_strcat(buffer, "%"); - ++format; - ++len; - } - next = strchr(format, '%'); - } - lenient_strcat(buffer, format); - len += strlen(format); - - return len; -} - void view_update_app_id(struct sway_view *view) { const char *app_id = view_get_app_id(view); @@ -1090,7 +1016,7 @@ void view_update_title(struct sway_view *view, bool force) { free(view->container->title); free(view->container->formatted_title); - size_t len = parse_title_format(view, NULL); + size_t len = parse_title_format(view->container, NULL); if (len) { char *buffer = calloc(len + 1, sizeof(char)); @@ -1098,7 +1024,7 @@ void view_update_title(struct sway_view *view, bool force) { return; } - parse_title_format(view, buffer); + parse_title_format(view->container, buffer); view->container->formatted_title = buffer; } else { view->container->formatted_title = NULL; From 31ce4ea53d5a61f8b85f683fdf71caad007debff Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Fri, 6 Sep 2024 19:09:41 -0400 Subject: [PATCH 22/71] container: Skip % char if it doesn't match a view property The else condition was missed here and we would never skip the % char if it didn't end up matching with any property. Since we fail to skip we would re-evaluate the % in an infinite loop never achieving any forward-progress. Fixes: https://github.com/swaywm/sway/issues/8333 (cherry picked from commit fc6b8d6af2a8b5c68bbf49753b0e560ad2cff208) --- sway/tree/container.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sway/tree/container.c b/sway/tree/container.c index 188d3223a..f482b06bc 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -714,6 +714,10 @@ size_t parse_title_format(struct sway_container *container, char *buffer) { } else if (strncmp(next, "%shell", 6) == 0) { len += append_prop(buffer, view_get_shell(container->view)); format += 6; + } else { + lenient_strcat(buffer, "%"); + ++format; + ++len; } } else { lenient_strcat(buffer, "%"); From 559f9eba336c4dac76e500e9a598e52d9035f66d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 6 Sep 2024 00:36:29 +0200 Subject: [PATCH 23/71] desktop/transaction: Deactivate workspace on inactive outputs If the output is not active, it might not have a valid geometry to arrange for. Outputs do not gain a geometry until modeset, so if an output is connected with a configuration present to disable it, it will not have a geometry. If the output has a past workspace restored, this will be attemtped arranged to fit a 0x0 rectangle, which asserts when trying to sort out borders. Consider the workspace activated only if the output itself is active to get the scene nodes disabled. (cherry picked from commit 14bff7b451d865f16e3fc82279dfba314b11269c) --- sway/desktop/transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 2ee5a5dff..931189891 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -559,7 +559,7 @@ static void arrange_output(struct sway_output *output, int width, int height) { for (int i = 0; i < output->current.workspaces->length; i++) { struct sway_workspace *child = output->current.workspaces->items[i]; - bool activated = output->current.active_workspace == child; + bool activated = output->current.active_workspace == child && output->wlr_output->enabled; wlr_scene_node_reparent(&child->layers.tiling->node, output->layers.tiling); wlr_scene_node_reparent(&child->layers.fullscreen->node, output->layers.fullscreen); From 24fafa94904ec18ed1b0e83aa6dc5aea3736ab0a Mon Sep 17 00:00:00 2001 From: llyyr Date: Sun, 8 Sep 2024 17:28:34 +0530 Subject: [PATCH 24/71] sway/input/keyboard: always set active keyboard if there is none Previously, we incorrectly only set active keyboard for non-virtual devices. 4c3c0602116c12c2821e1e505e7248b3c642b4ca incorrectly put unrelated code in `sway_keyboard_set_layout`. Fixes: 4c3c0602116c12c2821e1e505e7248b3c642b4ca (cherry picked from commit c5ba7f23a50cd43d39fbb45274484abbcaa4e157) --- sway/input/keyboard.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index efb9ac394..1a73df014 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -1028,13 +1028,6 @@ static void sway_keyboard_set_layout(struct sway_keyboard *keyboard, } } - // If the seat has no active keyboard, set this one - struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat; - struct wlr_keyboard *current_keyboard = seat->keyboard_state.keyboard; - if (current_keyboard == NULL) { - wlr_seat_set_keyboard(seat, keyboard->wlr); - } - if (keymap_changed) { ipc_event_input("xkb_keymap", keyboard->seat_device->input_device); @@ -1078,6 +1071,13 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) { sway_keyboard_set_layout(keyboard, input_config); } + // If the seat has no active keyboard, set this one + struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat; + struct wlr_keyboard *current_keyboard = seat->keyboard_state.keyboard; + if (current_keyboard == NULL) { + wlr_seat_set_keyboard(seat, keyboard->wlr); + } + wl_list_remove(&keyboard->keyboard_key.link); wl_signal_add(&keyboard->wlr->events.key, &keyboard->keyboard_key); keyboard->keyboard_key.notify = handle_keyboard_key; From 6835cbd0461efea9700b40ac6263d9098e69eaf5 Mon Sep 17 00:00:00 2001 From: Adam Chovanec Date: Sat, 7 Sep 2024 21:28:25 +0200 Subject: [PATCH 25/71] readme: update Czech translation (cherry picked from commit fb5eadc363a7f8b9eeeb0ba562ecb3c40e0e6e5a) --- README.cs.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.cs.md b/README.cs.md index 41efba54a..fbb23b34e 100644 --- a/README.cs.md +++ b/README.cs.md @@ -1,6 +1,6 @@ # sway -[English][en] - **[Česky][cs]** - [Deutsch][de] - [Dansk][dk] - [Español][es] - [Français][fr] - [Svenska][sv] - [Ελληνικά][gr] - [हिन्दी][hi] - [Magyar][hu] - [فارسی][ir] - [Italiano][it] - [日本語][ja] - [한국어][ko] - [Nederlands][nl] - [Polski][pl] - [Português][pt] - [Română][ro] - [Русский][ru] - [Türkçe][tr] - [Українська][uk] - [中文-简体][zh-CN] - [中文-繁體][zh-TW] +[English][en] - [عربي][ar] - **[Česky][cs]** - [Deutsch][de] - [Dansk][dk] - [Español][es] - [Français][fr] - [ქართული][ge] - [Ελληνικά][gr] - [हिन्दी][hi] - [Magyar][hu] - [فارسی][ir] - [Italiano][it] - [日本語][ja] - [한국어][ko] - [Nederlands][nl] - [Norsk][no] - [Polski][pl] - [Português][pt] - [Română][ro] - [Русский][ru] - [Svenska][sv] - [Türkçe][tr] - [Українська][uk] - [中文-简体][zh-CN] - [中文-繁體][zh-TW] sway je s [i3] kompatibilní [Wayland] kompozitor. Přečtěte si [FAQ]. Připojte se na [IRC kanál][IRC channel] \(#sway na irc.libera.chat). @@ -32,10 +32,11 @@ Nainstalujte závislosti: * pango * cairo * gdk-pixbuf2 (volitelné: oznamovací oblast) +* [swaybg] (volitelné: tapeta) * [scdoc] (volitelné: manuálové stránky) \* * git (volitelné: informace o verzi) \* -_\* Závislost pouze pro sestavení_ +_\* Závislost pouze pro kompilaci_ Spusťte tyto příkazy: @@ -56,12 +57,13 @@ Spusťte `sway` z TTY. Některé správce zobrazení mohou fungovat, ale nejsou podporovány sway (je známo, že gdm funguje docela dobře). [en]: https://github.com/swaywm/sway#readme +[ar]: README.ar.md [cs]: README.cs.md [de]: README.de.md [dk]: README.dk.md [es]: README.es.md [fr]: README.fr.md -[sv]: README.sv.md +[ge]: README.ge.md [gr]: README.gr.md [hi]: README.hi.md [hu]: README.hu.md @@ -70,10 +72,12 @@ podporovány sway (je známo, že gdm funguje docela dobře). [ja]: README.ja.md [ko]: README.ko.md [nl]: README.nl.md +[no]: README.no.md [pl]: README.pl.md [pt]: README.pt.md [ro]: README.ro.md [ru]: README.ru.md +[sv]: README.sv.md [tr]: README.tr.md [uk]: README.uk.md [zh-CN]: README.zh-CN.md @@ -86,4 +90,5 @@ podporovány sway (je známo, že gdm funguje docela dobře). [GitHub releases]: https://github.com/swaywm/sway/releases [Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup [wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots +[swaybg]: https://github.com/swaywm/swaybg/ [scdoc]: https://git.sr.ht/~sircmpwn/scdoc From 3264696469a89562ada73640957cd90121102bf8 Mon Sep 17 00:00:00 2001 From: Steffen Dirkwinkel Date: Fri, 13 Sep 2024 08:58:55 +0000 Subject: [PATCH 26/71] config/output: support DRM_FORMAT_ARGB8888 Some display output hardware [1] doesn't support any of the current formats, but works with ARGB8888. Fall back to it if available. [1] https://github.com/torvalds/linux/blob/196145c606d0f816fd3926483cb1ff87e09c2c0b/drivers/gpu/drm/xlnx/zynqmp_disp.c#L313 Signed-off-by: Steffen Dirkwinkel (cherry picked from commit f957c7e658871c27935f88f6e1d18b9db67f3808) --- sway/config/output.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sway/config/output.c b/sway/config/output.c index d33ea11a9..3fd234d0b 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -796,6 +796,7 @@ static bool search_render_format(struct search_context *ctx, size_t output_idx) DRM_FORMAT_XRGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, DRM_FORMAT_INVALID, }; if (render_format_is_bgr(wlr_output->render_format)) { From 12796fb0b364dcd43a5a500a92b9fb1ab653fb8c Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 29 Aug 2024 23:40:19 +0200 Subject: [PATCH 27/71] config/output: Add support for 6-bit render fmt GUD devices uses RGB565 by default for performance reasons. Allow specifying render_bit_depth 6 to pick this format. The definition works out if you consider the maximum number of bits per channel instead of the average. (cherry picked from commit 034d02f8a5099ad1283ce3bd1ced524a17f8ba2f) --- include/sway/config.h | 1 + sway/commands/output/render_bit_depth.c | 7 +++++-- sway/config/output.c | 25 +++++++++++++++++++------ sway/sway-output.5.scd | 6 +++--- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index d9f561571..2f5a17fae 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -262,6 +262,7 @@ enum scale_filter_mode { enum render_bit_depth { RENDER_BIT_DEPTH_DEFAULT, // the default is currently 8 + RENDER_BIT_DEPTH_6, RENDER_BIT_DEPTH_8, RENDER_BIT_DEPTH_10, }; diff --git a/sway/commands/output/render_bit_depth.c b/sway/commands/output/render_bit_depth.c index c419321ea..3fa30e045 100644 --- a/sway/commands/output/render_bit_depth.c +++ b/sway/commands/output/render_bit_depth.c @@ -11,7 +11,10 @@ struct cmd_results *output_cmd_render_bit_depth(int argc, char **argv) { return cmd_results_new(CMD_INVALID, "Missing bit depth argument."); } - if (strcmp(*argv, "8") == 0) { + if (strcmp(*argv, "6") == 0) { + config->handler_context.output_config->render_bit_depth = + RENDER_BIT_DEPTH_6; + } else if (strcmp(*argv, "8") == 0) { config->handler_context.output_config->render_bit_depth = RENDER_BIT_DEPTH_8; } else if (strcmp(*argv, "10") == 0) { @@ -19,7 +22,7 @@ struct cmd_results *output_cmd_render_bit_depth(int argc, char **argv) { RENDER_BIT_DEPTH_10; } else { return cmd_results_new(CMD_INVALID, - "Invalid bit depth. Must be a value in (8|10)."); + "Invalid bit depth. Must be a value in (6|8|10)."); } config->handler_context.leftovers.argc = argc - 1; diff --git a/sway/config/output.c b/sway/config/output.c index 3fd234d0b..3fdbfe0b4 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -401,9 +401,15 @@ static int compute_default_scale(struct wlr_output *output, return 2; } -static bool render_format_is_10bit(uint32_t render_format) { - return render_format == DRM_FORMAT_XRGB2101010 || - render_format == DRM_FORMAT_XBGR2101010; +static enum render_bit_depth bit_depth_from_format(uint32_t render_format) { + if (render_format == DRM_FORMAT_XRGB2101010 || render_format == DRM_FORMAT_XBGR2101010) { + return RENDER_BIT_DEPTH_10; + } else if (render_format == DRM_FORMAT_XRGB8888 || render_format == DRM_FORMAT_ARGB8888) { + return RENDER_BIT_DEPTH_8; + } else if (render_format == DRM_FORMAT_RGB565) { + return RENDER_BIT_DEPTH_6; + } + return RENDER_BIT_DEPTH_DEFAULT; } static bool render_format_is_bgr(uint32_t fmt) { @@ -499,11 +505,13 @@ static void queue_output_config(struct output_config *oc, if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { if (oc->render_bit_depth == RENDER_BIT_DEPTH_10 && - render_format_is_10bit(output->wlr_output->render_format)) { + bit_depth_from_format(output->wlr_output->render_format) == oc->render_bit_depth) { // 10-bit was set successfully before, try to save some tests by reusing the format wlr_output_state_set_render_format(pending, output->wlr_output->render_format); } else if (oc->render_bit_depth == RENDER_BIT_DEPTH_10) { wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB2101010); + } else if (oc->render_bit_depth == RENDER_BIT_DEPTH_6){ + wlr_output_state_set_render_format(pending, DRM_FORMAT_RGB565); } else { wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB8888); } @@ -797,6 +805,7 @@ static bool search_render_format(struct search_context *ctx, size_t output_idx) DRM_FORMAT_XBGR2101010, DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, + DRM_FORMAT_RGB565, DRM_FORMAT_INVALID, }; if (render_format_is_bgr(wlr_output->render_format)) { @@ -807,9 +816,13 @@ static bool search_render_format(struct search_context *ctx, size_t output_idx) const struct wlr_drm_format_set *primary_formats = wlr_output_get_primary_formats(wlr_output, WLR_BUFFER_CAP_DMABUF); - bool need_10bit = cfg->config && cfg->config->render_bit_depth == RENDER_BIT_DEPTH_10; + enum render_bit_depth needed_bits = RENDER_BIT_DEPTH_8; + if (cfg->config && cfg->config->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { + needed_bits = cfg->config->render_bit_depth; + } for (size_t idx = 0; fmts[idx] != DRM_FORMAT_INVALID; idx++) { - if (!need_10bit && render_format_is_10bit(fmts[idx])) { + enum render_bit_depth format_bits = bit_depth_from_format(fmts[idx]); + if (needed_bits < format_bits) { continue; } if (!wlr_drm_format_set_get(primary_formats, fmts[idx])) { diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd index d9a28807a..c5087b1bd 100644 --- a/sway/sway-output.5.scd +++ b/sway/sway-output.5.scd @@ -163,9 +163,9 @@ must be separated by one space. For example: adaptive sync can improve latency, but can cause flickering on some hardware. -*output* render_bit_depth 8|10 - Controls the color channel bit depth at which frames are rendered; the - default is currently 8 bits per channel. +*output* render_bit_depth 6|8|10 + Controls the maximum color channel bit depth at which frames are + rendered; the default is currently 8 bits per channel. Setting higher values will not have an effect if hardware and software lack support for such bit depths. Successfully increasing the render bit depth From a8b6d028689735655a2fd948de1f34999a8ac40b Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 30 Aug 2024 02:10:38 +0200 Subject: [PATCH 28/71] config/output: Stringify render format when logging it (cherry picked from commit 9765c29be11f04f903a45f34b9142a865784fc46) --- sway/config/output.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sway/config/output.c b/sway/config/output.c index 3fdbfe0b4..3e7d8ebd4 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "sway/config.h" #include "sway/input/cursor.h" #include "sway/output.h" @@ -685,7 +686,9 @@ static void dump_output_state(struct wlr_output *wlr_output, struct wlr_output_s sway_log(SWAY_DEBUG, " enabled: %s", state->enabled ? "yes" : "no"); } if (state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { - sway_log(SWAY_DEBUG, " render_format: %d", state->render_format); + char *format_name = drmGetFormatName(state->render_format); + sway_log(SWAY_DEBUG, " render_format: %s", format_name); + free(format_name); } if (state->committed & WLR_OUTPUT_STATE_MODE) { if (state->mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM) { From 4cca00458341e42c6241149f149a76eafe868b1a Mon Sep 17 00:00:00 2001 From: Emil Engberg Date: Fri, 20 Sep 2024 15:36:58 +0200 Subject: [PATCH 29/71] Add toggle for output adaptive_sync (cherry picked from commit e940acd3749a5af08d5c404cae242c8693784ddc) --- sway/commands/output/adaptive_sync.c | 24 ++++++++++++++++++++---- sway/sway-output.5.scd | 2 +- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/sway/commands/output/adaptive_sync.c b/sway/commands/output/adaptive_sync.c index 7382e2ee3..4ce88f885 100644 --- a/sway/commands/output/adaptive_sync.c +++ b/sway/commands/output/adaptive_sync.c @@ -1,5 +1,7 @@ +#include #include "sway/commands.h" #include "sway/config.h" +#include "sway/output.h" #include "util.h" struct cmd_results *output_cmd_adaptive_sync(int argc, char **argv) { @@ -10,12 +12,26 @@ struct cmd_results *output_cmd_adaptive_sync(int argc, char **argv) { return cmd_results_new(CMD_INVALID, "Missing adaptive_sync argument"); } - if (parse_boolean(argv[0], true)) { - config->handler_context.output_config->adaptive_sync = 1; - } else { - config->handler_context.output_config->adaptive_sync = 0; + bool current_value = true; + if (strcasecmp(argv[0], "toggle") == 0) { + const char *oc_name = config->handler_context.output_config->name; + if (strcmp(oc_name, "*") == 0) { + return cmd_results_new(CMD_INVALID, + "Cannot apply toggle to all outputs"); + } + + struct sway_output *sway_output = all_output_by_name_or_id(oc_name); + if (!sway_output || !sway_output->wlr_output) { + return cmd_results_new(CMD_FAILURE, + "Cannot apply toggle to unknown output %s", oc_name); + } + + current_value = + sway_output->wlr_output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED; } + config->handler_context.output_config->adaptive_sync = parse_boolean(argv[0], current_value); + config->handler_context.leftovers.argc = argc - 1; config->handler_context.leftovers.argv = argv + 1; return NULL; diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd index c5087b1bd..dc16c257b 100644 --- a/sway/sway-output.5.scd +++ b/sway/sway-output.5.scd @@ -154,7 +154,7 @@ must be separated by one space. For example: This setting only has an effect on Wayland and DRM backends, as support for presentation timestamps and predicted output refresh rate is required. -*output* adaptive_sync on|off +*output* adaptive_sync on|off|toggle Enables or disables adaptive synchronization (often referred to as Variable Refresh Rate, or by the vendor-specific names FreeSync/G-Sync). From b4d550bff88b046a82420b6e223276e9e65e8005 Mon Sep 17 00:00:00 2001 From: Scott Dubinsky Date: Fri, 20 Sep 2024 18:12:08 +0300 Subject: [PATCH 30/71] Remove unguarded double include (cherry picked from commit 266cd4515a015b5684eaf6c0b48ce1afa9be2739) --- sway/input/input-manager.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 248ca34ee..ddfe14689 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include From 5a920c48d1b2236c0b6c376611dc5d17a080bb8b Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Tue, 4 Jun 2024 20:05:58 -0400 Subject: [PATCH 31/71] text_input: Check for allocation failure (cherry picked from commit 48069097ea55021afa0af3c5148cb7caab724dcf) --- sway/input/text_input.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sway/input/text_input.c b/sway/input/text_input.c index 580a9f545..4d52fedc4 100644 --- a/sway/input/text_input.c +++ b/sway/input/text_input.c @@ -448,6 +448,11 @@ static void handle_im_new_popup_surface(struct wl_listener *listener, struct sway_input_method_relay *relay = wl_container_of(listener, relay, input_method_new_popup_surface); struct sway_input_popup *popup = calloc(1, sizeof(*popup)); + if (!popup) { + sway_log(SWAY_ERROR, "Failed to allocate an input method popup"); + return; + } + popup->relay = relay; popup->popup_surface = data; popup->popup_surface->data = popup; From af782c17bb81a0b2370470d94b35fd97296f4cfe Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sun, 4 Aug 2024 13:06:06 -0400 Subject: [PATCH 32/71] text_input: Move popup placement to own function (cherry picked from commit 1537c9dae53eebea4926321aa9f7fd982375859f) --- include/sway/input/text_input_popup.h | 1 + sway/input/text_input.c | 152 ++++++++++++++------------ 2 files changed, 84 insertions(+), 69 deletions(-) diff --git a/include/sway/input/text_input_popup.h b/include/sway/input/text_input_popup.h index e5f6ab8b5..97dd6444a 100644 --- a/include/sway/input/text_input_popup.h +++ b/include/sway/input/text_input_popup.h @@ -9,6 +9,7 @@ struct sway_input_popup { struct wlr_scene_tree *scene_tree; struct sway_popup_desc desc; struct wlr_input_popup_surface_v2 *popup_surface; + struct wlr_output *fixed_output; struct wl_list link; diff --git a/sway/input/text_input.c b/sway/input/text_input.c index 4d52fedc4..9be418f56 100644 --- a/sway/input/text_input.c +++ b/sway/input/text_input.c @@ -128,6 +128,80 @@ static void handle_im_destroy(struct wl_listener *listener, void *data) { } } +static void constrain_popup(struct sway_input_popup *popup) { + struct sway_text_input *text_input = + relay_get_focused_text_input(popup->relay); + + + struct wlr_box parent = {0}; + wlr_scene_node_coords(&popup->desc.relative->parent->node, &parent.x, &parent.y); + + struct wlr_box geo = {0}; + struct wlr_output *output; + + if (popup->desc.view) { + struct sway_view *view = popup->desc.view; + output = wlr_output_layout_output_at(root->output_layout, + view->container->pending.content_x + view->geometry.x, + view->container->pending.content_y + view->geometry.y); + + parent.width = view->geometry.width; + parent.height = view->geometry.height; + geo = view->geometry; + } else { + output = popup->fixed_output; + } + + struct wlr_box output_box; + wlr_output_layout_get_box(root->output_layout, output, &output_box); + + bool cursor_rect = text_input->input->current.features & + WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE; + struct wlr_box cursor_area; + if (cursor_rect) { + cursor_area = text_input->input->current.cursor_rectangle; + } else { + cursor_area = (struct wlr_box) { + .width = parent.width, + .height = parent.height, + }; + } + + int popup_width = popup->popup_surface->surface->current.width; + int popup_height = popup->popup_surface->surface->current.height; + int x1 = parent.x + cursor_area.x; + int x2 = parent.x + cursor_area.x + cursor_area.width; + int y1 = parent.y + cursor_area.y; + int y2 = parent.y + cursor_area.y + cursor_area.height; + int x = x1; + int y = y2; + + int available_right = output_box.x + output_box.width - x1; + int available_left = x2 - output_box.x; + if (available_right < popup_width && available_left > available_right) { + x = x2 - popup_width; + } + + int available_down = output_box.y + output_box.height - y2; + int available_up = y1 - output_box.y; + if (available_down < popup_height && available_up > available_down) { + y = y1 - popup_height; + } + + wlr_scene_node_set_position(popup->desc.relative, x - parent.x - geo.x, y - parent.y - geo.y); + if (cursor_rect) { + struct wlr_box box = { + .x = x1 - x, + .y = y1 - y, + .width = cursor_area.width, + .height = cursor_area.height, + }; + wlr_input_popup_surface_v2_send_text_input_rectangle( + popup->popup_surface, &box); + } + wlr_scene_node_set_position(&popup->scene_tree->node, x - geo.x, y - geo.y); +} + static void relay_send_im_state(struct sway_input_method_relay *relay, struct wlr_text_input_v3 *input) { struct wlr_input_method_v2 *input_method = relay->input_method; @@ -150,8 +224,7 @@ static void relay_send_im_state(struct sway_input_method_relay *relay, } struct sway_input_popup *popup; wl_list_for_each(popup, &relay->input_popups, link) { - // send_text_input_rectangle is called in this function - input_popup_update(popup); + constrain_popup(popup); } wlr_input_method_v2_send_done(input_method); // TODO: pass intent, display popup size @@ -297,50 +370,30 @@ static void input_popup_update(struct sway_input_popup *popup) { return; } - bool cursor_rect = text_input->input->current.features - & WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE; struct wlr_surface *focused_surface = text_input->input->focused_surface; - struct wlr_box cursor_area = text_input->input->current.cursor_rectangle; - struct wlr_box output_box; - struct wlr_box parent = {0}; struct wlr_layer_surface_v1 *layer_surface = wlr_layer_surface_v1_try_from_wlr_surface(focused_surface); struct wlr_scene_tree *relative_parent; - struct wlr_box geo = {0}; - popup->scene_tree = wlr_scene_subsurface_tree_create(root->layers.popup, popup->popup_surface->surface); if (layer_surface != NULL) { - struct sway_layer_surface *layer = - layer_surface->data; + struct sway_layer_surface *layer = layer_surface->data; if (layer == NULL) { return; } relative_parent = layer->scene->tree; - struct wlr_output *output = layer->layer_surface->output; - wlr_output_layout_get_box(root->output_layout, output, &output_box); - int lx, ly; - wlr_scene_node_coords(&layer->tree->node, &lx, &ly); - parent.x = lx; - parent.y = ly; popup->desc.view = NULL; + + // we don't need to add an event here to NULL out this field because + // this field will only be initialized if the popup is part of a layer + // surface. Layer surfaces get destroyed as part of the output being + // destroyed, thus also trickling down to popups. + popup->fixed_output = layer->layer_surface->output; } else { struct sway_view *view = view_from_wlr_surface(focused_surface); relative_parent = view->scene_tree; - geo = view->geometry; - int lx, ly; - wlr_scene_node_coords(&view->scene_tree->node, &lx, &ly); - struct wlr_output *output = wlr_output_layout_output_at(root->output_layout, - view->container->pending.content_x + view->geometry.x, - view->container->pending.content_y + view->geometry.y); - wlr_output_layout_get_box(root->output_layout, output, &output_box); - parent.x = lx; - parent.y = ly; - - parent.width = view->geometry.width; - parent.height = view->geometry.height; popup->desc.view = view; } @@ -354,46 +407,7 @@ static void input_popup_update(struct sway_input_popup *popup) { return; } - if (!cursor_rect) { - cursor_area.x = 0; - cursor_area.y = 0; - cursor_area.width = parent.width; - cursor_area.height = parent.height; - } - - int popup_width = popup->popup_surface->surface->current.width; - int popup_height = popup->popup_surface->surface->current.height; - int x1 = parent.x + cursor_area.x; - int x2 = parent.x + cursor_area.x + cursor_area.width; - int y1 = parent.y + cursor_area.y; - int y2 = parent.y + cursor_area.y + cursor_area.height; - int x = x1; - int y = y2; - - int available_right = output_box.x + output_box.width - x1; - int available_left = x2 - output_box.x; - if (available_right < popup_width && available_left > available_right) { - x = x2 - popup_width; - } - - int available_down = output_box.y + output_box.height - y2; - int available_up = y1 - output_box.y; - if (available_down < popup_height && available_up > available_down) { - y = y1 - popup_height; - } - - wlr_scene_node_set_position(&relative->node, x - parent.x - geo.x, y - parent.y - geo.y); - if (cursor_rect) { - struct wlr_box box = { - .x = x1 - x, - .y = y1 - y, - .width = cursor_area.width, - .height = cursor_area.height, - }; - wlr_input_popup_surface_v2_send_text_input_rectangle( - popup->popup_surface, &box); - } - wlr_scene_node_set_position(&popup->scene_tree->node, x - geo.x, y - geo.y); + constrain_popup(popup); } static void input_popup_set_focus(struct sway_input_popup *popup, From bb666f2ac9e67df16fed7206c533ae28d4d7d7c0 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sun, 4 Aug 2024 13:02:37 -0400 Subject: [PATCH 33/71] transaction: Allow no popup descriptor in popup list Input method popups in the future will destroy the scene descriptor when it isn't mapped and therefore shouldn't be tampered with here. (cherry picked from commit 023f6b0a50dd4fe17a29d7f02922e18ef37df857) --- sway/desktop/transaction.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 931189891..8f12832a0 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -612,9 +612,11 @@ void arrange_popups(struct wlr_scene_tree *popups) { struct sway_popup_desc *popup = scene_descriptor_try_get(node, SWAY_SCENE_DESC_POPUP); - int lx, ly; - wlr_scene_node_coords(popup->relative, &lx, &ly); - wlr_scene_node_set_position(node, lx, ly); + if (popup) { + int lx, ly; + wlr_scene_node_coords(popup->relative, &lx, &ly); + wlr_scene_node_set_position(node, lx, ly); + } } } From 9d667383b43c672e25aa8c3d5cf0779007b466af Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sun, 4 Aug 2024 13:03:59 -0400 Subject: [PATCH 34/71] text_input: Properly handle map/unmap events The last implementation would ignore these and get it could get into a bad state where it would start crashing sway. (cherry picked from commit 74e507962e32ec8d6606d28383ac109fbf2370e4) --- include/sway/input/text_input_popup.h | 2 + sway/input/text_input.c | 64 +++++++++++++++++++++++---- 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/include/sway/input/text_input_popup.h b/include/sway/input/text_input_popup.h index 97dd6444a..7e838ed2a 100644 --- a/include/sway/input/text_input_popup.h +++ b/include/sway/input/text_input_popup.h @@ -15,6 +15,8 @@ struct sway_input_popup { struct wl_listener popup_destroy; struct wl_listener popup_surface_commit; + struct wl_listener popup_surface_map; + struct wl_listener popup_surface_unmap; struct wl_listener focused_surface_unmap; }; diff --git a/sway/input/text_input.c b/sway/input/text_input.c index 9be418f56..1414215bc 100644 --- a/sway/input/text_input.c +++ b/sway/input/text_input.c @@ -132,6 +132,9 @@ static void constrain_popup(struct sway_input_popup *popup) { struct sway_text_input *text_input = relay_get_focused_text_input(popup->relay); + if (!popup->desc.relative) { + return; + } struct wlr_box parent = {0}; wlr_scene_node_coords(&popup->desc.relative->parent->node, &parent.x, &parent.y); @@ -199,7 +202,10 @@ static void constrain_popup(struct sway_input_popup *popup) { wlr_input_popup_surface_v2_send_text_input_rectangle( popup->popup_surface, &box); } - wlr_scene_node_set_position(&popup->scene_tree->node, x - geo.x, y - geo.y); + + if (popup->scene_tree) { + wlr_scene_node_set_position(&popup->scene_tree->node, x - geo.x, y - geo.y); + } } static void relay_send_im_state(struct sway_input_method_relay *relay, @@ -376,7 +382,6 @@ static void input_popup_update(struct sway_input_popup *popup) { wlr_layer_surface_v1_try_from_wlr_surface(focused_surface); struct wlr_scene_tree *relative_parent; - popup->scene_tree = wlr_scene_subsurface_tree_create(root->layers.popup, popup->popup_surface->surface); if (layer_surface != NULL) { struct sway_layer_surface *layer = layer_surface->data; if (layer == NULL) { @@ -435,19 +440,43 @@ static void input_popup_set_focus(struct sway_input_popup *popup, static void handle_im_popup_destroy(struct wl_listener *listener, void *data) { struct sway_input_popup *popup = wl_container_of(listener, popup, popup_destroy); + wlr_scene_node_destroy(&popup->scene_tree->node); wl_list_remove(&popup->focused_surface_unmap.link); wl_list_remove(&popup->popup_surface_commit.link); + wl_list_remove(&popup->popup_surface_map.link); + wl_list_remove(&popup->popup_surface_unmap.link); wl_list_remove(&popup->popup_destroy.link); wl_list_remove(&popup->link); free(popup); } -static void handle_im_popup_surface_commit(struct wl_listener *listener, - void *data) { +static void handle_im_popup_surface_map(struct wl_listener *listener, void *data) { + struct sway_input_popup *popup = + wl_container_of(listener, popup, popup_surface_map); + struct sway_text_input *text_input = relay_get_focused_text_input(popup->relay); + if (text_input != NULL) { + input_popup_set_focus(popup, text_input->input->focused_surface); + } else { + input_popup_set_focus(popup, NULL); + } +} + +static void handle_im_popup_surface_unmap(struct wl_listener *listener, void *data) { + struct sway_input_popup *popup = + wl_container_of(listener, popup, popup_surface_unmap); + + // relative should already be freed as it should be a child of the just unmapped scene + popup->desc.relative = NULL; + + input_popup_set_focus(popup, NULL); +} + +static void handle_im_popup_surface_commit(struct wl_listener *listener, void *data) { struct sway_input_popup *popup = wl_container_of(listener, popup, popup_surface_commit); - input_popup_update(popup); + + constrain_popup(popup); } static void handle_im_focused_surface_unmap( @@ -471,12 +500,29 @@ static void handle_im_new_popup_surface(struct wl_listener *listener, popup->popup_surface = data; popup->popup_surface->data = popup; - wl_signal_add( - &popup->popup_surface->events.destroy, &popup->popup_destroy); + popup->scene_tree = wlr_scene_tree_create(root->layers.popup); + if (!popup->scene_tree) { + sway_log(SWAY_ERROR, "Failed to allocate scene tree"); + free(popup); + return; + } + + if (!wlr_scene_subsurface_tree_create(popup->scene_tree, + popup->popup_surface->surface)) { + sway_log(SWAY_ERROR, "Failed to allocate subsurface tree"); + wlr_scene_node_destroy(&popup->scene_tree->node); + free(popup); + return; + } + + wl_signal_add(&popup->popup_surface->events.destroy, &popup->popup_destroy); popup->popup_destroy.notify = handle_im_popup_destroy; - wl_signal_add(&popup->popup_surface->surface->events.commit, - &popup->popup_surface_commit); + wl_signal_add(&popup->popup_surface->surface->events.commit, &popup->popup_surface_commit); popup->popup_surface_commit.notify = handle_im_popup_surface_commit; + wl_signal_add(&popup->popup_surface->surface->events.map, &popup->popup_surface_map); + popup->popup_surface_map.notify = handle_im_popup_surface_map; + wl_signal_add(&popup->popup_surface->surface->events.unmap, &popup->popup_surface_unmap); + popup->popup_surface_unmap.notify = handle_im_popup_surface_unmap; wl_list_init(&popup->focused_surface_unmap.link); popup->focused_surface_unmap.notify = handle_im_focused_surface_unmap; From 307ab531c0091ad7efb62dd299e31fd2ddf36074 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sat, 8 Jun 2024 15:58:56 -0400 Subject: [PATCH 35/71] text_input: Inline input_popup_update into input_popup_set_focus This seems to be the intention of input_popup_update in the first place: handle the scenario where the focus moves. (cherry picked from commit e9dd2182313e9a480e2b3d48162142414d1fee48) --- sway/input/text_input.c | 75 ++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 43 deletions(-) diff --git a/sway/input/text_input.c b/sway/input/text_input.c index 1414215bc..6bcd02341 100644 --- a/sway/input/text_input.c +++ b/sway/input/text_input.c @@ -11,8 +11,6 @@ #include "sway/layers.h" #include "sway/server.h" -static void input_popup_update(struct sway_input_popup *popup); - static struct sway_text_input *relay_get_focusable_text_input( struct sway_input_method_relay *relay) { struct sway_text_input *text_input = NULL; @@ -208,6 +206,9 @@ static void constrain_popup(struct sway_input_popup *popup) { } } +static void input_popup_set_focus(struct sway_input_popup *popup, + struct wlr_surface *surface); + static void relay_send_im_state(struct sway_input_method_relay *relay, struct wlr_text_input_v3 *input) { struct wlr_input_method_v2 *input_method = relay->input_method; @@ -228,9 +229,16 @@ static void relay_send_im_state(struct sway_input_method_relay *relay, input->current.content_type.hint, input->current.content_type.purpose); } + + struct sway_text_input *text_input = relay_get_focused_text_input(relay); + struct sway_input_popup *popup; wl_list_for_each(popup, &relay->input_popups, link) { - constrain_popup(popup); + if (text_input != NULL) { + input_popup_set_focus(popup, text_input->input->focused_surface); + } else { + input_popup_set_focus(popup, NULL); + } } wlr_input_method_v2_send_done(input_method); // TODO: pass intent, display popup size @@ -354,35 +362,35 @@ static void relay_handle_text_input(struct wl_listener *listener, sway_text_input_create(relay, wlr_text_input); } -static void input_popup_update(struct sway_input_popup *popup) { - struct sway_text_input *text_input = - relay_get_focused_text_input(popup->relay); +static void input_popup_set_focus(struct sway_input_popup *popup, + struct wlr_surface *surface) { + wl_list_remove(&popup->focused_surface_unmap.link); - if (text_input == NULL || text_input->input->focused_surface == NULL) { + if (!popup->scene_tree) { + wl_list_init(&popup->focused_surface_unmap.link); return; } - if (popup->scene_tree != NULL) { - wlr_scene_node_destroy(&popup->scene_tree->node); - popup->scene_tree = NULL; - } - if (popup->desc.relative != NULL) { + if (popup->desc.relative) { + scene_descriptor_destroy(&popup->scene_tree->node, SWAY_SCENE_DESC_POPUP); wlr_scene_node_destroy(popup->desc.relative); popup->desc.relative = NULL; } - popup->desc.view = NULL; - if (!popup->popup_surface->surface->mapped) { + if (surface == NULL) { + wl_list_init(&popup->focused_surface_unmap.link); + wlr_scene_node_set_enabled(&popup->scene_tree->node, false); return; } - struct wlr_surface *focused_surface = text_input->input->focused_surface; - struct wlr_layer_surface_v1 *layer_surface = - wlr_layer_surface_v1_try_from_wlr_surface(focused_surface); - struct wlr_scene_tree *relative_parent; + wlr_layer_surface_v1_try_from_wlr_surface(surface); + + struct wlr_scene_tree *relative_parent; + if (layer_surface) { + wl_signal_add(&layer_surface->surface->events.unmap, + &popup->focused_surface_unmap); - if (layer_surface != NULL) { struct sway_layer_surface *layer = layer_surface->data; if (layer == NULL) { return; @@ -397,7 +405,8 @@ static void input_popup_update(struct sway_input_popup *popup) { // destroyed, thus also trickling down to popups. popup->fixed_output = layer->layer_surface->output; } else { - struct sway_view *view = view_from_wlr_surface(focused_surface); + struct sway_view *view = view_from_wlr_surface(surface); + wl_signal_add(&view->events.unmap, &popup->focused_surface_unmap); relative_parent = view->scene_tree; popup->desc.view = view; } @@ -413,28 +422,7 @@ static void input_popup_update(struct sway_input_popup *popup) { } constrain_popup(popup); -} - -static void input_popup_set_focus(struct sway_input_popup *popup, - struct wlr_surface *surface) { - wl_list_remove(&popup->focused_surface_unmap.link); - - if (surface == NULL) { - wl_list_init(&popup->focused_surface_unmap.link); - input_popup_update(popup); - return; - } - struct wlr_layer_surface_v1 *layer_surface = - wlr_layer_surface_v1_try_from_wlr_surface(surface); - if (layer_surface != NULL) { - wl_signal_add( - &layer_surface->surface->events.unmap, &popup->focused_surface_unmap); - input_popup_update(popup); - return; - } - - struct sway_view *view = view_from_wlr_surface(surface); - wl_signal_add(&view->events.unmap, &popup->focused_surface_unmap); + wlr_scene_node_set_enabled(&popup->scene_tree->node, true); } static void handle_im_popup_destroy(struct wl_listener *listener, void *data) { @@ -483,7 +471,8 @@ static void handle_im_focused_surface_unmap( struct wl_listener *listener, void *data) { struct sway_input_popup *popup = wl_container_of(listener, popup, focused_surface_unmap); - input_popup_update(popup); + + input_popup_set_focus(popup, NULL); } static void handle_im_new_popup_surface(struct wl_listener *listener, From 2f1db190c65b8c495ac00db2593f6776635574e7 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 3 Sep 2024 15:28:29 +0200 Subject: [PATCH 36/71] desktop/output: Do not use commit listener to arrange The reasoning for using a commit handler is to ensure that all paths for output changes are correctly handled. With the centralized modeset infrastructure in place, we can move the logic there. This allows us to be smarter and avoid extraneous arranges, output manager updates and transaction commits. The side-effect is a minor duplication for the special-case request_state, but the shared path will be relied upon further in future commits to justify this duplication. (cherry picked from commit b83e5aaa546792336ecc60d2e61708f3cd6b1f5d) --- include/sway/output.h | 2 ++ sway/config/output.c | 8 ++++++++ sway/desktop/output.c | 29 ++++++++++++++--------------- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/include/sway/output.h b/include/sway/output.h index 7e2d58927..a9e697d82 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -149,4 +149,6 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener, struct sway_output_non_desktop *output_non_desktop_create(struct wlr_output *wlr_output); +void update_output_manager_config(struct sway_server *server); + #endif diff --git a/sway/config/output.c b/sway/config/output.c index 3e7d8ebd4..230c2f5d9 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -12,9 +12,12 @@ #include #include #include "sway/config.h" +#include "sway/desktop/transaction.h" #include "sway/input/cursor.h" +#include "sway/layers.h" #include "sway/output.h" #include "sway/server.h" +#include "sway/tree/arrange.h" #include "sway/tree/root.h" #include "log.h" #include "util.h" @@ -980,8 +983,13 @@ bool apply_output_configs(struct matched_output_config *configs, sway_log(SWAY_DEBUG, "Finalizing config for %s", cfg->output->wlr_output->name); finalize_output_config(cfg->config, cfg->output); + arrange_layers(cfg->output); } + arrange_root(); + update_output_manager_config(&server); + transaction_commit_dirty(); + out: wlr_output_swapchain_manager_finish(&swapchain_mgr); for (size_t idx = 0; idx < configs_len; idx++) { diff --git a/sway/desktop/output.c b/sway/desktop/output.c index c1aa4483e..aaa8c087a 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -374,7 +374,7 @@ static void handle_frame(struct wl_listener *listener, void *user_data) { wlr_scene_output_for_each_buffer(output->scene_output, send_frame_done_iterator, &data); } -static void update_output_manager_config(struct sway_server *server) { +void update_output_manager_config(struct sway_server *server) { struct wlr_output_configuration_v1 *config = wlr_output_configuration_v1_create(); @@ -405,9 +405,6 @@ static int timer_modeset_handle(void *data) { server->delayed_modeset = NULL; apply_all_output_configs(); - transaction_commit_dirty(); - update_output_manager_config(server); - return 0; } @@ -463,17 +460,6 @@ static void handle_commit(struct wl_listener *listener, void *data) { return; } - if (event->state->committed & ( - WLR_OUTPUT_STATE_MODE | - WLR_OUTPUT_STATE_TRANSFORM | - WLR_OUTPUT_STATE_SCALE)) { - arrange_layers(output); - arrange_output(output); - transaction_commit_dirty(); - - update_output_manager_config(output->server); - } - // Next time the output is enabled, try to re-apply the gamma LUT if ((event->state->committed & WLR_OUTPUT_STATE_ENABLED) && !output->wlr_output->enabled) { output->gamma_lut_changed = true; @@ -496,7 +482,20 @@ static void handle_request_state(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, request_state); const struct wlr_output_event_request_state *event = data; + + uint32_t committed = event->state->committed; wlr_output_commit_state(output->wlr_output, event->state); + + if (committed & ( + WLR_OUTPUT_STATE_MODE | + WLR_OUTPUT_STATE_TRANSFORM | + WLR_OUTPUT_STATE_SCALE)) { + arrange_layers(output); + arrange_output(output); + transaction_commit_dirty(); + + update_output_manager_config(output->server); + } } static unsigned int last_headless_num = 0; From fa96c64e24eac2f30cdc4feed828600d9de75dd6 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 3 Sep 2024 15:36:47 +0200 Subject: [PATCH 37/71] tree/output: Rely on modeset arranging root output_enable/output_disable are only called from modeset, and from output destroy which requests modeset. As such, they can rely on the modeset handling arrange. (cherry picked from 6045ad9a0224ea2aab2d488cd356b5557007f5d1) --- sway/tree/output.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/sway/tree/output.c b/sway/tree/output.c index 6c8dd6dc9..f3b0b27a2 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -183,9 +183,6 @@ void output_enable(struct sway_output *output) { input_manager_configure_xcursor(); wl_signal_emit_mutable(&root->events.new_node, &output->node); - - arrange_layers(output); - arrange_root(); } static void evacuate_sticky(struct sway_workspace *old_ws, @@ -300,13 +297,6 @@ void output_disable(struct sway_output *output) { list_del(root->outputs, index); output->enabled = false; - - arrange_root(); - - // Reconfigure all devices, since devices with map_to_output directives for - // an output that goes offline should stop sending events as long as the - // output remains offline. - input_manager_configure_all_input_mappings(); } void output_begin_destroy(struct sway_output *output) { From 6baee5cb687a7ef9a67bf7cf64b8ea0fd20edcbf Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 3 Sep 2024 15:39:39 +0200 Subject: [PATCH 38/71] (desktop|tree)/output: Do not use layout listener to arrange Output layout changes originate from the centralized modeset infrastructure and request_state which already takes care of arranging and updating outputs as needed. (cherry picked from af28ac04a4d523aecd74dacc94a91f7d9e537982) --- include/sway/output.h | 1 - include/sway/server.h | 1 - include/sway/tree/root.h | 2 -- sway/desktop/output.c | 7 ------- sway/server.c | 3 --- sway/tree/root.c | 10 ---------- 6 files changed, 24 deletions(-) diff --git a/include/sway/output.h b/include/sway/output.h index a9e697d82..2a92be999 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -136,7 +136,6 @@ enum sway_container_layout output_get_default_layout( enum wlr_direction opposite_direction(enum wlr_direction d); -void handle_output_layout_change(struct wl_listener *listener, void *data); void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data); diff --git a/include/sway/server.h b/include/sway/server.h index 460f9e17f..ccf4a9cc2 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -45,7 +45,6 @@ struct sway_server { struct sway_input_manager *input; struct wl_listener new_output; - struct wl_listener output_layout_change; struct wl_listener renderer_lost; struct wlr_idle_notifier_v1 *idle_notifier_v1; diff --git a/include/sway/tree/root.h b/include/sway/tree/root.h index 7de0abcdd..10d9ea981 100644 --- a/include/sway/tree/root.h +++ b/include/sway/tree/root.h @@ -16,8 +16,6 @@ struct sway_root { struct sway_node node; struct wlr_output_layout *output_layout; - struct wl_listener output_layout_change; - // scene node layout: // - root // - staging diff --git a/sway/desktop/output.c b/sway/desktop/output.c index aaa8c087a..5aa46dded 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -578,13 +578,6 @@ void handle_new_output(struct wl_listener *listener, void *data) { request_modeset(server); } -void handle_output_layout_change(struct wl_listener *listener, - void *data) { - struct sway_server *server = - wl_container_of(listener, server, output_layout_change); - update_output_manager_config(server); -} - void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data) { struct sway_server *server = wl_container_of(listener, server, gamma_control_set_gamma); diff --git a/sway/server.c b/sway/server.c index 2922cc10f..12492224d 100644 --- a/sway/server.c +++ b/sway/server.c @@ -272,9 +272,6 @@ bool server_init(struct sway_server *server) { server->new_output.notify = handle_new_output; wl_signal_add(&server->backend->events.new_output, &server->new_output); - server->output_layout_change.notify = handle_output_layout_change; - wl_signal_add(&root->output_layout->events.change, - &server->output_layout_change); server->xdg_output_manager_v1 = wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout); diff --git a/sway/tree/root.c b/sway/tree/root.c index 20fcfa595..19d072b5c 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c @@ -19,12 +19,6 @@ struct sway_root *root; -static void output_layout_handle_change(struct wl_listener *listener, - void *data) { - arrange_root(); - transaction_commit_dirty(); -} - struct sway_root *root_create(struct wl_display *wl_display) { struct sway_root *root = calloc(1, sizeof(struct sway_root)); if (!root) { @@ -81,14 +75,10 @@ struct sway_root *root_create(struct wl_display *wl_display) { root->non_desktop_outputs = create_list(); root->scratchpad = create_list(); - root->output_layout_change.notify = output_layout_handle_change; - wl_signal_add(&root->output_layout->events.change, - &root->output_layout_change); return root; } void root_destroy(struct sway_root *root) { - wl_list_remove(&root->output_layout_change.link); list_free(root->scratchpad); list_free(root->non_desktop_outputs); list_free(root->outputs); From c580b54b5e4223c8830292261da35a7e36f83f10 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 5 Sep 2024 18:32:00 +0200 Subject: [PATCH 39/71] desktop/output: Avoid duplicate output manager update (cherry picked from 4fe054c6db74401f4afc7453fc74665097b5261d) --- sway/desktop/output.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 5aa46dded..67ea6c295 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -683,10 +683,6 @@ static void output_manager_apply(struct sway_server *server, wlr_output_configuration_v1_send_failed(config); } wlr_output_configuration_v1_destroy(config); - - if (!test_only) { - update_output_manager_config(server); - } } void handle_output_manager_apply(struct wl_listener *listener, void *data) { From b7be9de2bec17bf5263f16ef8e388b6e311ea53c Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 5 Sep 2024 18:32:51 +0200 Subject: [PATCH 40/71] tree/output: Avoid duplicate input mapping configure (cherry picked from 4fe054c6db74401f4afc7453fc74665097b5261d) --- sway/tree/output.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sway/tree/output.c b/sway/tree/output.c index f3b0b27a2..44b941ca2 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -180,8 +180,6 @@ void output_enable(struct sway_output *output) { ws->layout = output_get_default_layout(output); } - input_manager_configure_xcursor(); - wl_signal_emit_mutable(&root->events.new_node, &output->node); } From 2879260f797f679954746bfff6a38365328b3929 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 6 Sep 2024 00:35:57 +0200 Subject: [PATCH 41/71] tree/arrange: Remove redundant output geometry update This is handled by apply_output_configs. (cherry picked from 4f9ce4675cf428e8acd632de31482981e1bedcf8) --- sway/tree/arrange.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index d4003fe65..352ec0e57 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c @@ -314,14 +314,6 @@ void arrange_output(struct sway_output *output) { if (config->reloading) { return; } - struct wlr_box output_box; - wlr_output_layout_get_box(root->output_layout, - output->wlr_output, &output_box); - output->lx = output_box.x; - output->ly = output_box.y; - output->width = output_box.width; - output->height = output_box.height; - for (int i = 0; i < output->workspaces->length; ++i) { struct sway_workspace *workspace = output->workspaces->items[i]; arrange_workspace(workspace); From af86879462aa06ec2c6aaba4c9ef49c3c7d4c638 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Fri, 6 Sep 2024 00:42:49 +0200 Subject: [PATCH 42/71] tree/arrange; Skip arranging disabled outputs Disabled outputs might not have a geometry to arrange for, so skip the arrange to avoid messing up the workspace geometry. (cherry picked from f4a6b0395f3fe38cb14bec1f5ac30445496e525c) --- sway/tree/arrange.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index 352ec0e57..2b95a6dc9 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c @@ -314,6 +314,9 @@ void arrange_output(struct sway_output *output) { if (config->reloading) { return; } + if (!output->wlr_output->enabled) { + return; + } for (int i = 0; i < output->workspaces->length; ++i) { struct sway_workspace *workspace = output->workspaces->items[i]; arrange_workspace(workspace); From 5664103902d688b263c4f44f620b70f409f4e23c Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 5 Sep 2024 22:25:44 +0200 Subject: [PATCH 43/71] config/output: Support multiple matches in find_output_config Simplify find_output_config and inline the search through the output configs instead of using list_seq_find with a comparator function. The new implementation will merge any amount of matched configs in order, which will be relied upon in a future commit. (cherry picked from a0c03499348a4a3d4d2e9a387bf366ccbcf68186) --- sway/config/output.c | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/sway/config/output.c b/sway/config/output.c index 230c2f5d9..d7e7657a0 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -26,13 +26,6 @@ #include #endif -int output_name_cmp(const void *item, const void *data) { - const struct output_config *output = item; - const char *name = data; - - return strcmp(output->name, name); -} - void output_get_identifier(char *identifier, size_t len, struct sway_output *output) { struct wlr_output *wlr_output = output->wlr_output; @@ -624,8 +617,6 @@ static void default_output_config(struct output_config *oc, // configuration that applies to the specified output. struct output_config *find_output_config(struct sway_output *sway_output) { const char *name = sway_output->wlr_output->name; - struct output_config *oc = NULL; - struct output_config *result = new_output_config(name); if (config->reloading) { default_output_config(result, sway_output->wlr_output); @@ -634,25 +625,21 @@ struct output_config *find_output_config(struct sway_output *sway_output) { char id[128]; output_get_identifier(id, sizeof(id), sway_output); - int i; - bool match = false; - if ((i = list_seq_find(config->output_configs, output_name_cmp, "*")) >= 0) { - match = true; - oc = config->output_configs->items[i]; - merge_output_config(result, oc); - } - if ((i = list_seq_find(config->output_configs, output_name_cmp, name)) >= 0) { - match = true; - oc = config->output_configs->items[i]; - merge_output_config(result, oc); - } - if ((i = list_seq_find(config->output_configs, output_name_cmp, id)) >= 0) { - match = true; - oc = config->output_configs->items[i]; - merge_output_config(result, oc); + // We take a new config and merge on top, in order, the wildcard config, + // output config by name, and output config by identifier to form the final + // config. If there are multiple matches, they are merged in order. + struct output_config *oc = NULL; + const char *names[] = {"*", name, id, NULL}; + for (const char **name = &names[0]; *name; name++) { + for (int idx = 0; idx < config->output_configs->length; idx++) { + oc = config->output_configs->items[idx]; + if (strcmp(oc->name, *name) == 0) { + merge_output_config(result, oc); + } + } } - if (!match && !config->reloading) { + if (oc == NULL && !config->reloading) { // No name, identifier, or wildcard config. Since we are not // reloading with defaults, the output config will be empty, so // just return NULL From 3b27392a472bf31b91b50421a92bc53065020701 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 9 Sep 2024 11:57:06 +0200 Subject: [PATCH 44/71] config/output: Always start with default in find_output_config We always need to start out with the default configuration, regardless of whether the config is reloading or not to ensure that config decisions are stable given a specific configuration. (cherry picked from 0496477f92e60d504c3938a54e823ad56c8b1868) --- sway/config/output.c | 41 +++++++++++------------------------------ 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/sway/config/output.c b/sway/config/output.c index d7e7657a0..b182f4b4a 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -593,35 +593,24 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output return true; } -static void default_output_config(struct output_config *oc, - struct wlr_output *wlr_output) { - oc->enabled = 1; - oc->power = 1; - struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output); - if (mode != NULL) { - oc->width = mode->width; - oc->height = mode->height; - oc->refresh_rate = mode->refresh / 1000.f; - } - oc->x = oc->y = -1; - oc->scale = 0; // auto - oc->scale_filter = SCALE_FILTER_DEFAULT; - struct sway_output *output = wlr_output->data; - oc->subpixel = output->detected_subpixel; - oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; - oc->max_render_time = 0; - oc->allow_tearing = 0; -} - // find_output_config returns a merged output_config containing all stored // configuration that applies to the specified output. struct output_config *find_output_config(struct sway_output *sway_output) { const char *name = sway_output->wlr_output->name; struct output_config *result = new_output_config(name); - if (config->reloading) { - default_output_config(result, sway_output->wlr_output); + if (result == NULL) { + return NULL; } + // Set output defaults for the "base" configuration + result->enabled = 1; + result->power = 1; + result->scale = 0; // auto + result->subpixel = sway_output->detected_subpixel; + result->transform = WL_OUTPUT_TRANSFORM_NORMAL; + result->max_render_time = 0; + result->allow_tearing = 0; + char id[128]; output_get_identifier(id, sizeof(id), sway_output); @@ -639,14 +628,6 @@ struct output_config *find_output_config(struct sway_output *sway_output) { } } - if (oc == NULL && !config->reloading) { - // No name, identifier, or wildcard config. Since we are not - // reloading with defaults, the output config will be empty, so - // just return NULL - free_output_config(result); - return NULL; - } - return result; } From a9c295fd6709e788d9b12167a53d2f8c031718f0 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 9 Sep 2024 15:28:22 +0200 Subject: [PATCH 45/71] config/output: Accept a list of output_configs to use Instead of using a single finalized output config per output, accept a regular list of output configs like the one ultimately stored for configuration purposes. This allows the output management code to test an augmented configuration while still using the same output config logic, without having to mutate the stored configuration. This in turn allows us to make a few APIs private. A bug note about an existing issue with derade to off is added as well. (cherry picked from 29b3f00e6fd99296cde7e94b7063acfd075c559c) --- include/sway/config.h | 15 ++------ sway/config/output.c | 47 ++++++++++++++++++------- sway/desktop/output.c | 80 ++++++++++++++++--------------------------- 3 files changed, 67 insertions(+), 75 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index 2f5a17fae..33cebe2aa 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -297,14 +297,6 @@ struct output_config { char *background_fallback; }; -/** - * An output config pre-matched to an output - */ -struct matched_output_config { - struct sway_output *output; - struct output_config *config; -}; - /** * Stores size of gaps for each side */ @@ -694,14 +686,11 @@ const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filt struct output_config *new_output_config(const char *name); -bool apply_output_configs(struct matched_output_config *configs, - size_t configs_len, bool test_only, bool degrade_to_off); +bool apply_output_configs(struct output_config **ocs, size_t ocs_len, + bool test_only, bool degrade_to_off); void apply_all_output_configs(void); -void sort_output_configs_by_priority(struct matched_output_config *configs, - size_t configs_len); - /** * store_output_config stores a new output config. An output may be matched by * three different config types, in order of precedence: Identifier, name and diff --git a/sway/config/output.c b/sway/config/output.c index b182f4b4a..60718bf03 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -593,9 +593,11 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output return true; } -// find_output_config returns a merged output_config containing all stored -// configuration that applies to the specified output. -struct output_config *find_output_config(struct sway_output *sway_output) { +// find_output_config_from_list returns a merged output_config containing all +// stored configuration that applies to the specified output. +static struct output_config *find_output_config_from_list( + struct output_config **configs, size_t configs_len, + struct sway_output *sway_output) { const char *name = sway_output->wlr_output->name; struct output_config *result = new_output_config(name); if (result == NULL) { @@ -620,8 +622,8 @@ struct output_config *find_output_config(struct sway_output *sway_output) { struct output_config *oc = NULL; const char *names[] = {"*", name, id, NULL}; for (const char **name = &names[0]; *name; name++) { - for (int idx = 0; idx < config->output_configs->length; idx++) { - oc = config->output_configs->items[idx]; + for (size_t idx = 0; idx < configs_len; idx++) { + oc = configs[idx]; if (strcmp(oc->name, *name) == 0) { merge_output_config(result, oc); } @@ -631,6 +633,12 @@ struct output_config *find_output_config(struct sway_output *sway_output) { return result; } +struct output_config *find_output_config(struct sway_output *sway_output) { + return find_output_config_from_list( + (struct output_config **)config->output_configs->items, + config->output_configs->length, sway_output); +} + static bool config_has_manual_mode(struct output_config *oc) { if (!oc) { return false; @@ -643,6 +651,14 @@ static bool config_has_manual_mode(struct output_config *oc) { return false; } +/** + * An output config pre-matched to an output + */ +struct matched_output_config { + struct sway_output *output; + struct output_config *config; +}; + struct search_context { struct wlr_output_swapchain_manager *swapchain_mgr; struct wlr_backend_output_state *states; @@ -869,12 +885,12 @@ static int compare_matched_output_config_priority(const void *a, const void *b) return 0; } -void sort_output_configs_by_priority(struct matched_output_config *configs, - size_t configs_len) { +static void sort_output_configs_by_priority( + struct matched_output_config *configs, size_t configs_len) { qsort(configs, configs_len, sizeof(*configs), compare_matched_output_config_priority); } -bool apply_output_configs(struct matched_output_config *configs, +static bool apply_resolved_output_configs(struct matched_output_config *configs, size_t configs_len, bool test_only, bool degrade_to_off) { struct wlr_backend_output_state *states = calloc(configs_len, sizeof(*states)); if (!states) { @@ -982,11 +998,12 @@ out: return ok; } -void apply_all_output_configs(void) { +bool apply_output_configs(struct output_config **ocs, size_t ocs_len, + bool test_only, bool degrade_to_off) { size_t configs_len = wl_list_length(&root->all_outputs); struct matched_output_config *configs = calloc(configs_len, sizeof(*configs)); if (!configs) { - return; + return false; } int config_idx = 0; @@ -999,16 +1016,22 @@ void apply_all_output_configs(void) { struct matched_output_config *config = &configs[config_idx++]; config->output = sway_output; - config->config = find_output_config(sway_output); + config->config = find_output_config_from_list(ocs, ocs_len, sway_output); } sort_output_configs_by_priority(configs, configs_len); - apply_output_configs(configs, configs_len, false, true); + bool ok = apply_resolved_output_configs(configs, configs_len, test_only, degrade_to_off); for (size_t idx = 0; idx < configs_len; idx++) { struct matched_output_config *cfg = &configs[idx]; free_output_config(cfg->config); } free(configs); + return ok; +} + +void apply_all_output_configs(void) { + apply_output_configs((struct output_config **)config->output_configs->items, + config->output_configs->length, false, true); } void free_output_config(struct output_config *oc) { diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 67ea6c295..1fd2f6931 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -594,9 +594,8 @@ void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data) { } static struct output_config *output_config_for_config_head( - struct wlr_output_configuration_head_v1 *config_head, - struct sway_output *output) { - struct output_config *oc = new_output_config(output->wlr_output->name); + struct wlr_output_configuration_head_v1 *config_head) { + struct output_config *oc = new_output_config(config_head->state.output->name); oc->enabled = config_head->state.enabled; if (!oc->enabled) { return oc; @@ -622,67 +621,48 @@ static struct output_config *output_config_for_config_head( } static void output_manager_apply(struct sway_server *server, - struct wlr_output_configuration_v1 *config, bool test_only) { - size_t configs_len = wl_list_length(&root->all_outputs); - struct matched_output_config *configs = calloc(configs_len, sizeof(*configs)); + struct wlr_output_configuration_v1 *cfg, bool test_only) { + bool ok = false; + size_t configs_len = config->output_configs->length + wl_list_length(&cfg->heads); + struct output_config **configs = calloc(configs_len, sizeof(*configs)); if (!configs) { - return; + goto done; + } + size_t start_new_configs = config->output_configs->length; + for (size_t idx = 0; idx < start_new_configs; idx++) { + configs[idx] = config->output_configs->items[idx]; } - int config_idx = 0; - struct sway_output *sway_output; - wl_list_for_each(sway_output, &root->all_outputs, link) { - if (sway_output == root->fallback_output) { - configs_len--; - continue; - } - - struct matched_output_config *cfg = &configs[config_idx++]; - cfg->output = sway_output; - - struct wlr_output_configuration_head_v1 *config_head; - wl_list_for_each(config_head, &config->heads, link) { - if (config_head->state.output == sway_output->wlr_output) { - cfg->config = output_config_for_config_head(config_head, sway_output); - break; - } - } - if (!cfg->config) { - cfg->config = find_output_config(sway_output); - } + size_t config_idx = start_new_configs; + struct wlr_output_configuration_head_v1 *config_head; + wl_list_for_each(config_head, &cfg->heads, link) { + // Generate the configuration and store it as a temporary + // config. We keep a record of it so we can remove it later. + struct output_config *oc = output_config_for_config_head(config_head); + configs[config_idx++] = oc; } - sort_output_configs_by_priority(configs, configs_len); - bool ok = apply_output_configs(configs, configs_len, test_only, false); - for (size_t idx = 0; idx < configs_len; idx++) { - struct matched_output_config *cfg = &configs[idx]; - - // Only store new configs for successful non-test commits. Old configs, - // test-only and failed commits just get freed. - bool store_config = false; + // Try to commit without degrade to off enabled. Note that this will fail + // if any output configured for enablement fails to be enabled, even if it + // was not part of the config heads we were asked to configure. + ok = apply_output_configs(configs, configs_len, test_only, false); + for (size_t idx = start_new_configs; idx < configs_len; idx++) { + struct output_config *cfg = configs[idx]; if (!test_only && ok) { - struct wlr_output_configuration_head_v1 *config_head; - wl_list_for_each(config_head, &config->heads, link) { - if (config_head->state.output == cfg->output->wlr_output) { - store_config = true; - break; - } - } - } - if (store_config) { - store_output_config(cfg->config); + store_output_config(cfg); } else { - free_output_config(cfg->config); + free_output_config(cfg); } } free(configs); +done: if (ok) { - wlr_output_configuration_v1_send_succeeded(config); + wlr_output_configuration_v1_send_succeeded(cfg); } else { - wlr_output_configuration_v1_send_failed(config); + wlr_output_configuration_v1_send_failed(cfg); } - wlr_output_configuration_v1_destroy(config); + wlr_output_configuration_v1_destroy(cfg); } void handle_output_manager_apply(struct wl_listener *listener, void *data) { From 5686be82c6b1c25e5c188ee05690edfe981ff9c0 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 9 Sep 2024 20:04:17 +0200 Subject: [PATCH 46/71] config/output: Rename to apply_stored_output_configs (cherry-picked from d7a76d381bbe4321578bc3a95fbc82d76b67ef05) --- include/sway/config.h | 2 +- sway/commands/output.c | 2 +- sway/config.c | 2 +- sway/config/output.c | 2 +- sway/desktop/output.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index 33cebe2aa..3cd59722f 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -689,7 +689,7 @@ struct output_config *new_output_config(const char *name); bool apply_output_configs(struct output_config **ocs, size_t ocs_len, bool test_only, bool degrade_to_off); -void apply_all_output_configs(void); +void apply_stored_output_configs(void); /** * store_output_config stores a new output config. An output may be matched by diff --git a/sway/commands/output.c b/sway/commands/output.c index 9478e0bad..3f65b909c 100644 --- a/sway/commands/output.c +++ b/sway/commands/output.c @@ -111,7 +111,7 @@ struct cmd_results *cmd_output(int argc, char **argv) { // entire config and before the deferred commands so that an auto generated // workspace name is not given to re-enabled outputs. if (!config->reloading && !config->validating) { - apply_all_output_configs(); + apply_stored_output_configs(); if (background) { if (!spawn_swaybg()) { return cmd_results_new(CMD_FAILURE, diff --git a/sway/config.c b/sway/config.c index 5058efcc0..5fc414a14 100644 --- a/sway/config.c +++ b/sway/config.c @@ -533,7 +533,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) { } sway_switch_retrigger_bindings_for_all(); - apply_all_output_configs(); + apply_stored_output_configs(); spawn_swaybg(); config->reloading = false; diff --git a/sway/config/output.c b/sway/config/output.c index 60718bf03..84d0c6dde 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -1029,7 +1029,7 @@ bool apply_output_configs(struct output_config **ocs, size_t ocs_len, return ok; } -void apply_all_output_configs(void) { +void apply_stored_output_configs(void) { apply_output_configs((struct output_config **)config->output_configs->items, config->output_configs->length, false, true); } diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 1fd2f6931..24ea019a8 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -404,7 +404,7 @@ static int timer_modeset_handle(void *data) { wl_event_source_remove(server->delayed_modeset); server->delayed_modeset = NULL; - apply_all_output_configs(); + apply_stored_output_configs(); return 0; } From 7f9baa05fa1e6c5677c88bc45da354bdeefcedd3 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 18 Sep 2024 00:46:29 +0200 Subject: [PATCH 47/71] ext-session-lock: Do not use commit listener to arrange Arranging lock surfaces rely on the sway_output width and height being updated, but these are only updated after the commit has been completed and all commit listeners have executed. This means that the lock surfaces will not be appropriately scaled to match a change in output dimensions, and may reveal what is under the lock background. Replace the implicit arrange through the output commit listener with an explicit arrange after the output configuration is finalized. This might have regressed by other transition away from output commit listeners for other arrange tasks, but even then it would have erroneously relied on signalling order. (cherry-picked from 785a459a55d8b55b4bed1fdc55b04c32be5b450c) --- include/sway/lock.h | 6 ++++++ sway/config/output.c | 2 ++ sway/lock.c | 29 ++++++++++++----------------- 3 files changed, 20 insertions(+), 17 deletions(-) create mode 100644 include/sway/lock.h diff --git a/include/sway/lock.h b/include/sway/lock.h new file mode 100644 index 000000000..5be0f9695 --- /dev/null +++ b/include/sway/lock.h @@ -0,0 +1,6 @@ +#ifndef _SWAY_LOCK_H +#define _SWAY_LOCK_H + +void arrange_locks(void); + +#endif diff --git a/sway/config/output.c b/sway/config/output.c index 84d0c6dde..8e2528c80 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -15,6 +15,7 @@ #include "sway/desktop/transaction.h" #include "sway/input/cursor.h" #include "sway/layers.h" +#include "sway/lock.h" #include "sway/output.h" #include "sway/server.h" #include "sway/tree/arrange.h" @@ -971,6 +972,7 @@ static bool apply_resolved_output_configs(struct matched_output_config *configs, } arrange_root(); + arrange_locks(); update_output_manager_config(&server); transaction_commit_dirty(); diff --git a/sway/lock.c b/sway/lock.c index 289e8ca46..43f313308 100644 --- a/sway/lock.c +++ b/sway/lock.c @@ -8,6 +8,7 @@ #include "sway/layers.h" #include "sway/output.h" #include "sway/server.h" +#include "sway/lock.h" struct sway_session_lock_output { struct wlr_scene_tree *tree; @@ -19,7 +20,6 @@ struct sway_session_lock_output { struct wl_list link; // sway_session_lock::outputs struct wl_listener destroy; - struct wl_listener commit; struct wlr_session_lock_surface_v1 *surface; @@ -89,6 +89,17 @@ static void lock_output_reconfigure(struct sway_session_lock_output *output) { } } +void arrange_locks(void) { + if (server.session_lock.lock == NULL) { + return; + } + + struct sway_session_lock_output *lock_output; + wl_list_for_each(lock_output, &server.session_lock.lock->outputs, link) { + lock_output_reconfigure(lock_output); + } +} + static void handle_new_surface(struct wl_listener *listener, void *data) { struct sway_session_lock *lock = wl_container_of(listener, lock, new_surface); struct wlr_session_lock_surface_v1 *lock_surface = data; @@ -125,7 +136,6 @@ static void sway_session_lock_output_destroy(struct sway_session_lock_output *ou wl_list_remove(&output->surface_map.link); } - wl_list_remove(&output->commit.link); wl_list_remove(&output->destroy.link); wl_list_remove(&output->link); @@ -138,18 +148,6 @@ static void lock_node_handle_destroy(struct wl_listener *listener, void *data) { sway_session_lock_output_destroy(output); } -static void lock_output_handle_commit(struct wl_listener *listener, void *data) { - struct wlr_output_event_commit *event = data; - struct sway_session_lock_output *output = - wl_container_of(listener, output, commit); - if (event->state->committed & ( - WLR_OUTPUT_STATE_MODE | - WLR_OUTPUT_STATE_SCALE | - WLR_OUTPUT_STATE_TRANSFORM)) { - lock_output_reconfigure(output); - } -} - static struct sway_session_lock_output *session_lock_output_create( struct sway_session_lock *lock, struct sway_output *output) { struct sway_session_lock_output *lock_output = calloc(1, sizeof(*lock_output)); @@ -186,9 +184,6 @@ static struct sway_session_lock_output *session_lock_output_create( lock_output->destroy.notify = lock_node_handle_destroy; wl_signal_add(&tree->node.events.destroy, &lock_output->destroy); - lock_output->commit.notify = lock_output_handle_commit; - wl_signal_add(&output->wlr_output->events.commit, &lock_output->commit); - lock_output_reconfigure(lock_output); wl_list_insert(&lock->outputs, &lock_output->link); From 0299e0412aa8639f4c703ba8e626bd075a9bd7b8 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 21 Sep 2024 00:53:26 +0200 Subject: [PATCH 48/71] commands/gaps: Check config->reading instead Checking if the config is not active or is reloading is just a convoluted way of checking if the config is being read. (cherry picked from commit 861dde100ab5536bea190b078c6c51adb6814be5) --- sway/commands/gaps.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sway/commands/gaps.c b/sway/commands/gaps.c index 1deeb56e1..7ac6fcff5 100644 --- a/sway/commands/gaps.c +++ b/sway/commands/gaps.c @@ -215,15 +215,13 @@ struct cmd_results *cmd_gaps(int argc, char **argv) { return error; } - bool config_loading = !config->active || config->reloading; - if (argc == 2) { return gaps_set_defaults(argc, argv); } - if (argc == 4 && !config_loading) { + if (argc == 4 && !config->reading) { return gaps_set_runtime(argc, argv); } - if (config_loading) { + if (config->reading) { return cmd_results_new(CMD_INVALID, "Expected %s", expected_defaults); } return cmd_results_new(CMD_INVALID, "Expected %s or %s", From 952c428482682122603e19a0d5a695572d9e54df Mon Sep 17 00:00:00 2001 From: Olivia Taliesin Date: Tue, 15 Feb 2022 14:46:12 -0700 Subject: [PATCH 49/71] Removed destination-is-ancestor check from container_move_to_container to match i3 behaviour (cherry picked from commit b6da218974d2e0508e7816f707fe0b1f1c97f0d6) --- sway/commands/move.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sway/commands/move.c b/sway/commands/move.c index ad106c648..8891514ce 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -240,7 +240,6 @@ static void container_move_to_workspace(struct sway_container *container, static void container_move_to_container(struct sway_container *container, struct sway_container *destination) { if (container == destination - || container_has_ancestor(container, destination) || container_has_ancestor(destination, container)) { return; } From 4aa71ca661e0cac3927ca1d42d968b8b3f9b4225 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 21 Sep 2024 00:51:14 +0200 Subject: [PATCH 50/71] desktop/output: Expose request_modeset We remove the struct sway_server argument for consistency with the rest of our internal APIs which rely on the global server instance. (cherry picked from commit b73f54a966a30c2253818b89fefda16477531c14) --- include/sway/config.h | 2 ++ sway/desktop/output.c | 18 ++++++++---------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index 3cd59722f..71721393e 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -704,6 +704,8 @@ struct output_config *find_output_config(struct sway_output *output); void free_output_config(struct output_config *oc); +void request_modeset(void); + bool spawn_swaybg(void); int workspace_output_cmp_workspace(const void *a, const void *b); diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 24ea019a8..1f5b73d98 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -408,17 +408,15 @@ static int timer_modeset_handle(void *data) { return 0; } -static void request_modeset(struct sway_server *server) { - if (server->delayed_modeset == NULL) { - server->delayed_modeset = wl_event_loop_add_timer(server->wl_event_loop, - timer_modeset_handle, server); - wl_event_source_timer_update(server->delayed_modeset, 10); +void request_modeset(void) { + if (server.delayed_modeset == NULL) { + server.delayed_modeset = wl_event_loop_add_timer(server.wl_event_loop, + timer_modeset_handle, &server); + wl_event_source_timer_update(server.delayed_modeset, 10); } } static void begin_destroy(struct sway_output *output) { - struct sway_server *server = output->server; - if (output->enabled) { output_disable(output); } @@ -439,7 +437,7 @@ static void begin_destroy(struct sway_output *output) { output->wlr_output->data = NULL; output->wlr_output = NULL; - request_modeset(server); + request_modeset(); } static void handle_destroy(struct wl_listener *listener, void *data) { @@ -575,7 +573,7 @@ void handle_new_output(struct wl_listener *listener, void *data) { sway_session_lock_add_output(server->session_lock.lock, output); } - request_modeset(server); + request_modeset(); } void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data) { @@ -696,5 +694,5 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener, break; } store_output_config(oc); - request_modeset(output->server); + request_modeset(); } From 4ea5a9cee140377bdf1aae699c801ef497cb9899 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 21 Sep 2024 01:00:04 +0200 Subject: [PATCH 51/71] config: Batch input/output configuration on load We batch modesets and input configuration performed during config reload but commit for every command during the intial config load. There is no need to perform commits during the initial config load as outputs have not yet been created, but swaybg spawn should still be batched. At the same time, replace direct calls to apply output configuration with request_modeset to properly handle the modeset timer. (cherry picked from commit cdff4f7c74b76e9141164b8c154621646140d8ec) --- sway/commands/input.c | 2 +- sway/commands/output.c | 21 ++++++++++----------- sway/config.c | 10 ++++++---- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/sway/commands/input.c b/sway/commands/input.c index 35846b1cf..310375a94 100644 --- a/sway/commands/input.c +++ b/sway/commands/input.c @@ -94,7 +94,7 @@ struct cmd_results *cmd_input(int argc, char **argv) { return res; } - if (!config->reloading) { + if (!config->reading) { input_manager_apply_input_config(ic); } } else { diff --git a/sway/commands/output.c b/sway/commands/output.c index 3f65b909c..9d58413f2 100644 --- a/sway/commands/output.c +++ b/sway/commands/output.c @@ -107,17 +107,16 @@ struct cmd_results *cmd_output(int argc, char **argv) { store_output_config(output); - // If reloading, the output configs will be applied after reading the - // entire config and before the deferred commands so that an auto generated - // workspace name is not given to re-enabled outputs. - if (!config->reloading && !config->validating) { - apply_stored_output_configs(); - if (background) { - if (!spawn_swaybg()) { - return cmd_results_new(CMD_FAILURE, - "Failed to apply background configuration"); - } - } + if (config->reading) { + // When reading the config file, we wait till the end to do a single + // modeset and swaybg spawn. + return cmd_results_new(CMD_SUCCESS, NULL); + } + request_modeset(); + + if (background && !spawn_swaybg()) { + return cmd_results_new(CMD_FAILURE, + "Failed to apply background configuration"); } return cmd_results_new(CMD_SUCCESS, NULL); diff --git a/sway/config.c b/sway/config.c index 5fc414a14..1090edc5c 100644 --- a/sway/config.c +++ b/sway/config.c @@ -516,7 +516,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) { // Only really necessary if not explicitly `font` is set in the config. config_update_font_height(); - if (is_active && !validating) { + if (!validating) { input_manager_verify_fallback_seat(); for (int i = 0; i < config->input_configs->length; i++) { @@ -533,12 +533,14 @@ bool load_main_config(const char *file, bool is_active, bool validating) { } sway_switch_retrigger_bindings_for_all(); - apply_stored_output_configs(); spawn_swaybg(); config->reloading = false; - if (config->swaynag_config_errors.client != NULL) { - swaynag_show(&config->swaynag_config_errors); + if (is_active) { + request_modeset(); + if (config->swaynag_config_errors.client != NULL) { + swaynag_show(&config->swaynag_config_errors); + } } } From 75cfed65bb79e30c92e756590039fb824fe63e14 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 21 Sep 2024 01:02:54 +0200 Subject: [PATCH 52/71] desktop/output: Clear modeset timer on output manager apply If a modeset timer exists at the time we apply an output manager config, clear it to avoid a useless double commit. (cherry picked from commit 63345977e2c411359a049c40cf2c1044a22b4f4a) --- sway/desktop/output.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 1f5b73d98..0a19ad579 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -657,6 +657,10 @@ static void output_manager_apply(struct sway_server *server, done: if (ok) { wlr_output_configuration_v1_send_succeeded(cfg); + if (server->delayed_modeset != NULL) { + wl_event_source_remove(server->delayed_modeset); + server->delayed_modeset = NULL; + } } else { wlr_output_configuration_v1_send_failed(cfg); } From 1311685d1c799d426795d2c4ddfa892fe405899f Mon Sep 17 00:00:00 2001 From: Furkan Sahin Date: Wed, 25 Sep 2024 06:35:30 -0500 Subject: [PATCH 53/71] swaybar: Fix 100% cpu usage if dbus dies. Currently, swaybar does not gracefully die if it detects that the dbus connection was lost. Although it's not recommended to restart dbus without restarting the compositor, it can very easily happen. In the case it does, compositor's tray should not consume 100% cpu until it has to be force killed. apply suggestions just setting the bar to not running will call teardown and unref the dbus. (cherry picked from commit 00e9a941523baa4afa1f9c077235aa7aa5e8aeab) --- swaybar/bar.c | 2 +- swaybar/ipc.c | 3 +-- swaybar/tray/tray.c | 12 ++++++++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/swaybar/bar.c b/swaybar/bar.c index 5b1213a8d..4d20f20f0 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -508,7 +508,7 @@ void bar_run(struct swaybar *bar) { } #if HAVE_TRAY if (bar->tray) { - loop_add_fd(bar->eventloop, bar->tray->fd, POLLIN, tray_in, bar->tray->bus); + loop_add_fd(bar->eventloop, bar->tray->fd, POLLIN, tray_in, bar); } #endif while (bar->running) { diff --git a/swaybar/ipc.c b/swaybar/ipc.c index 03500bdf3..71c9a4c5e 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c @@ -518,8 +518,7 @@ static bool handle_barconfig_update(struct swaybar *bar, const char *payload, #if HAVE_TRAY if (oldcfg->tray_hidden && !newcfg->tray_hidden) { bar->tray = create_tray(bar); - loop_add_fd(bar->eventloop, bar->tray->fd, POLLIN, tray_in, - bar->tray->bus); + loop_add_fd(bar->eventloop, bar->tray->fd, POLLIN, tray_in, bar); } else if (bar->tray && newcfg->tray_hidden) { loop_remove_fd(bar->eventloop, bar->tray->fd); destroy_tray(bar->tray); diff --git a/swaybar/tray/tray.c b/swaybar/tray/tray.c index b0545f4a7..a4f382bfb 100644 --- a/swaybar/tray/tray.c +++ b/swaybar/tray/tray.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -90,9 +91,16 @@ void destroy_tray(struct swaybar_tray *tray) { } void tray_in(int fd, short mask, void *data) { - sd_bus *bus = data; + struct swaybar *bar = data; int ret; - while ((ret = sd_bus_process(bus, NULL)) > 0) { + + if (mask & (POLLHUP | POLLERR)) { + sway_log(SWAY_ERROR, "D-Bus connection closed unexpectedly"); + bar->running = false; + return; + } + + while ((ret = sd_bus_process(bar->tray->bus, NULL)) > 0) { // This space intentionally left blank } if (ret < 0) { From 872cf451a1821931fca9c4f1dce279d8254cb2d2 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 29 Sep 2024 16:57:52 +0200 Subject: [PATCH 54/71] Add support for alpha-modifier-v1 (cherry picked from commit a0b3606f1725ee56e8dc15ae51ce62d042c0668a) --- sway/server.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sway/server.c b/sway/server.c index 12492224d..9648f258c 100644 --- a/sway/server.c +++ b/sway/server.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -321,6 +322,7 @@ bool server_init(struct sway_server *server) { &server->pointer_constraint); wlr_presentation_create(server->wl_display, server->backend); + wlr_alpha_modifier_v1_create(server->wl_display); server->output_manager_v1 = wlr_output_manager_v1_create(server->wl_display); From ae75fea8ef7434749a8074b12438a65aec4b2038 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 29 Sep 2024 17:32:08 +0200 Subject: [PATCH 55/71] build: bump version to 1.10-rc1 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 6999e199c..38b4056f1 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'sway', 'c', - version: '1.10-dev', + version: '1.10-rc1', license: 'MIT', meson_version: '>=0.60.0', default_options: [ From 703671a12dd979b3cd75d44334fe43a433dc2162 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 29 Sep 2024 17:38:27 +0200 Subject: [PATCH 56/71] release: push tags before creating GitHub release Otherwise the GitHub release isn't attached to the Git tag. (cherry picked from commit a2757e5f165eae445ae550fd1d13f9ec0db44efc) --- release.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/release.sh b/release.sh index 62baf4153..c5644cfd0 100755 --- a/release.sh +++ b/release.sh @@ -28,4 +28,5 @@ archive=$prefix.tar.gz git archive --prefix="$prefix/" -o "$archive" "$next" gpg --output "$archive".sig --detach-sig "$archive" +git push --follow-tags gh release create "sway $next" -t "$next" -n "" -d "$archive" "$archive.sig" From 0de35b3585f32951a7a7e6c2b1d8673b78cccefd Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sun, 29 Sep 2024 16:50:00 -0400 Subject: [PATCH 57/71] Fix alpha-modifier-v1 (cherry picked from commit 9a9be01ad4130e4e19b437fd064f90982974971f) --- sway/desktop/output.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 0a19ad579..35a61bd0f 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -216,6 +217,15 @@ static void output_configure_scene(struct sway_output *output, if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); + struct wlr_scene_surface *surface = wlr_scene_surface_try_from_buffer(buffer); + + if (surface) { + const struct wlr_alpha_modifier_surface_v1_state *alpha_modifier_state = + wlr_alpha_modifier_v1_get_surface_state(surface->surface); + if (alpha_modifier_state != NULL) { + opacity *= (float)alpha_modifier_state->multiplier; + } + } // hack: don't call the scene setter because that will damage all outputs // We don't want to damage outputs that aren't our current output that From 67ecc7d2cd0f27986ec11fc9b7ef1279af294427 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 2 Oct 2024 15:55:17 +0200 Subject: [PATCH 58/71] Re-init renderer for all outputs on lost context sway_root.outputs only include enabled outputs. We also need to re-init the renderer for any disabled outputs, so use sway_root.all_outputs instead. Resolves the following heap-use-after-free accessing the render formats when a disabled output is modeset after a GPU reset has occurred. (cherry picked from commit c90cb37b2a0861548461daa9b75d75317e01b679) --- sway/server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sway/server.c b/sway/server.c index 9648f258c..7c17fdf11 100644 --- a/sway/server.c +++ b/sway/server.c @@ -204,8 +204,8 @@ static void handle_renderer_lost(struct wl_listener *listener, void *data) { wlr_compositor_set_renderer(server->compositor, renderer); - for (int i = 0; i < root->outputs->length; ++i) { - struct sway_output *output = root->outputs->items[i]; + struct sway_output *output; + wl_list_for_each(output, &root->all_outputs, link) { wlr_output_init_render(output->wlr_output, server->allocator, server->renderer); } From 63005491cfa374c1eb56f5ca6981a8f39961f67e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 6 Oct 2024 16:54:45 +0200 Subject: [PATCH 59/71] build: bump version to 1.10-rc2 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 38b4056f1..a01daccca 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'sway', 'c', - version: '1.10-rc1', + version: '1.10-rc2', license: 'MIT', meson_version: '>=0.60.0', default_options: [ From 91be6e8a09fd8d4b556ff81efc1846943f5c44ea Mon Sep 17 00:00:00 2001 From: ShootingStarDragons Date: Mon, 7 Oct 2024 18:49:44 +0900 Subject: [PATCH 60/71] fix: sway crashes if switch to another workspace with surface when IME popup is shown in pr https://github.com/swaywm/sway/pull/8196, when im_popup_surface is unmapped, author set the popup->relative to NULL, butt popup is still in popup groups, where assert the relative is not NULL, this cause the panic Take the suggestion of Nefsen402, remove the line where set relative to NULL, and add NULL check in scene_descriptor_destory (cherry picked from commit f855b0898bf00285d5a7b840963b327230486632) --- sway/input/text_input.c | 1 + sway/scene_descriptor.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/sway/input/text_input.c b/sway/input/text_input.c index 6bcd02341..e16724671 100644 --- a/sway/input/text_input.c +++ b/sway/input/text_input.c @@ -454,6 +454,7 @@ static void handle_im_popup_surface_unmap(struct wl_listener *listener, void *da struct sway_input_popup *popup = wl_container_of(listener, popup, popup_surface_unmap); + scene_descriptor_destroy(&popup->scene_tree->node, SWAY_SCENE_DESC_POPUP); // relative should already be freed as it should be a child of the just unmapped scene popup->desc.relative = NULL; diff --git a/sway/scene_descriptor.c b/sway/scene_descriptor.c index a30d46646..92bdda00c 100644 --- a/sway/scene_descriptor.c +++ b/sway/scene_descriptor.c @@ -39,6 +39,9 @@ void *scene_descriptor_try_get(struct wlr_scene_node *node, void scene_descriptor_destroy(struct wlr_scene_node *node, enum sway_scene_descriptor_type type) { struct scene_descriptor *desc = scene_node_get_descriptor(node, type); + if (!desc) { + return; + } descriptor_destroy(desc); } From d262a241cc6dacf2701e8f2c5d89848d54f2f1e5 Mon Sep 17 00:00:00 2001 From: Furkan Sahin Date: Tue, 8 Oct 2024 11:09:57 -0500 Subject: [PATCH 61/71] input/mouse: bugfix button2 being interpreted as trying to move the container Man sway(5) specifies that when tiling_drag is enable, the floating_mod can be used to drag tiling, as well as floating containers. However the current code indiscriminately assumes any button press to be intended for moving the container, consequently causing an unintended call to `seatop_move_tilting:handle_button` rather than `seatop_default:handle_button` to pass `state=WL_POINTER_BUTTON_STATE_RELEASED` to `get_active_mouse_binding` My idea was to make 'Handle moving a tiling container' follow the same path as 'Handle moving a floating container' because the initial call to handle moving a floating correctly exits that branch and ends up passing the RELEASED state to `get_active_mouse_binding`. Fixes #8334 (cherry picked from commit 7f1cd0b73ba3290f8ee5f81fdf7f1ffa4c642ea7) --- sway/input/seatop_default.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c index f4a0f4634..52984818c 100644 --- a/sway/input/seatop_default.c +++ b/sway/input/seatop_default.c @@ -491,7 +491,9 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, // Handle moving a tiling container if (config->tiling_drag && (mod_pressed || on_titlebar) && state == WL_POINTER_BUTTON_STATE_PRESSED && !is_floating_or_child && - cont && cont->pending.fullscreen_mode == FULLSCREEN_NONE) { + cont && cont->pending.fullscreen_mode == FULLSCREEN_NONE && + button == (config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT)) { + // If moving a container by its title bar, use a threshold for the drag if (!mod_pressed && config->tiling_drag_threshold > 0) { seatop_begin_move_tiling_threshold(seat, cont); From dc8f5338be5a1fb504ca39337c52fb0baf839f83 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 13 Oct 2024 18:00:12 +0200 Subject: [PATCH 62/71] build: bump version to 1.10-rc3 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index a01daccca..61981f45a 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'sway', 'c', - version: '1.10-rc2', + version: '1.10-rc3', license: 'MIT', meson_version: '>=0.60.0', default_options: [ From fb4969610c2f9461d55507dfbdf237174c615d4c Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Wed, 16 Oct 2024 21:55:57 +0200 Subject: [PATCH 63/71] config/output: Improve modeset state logging Include scale and subpixel in the output state log, and log the output state on first commit attempt instead of just during fallback search. (cherry picked from commit 7d93652105c370518f1e5856f8586b2297cab772) --- sway/config/output.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sway/config/output.c b/sway/config/output.c index 8e2528c80..d774d17eb 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -692,6 +692,13 @@ static void dump_output_state(struct wlr_output *wlr_output, struct wlr_output_s sway_log(SWAY_DEBUG, " adaptive_sync: %s", state->adaptive_sync_enabled ? "enabled": "disabled"); } + if (state->committed & WLR_OUTPUT_STATE_SCALE) { + sway_log(SWAY_DEBUG, " scale: %f", state->scale); + } + if (state->committed & WLR_OUTPUT_STATE_SUBPIXEL) { + sway_log(SWAY_DEBUG, " subpixel: %s", + sway_wl_output_subpixel_to_string(state->subpixel)); + } } static bool search_valid_config(struct search_context *ctx, size_t output_idx); @@ -906,9 +913,8 @@ static bool apply_resolved_output_configs(struct matched_output_config *configs, backend_state->output = cfg->output->wlr_output; wlr_output_state_init(&backend_state->base); - sway_log(SWAY_DEBUG, "Preparing config for %s", - cfg->output->wlr_output->name); queue_output_config(cfg->config, cfg->output, &backend_state->base); + dump_output_state(cfg->output->wlr_output, &backend_state->base); } struct wlr_output_swapchain_manager swapchain_mgr; From 124a96c501734b737258b0302f1e4cfe353a551a Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 17 Oct 2024 00:19:29 +0200 Subject: [PATCH 64/71] config/output: Always set output states from config queue_output_config had some remaining logic that would avoid setting output states if they already appeared to be in effect. That is not what most of the states did nor what is currently expected, so clean that up. (cherry picked from commit 7e0c0dda42183cf3f6a64bace230252cbeadbbd6) --- sway/config/output.c | 53 ++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/sway/config/output.c b/sway/config/output.c index d774d17eb..b9fb773a0 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -451,54 +451,41 @@ static void queue_output_config(struct output_config *oc, wlr_output_state_set_mode(pending, preferred_mode); } - if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) { - sway_log(SWAY_DEBUG, "Set %s subpixel to %s", oc->name, - sway_wl_output_subpixel_to_string(oc->subpixel)); + if (oc && oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN) { wlr_output_state_set_subpixel(pending, oc->subpixel); + } else { + wlr_output_state_set_subpixel(pending, output->detected_subpixel); } - enum wl_output_transform tr = WL_OUTPUT_TRANSFORM_NORMAL; if (oc && oc->transform >= 0) { - tr = oc->transform; + wlr_output_state_set_transform(pending, oc->transform); #if WLR_HAS_DRM_BACKEND } else if (wlr_output_is_drm(wlr_output)) { - tr = wlr_drm_connector_get_panel_orientation(wlr_output); - sway_log(SWAY_DEBUG, "Auto-detected output transform: %d", tr); + wlr_output_state_set_transform(pending, + wlr_drm_connector_get_panel_orientation(wlr_output)); #endif - } - if (wlr_output->transform != tr) { - sway_log(SWAY_DEBUG, "Set %s transform to %d", wlr_output->name, tr); - wlr_output_state_set_transform(pending, tr); + } else { + wlr_output_state_set_transform(pending, WL_OUTPUT_TRANSFORM_NORMAL); } - // Apply the scale last before the commit, because the scale auto-detection - // reads the pending output size - float scale; + // Apply the scale after sorting out the mode, because the scale + // auto-detection reads the pending output size if (oc && oc->scale > 0) { - scale = oc->scale; - // The factional-scale-v1 protocol uses increments of 120ths to send // the scale factor to the client. Adjust the scale so that we use the // same value as the clients'. - float adjusted_scale = round(scale * 120) / 120; - if (scale != adjusted_scale) { - sway_log(SWAY_INFO, "Adjusting output scale from %f to %f", - scale, adjusted_scale); - scale = adjusted_scale; - } + wlr_output_state_set_scale(pending, round(oc->scale * 120) / 120); } else { - scale = compute_default_scale(wlr_output, pending); - sway_log(SWAY_DEBUG, "Auto-detected output scale: %f", scale); - } - if (scale != wlr_output->scale) { - sway_log(SWAY_DEBUG, "Set %s scale to %f", wlr_output->name, scale); - wlr_output_state_set_scale(pending, scale); + wlr_output_state_set_scale(pending, + compute_default_scale(wlr_output, pending)); } - if (oc && oc->adaptive_sync != -1 && wlr_output->adaptive_sync_supported) { - sway_log(SWAY_DEBUG, "Set %s adaptive sync to %d", wlr_output->name, - oc->adaptive_sync); - wlr_output_state_set_adaptive_sync_enabled(pending, oc->adaptive_sync == 1); + if (wlr_output->adaptive_sync_supported) { + if (oc && oc->adaptive_sync != -1) { + wlr_output_state_set_adaptive_sync_enabled(pending, oc->adaptive_sync == 1); + } else { + wlr_output_state_set_adaptive_sync_enabled(pending, false); + } } if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { @@ -513,6 +500,8 @@ static void queue_output_config(struct output_config *oc, } else { wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB8888); } + } else { + wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB8888); } } From baea664edc5e360d2855c9a95e035299245eaca0 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 17 Oct 2024 01:08:54 +0200 Subject: [PATCH 65/71] config/output: Always set all output fields on finalize (cherry picked from commit af0d4a048a38847769fda4898a07a72401ee40be) --- sway/config/output.c | 51 +++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/sway/config/output.c b/sway/config/output.c index b9fb773a0..f39082d04 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -520,24 +520,23 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output return true; } - if (oc) { - enum scale_filter_mode scale_filter_old = output->scale_filter; - switch (oc->scale_filter) { - case SCALE_FILTER_DEFAULT: - case SCALE_FILTER_SMART: - output->scale_filter = ceilf(wlr_output->scale) == wlr_output->scale ? - SCALE_FILTER_NEAREST : SCALE_FILTER_LINEAR; - break; - case SCALE_FILTER_LINEAR: - case SCALE_FILTER_NEAREST: - output->scale_filter = oc->scale_filter; - break; - } - if (scale_filter_old != output->scale_filter) { - sway_log(SWAY_DEBUG, "Set %s scale_filter to %s", oc->name, - sway_output_scale_filter_to_string(output->scale_filter)); - wlr_damage_ring_add_whole(&output->scene_output->damage_ring); - } + enum scale_filter_mode scale_filter_old = output->scale_filter; + enum scale_filter_mode scale_filter_new = oc ? oc->scale_filter : SCALE_FILTER_DEFAULT; + switch (scale_filter_new) { + case SCALE_FILTER_DEFAULT: + case SCALE_FILTER_SMART: + output->scale_filter = ceilf(wlr_output->scale) == wlr_output->scale ? + SCALE_FILTER_NEAREST : SCALE_FILTER_LINEAR; + break; + case SCALE_FILTER_LINEAR: + case SCALE_FILTER_NEAREST: + output->scale_filter = scale_filter_new; + break; + } + if (scale_filter_old != output->scale_filter) { + sway_log(SWAY_DEBUG, "Set %s scale_filter to %s", oc->name, + sway_output_scale_filter_to_string(output->scale_filter)); + wlr_damage_ring_add_whole(&output->scene_output->damage_ring); } // Find position for it @@ -560,25 +559,19 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output output_enable(output); } - if (oc && oc->max_render_time >= 0) { - sway_log(SWAY_DEBUG, "Set %s max render time to %d", - oc->name, oc->max_render_time); - output->max_render_time = oc->max_render_time; - } - if (oc && oc->set_color_transform) { if (oc->color_transform) { wlr_color_transform_ref(oc->color_transform); } wlr_color_transform_unref(output->color_transform); output->color_transform = oc->color_transform; + } else { + wlr_color_transform_unref(output->color_transform); + output->color_transform = NULL; } - if (oc && oc->allow_tearing >= 0) { - sway_log(SWAY_DEBUG, "Set %s allow tearing to %d", - oc->name, oc->allow_tearing); - output->allow_tearing = oc->allow_tearing; - } + output->max_render_time = oc && oc->max_render_time > 0 ? oc->max_render_time : 0; + output->allow_tearing = oc && oc->allow_tearing > 0; return true; } From 46003d0e85887a051930e5941d4bac6046ebe60c Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 17 Oct 2024 01:19:28 +0200 Subject: [PATCH 66/71] config/output: Remove initial values in find_output_config Starting by setting some special initial output config values settings was something sway used to do when the config was initially being processed. This was later changed to always happen, as there shouldn't be differences in how output config is calculated during config load and after. Most of these values are redundant, as they are either the zero value or a value that would be selected if the unset (-1) value was found. For output transforms, the automatic panel orientation code would only trigger if the final output config has an unset transform, which the initial values set in find_output_config made impossible. Remove these initial values and instead use a fresh output config as is. (cherry picked from commit 17ecb9eb1d355c677dc9cf772d372982b7b9541b) --- sway/config/output.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/sway/config/output.c b/sway/config/output.c index f39082d04..6db10b076 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -587,15 +587,6 @@ static struct output_config *find_output_config_from_list( return NULL; } - // Set output defaults for the "base" configuration - result->enabled = 1; - result->power = 1; - result->scale = 0; // auto - result->subpixel = sway_output->detected_subpixel; - result->transform = WL_OUTPUT_TRANSFORM_NORMAL; - result->max_render_time = 0; - result->allow_tearing = 0; - char id[128]; output_get_identifier(id, sizeof(id), sway_output); From f75edbe01bf3eedc5baf64ab6f22ce59afc3bae9 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 17 Oct 2024 01:28:38 +0200 Subject: [PATCH 67/71] config/output: Remove remaining logs from queue_output_config The job of queue_output_config is now just to fill out a wlr_output_state according to the output configuration, but it still has a lot of logging from before we had wlr_output_state or the new modeset logic, when queue_output_state instead touched the implicit pending state of wlr_output. Whatever debug logs it had would already be covered by the output state debug logs or the command debug logs, so let's just remove it. (cherry picked from commit a63027245a6805bb952e47c5751ecdd7d1063d2f) --- sway/config/output.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/sway/config/output.c b/sway/config/output.c index 6db10b076..5fb282d4d 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -285,7 +285,6 @@ static void set_mode(struct wlr_output *output, struct wlr_output_state *pending mhz = mhz <= 0 ? INT_MAX : mhz; if (wl_list_empty(&output->modes) || custom) { - sway_log(SWAY_DEBUG, "Assigning custom mode to %s", output->name); wlr_output_state_set_custom_mode(pending, width, height, refresh_rate > 0 ? mhz : 0); return; @@ -305,10 +304,7 @@ static void set_mode(struct wlr_output *output, struct wlr_output_state *pending } } } - if (best) { - sway_log(SWAY_INFO, "Assigning configured mode (%dx%d@%.3fHz) to %s", - best->width, best->height, best->refresh / 1000.f, output->name); - } else { + if (!best) { best = wlr_output_preferred_mode(output); sway_log(SWAY_INFO, "Configured mode (%dx%d@%.3fHz) not available, " "applying preferred mode (%dx%d@%.3fHz)", @@ -325,7 +321,6 @@ static void set_modeline(struct wlr_output *output, sway_log(SWAY_ERROR, "Modeline can only be set to DRM output"); return; } - sway_log(SWAY_DEBUG, "Assigning custom modeline to %s", output->name); struct wlr_output_mode *mode = wlr_drm_connector_add_mode(output, drm_mode); if (mode) { wlr_output_state_set_mode(pending, mode); @@ -391,7 +386,6 @@ static int compute_default_scale(struct wlr_output *output, double dpi_x = (double) width / (output->phys_width / MM_PER_INCH); double dpi_y = (double) height / (output->phys_height / MM_PER_INCH); - sway_log(SWAY_DEBUG, "Output DPI: %fx%f", dpi_x, dpi_y); if (dpi_x <= HIDPI_DPI_LIMIT || dpi_y <= HIDPI_DPI_LIMIT) { return 1; } @@ -427,25 +421,17 @@ static void queue_output_config(struct output_config *oc, struct wlr_output *wlr_output = output->wlr_output; if (output_config_is_disabling(oc)) { - sway_log(SWAY_DEBUG, "Turning off output %s", wlr_output->name); wlr_output_state_set_enabled(pending, false); return; } - - sway_log(SWAY_DEBUG, "Turning on output %s", wlr_output->name); wlr_output_state_set_enabled(pending, true); if (oc && oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t) -1) { - sway_log(SWAY_DEBUG, "Set %s modeline", - wlr_output->name); set_modeline(wlr_output, pending, &oc->drm_mode); } else if (oc && oc->width > 0 && oc->height > 0) { - sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f Hz)", - wlr_output->name, oc->width, oc->height, oc->refresh_rate); set_mode(wlr_output, pending, oc->width, oc->height, oc->refresh_rate, oc->custom_mode == 1); } else if (!wl_list_empty(&wlr_output->modes)) { - sway_log(SWAY_DEBUG, "Set preferred mode"); struct wlr_output_mode *preferred_mode = wlr_output_preferred_mode(wlr_output); wlr_output_state_set_mode(pending, preferred_mode); From d88c4cf25d7b7d743e6e02b87c41d6cc1b62d0d4 Mon Sep 17 00:00:00 2001 From: Jan Palus Date: Wed, 16 Oct 2024 19:47:54 +0200 Subject: [PATCH 68/71] trigger container update after disabling urgent in timer switching workspace directly to urgent window creates timer which delays reset of urgent state so user is able to notice it. make sure state change is reflected visually as well (border change) by triggering container update Fixes: #8377 (cherry picked from commit db76fefd0c61d2c85f448eeb43ca3a97c10770a5) --- sway/input/seat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sway/input/seat.c b/sway/input/seat.c index 9a00a3e24..0dd26290e 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -1094,6 +1094,7 @@ static void seat_send_unfocus(struct sway_node *node, struct sway_seat *seat) { static int handle_urgent_timeout(void *data) { struct sway_view *view = data; view_set_urgent(view, false); + container_update_itself_and_parents(view->container); return 0; } From 08362d98c632d3ce064ea48a3c308c2ee35c40db Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Mon, 14 Oct 2024 16:03:55 -0400 Subject: [PATCH 69/71] layer_shell: Arrange exclusive zone clients first This makes layer_shell more stable against the order of clients. (cherry picked from commit ce6b2db0f2e9c71dda496d1aaaafcdcb9dade150) --- sway/desktop/layer_shell.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index b136a24e7..62c6a5118 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -54,7 +54,7 @@ struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface( } static void arrange_surface(struct sway_output *output, const struct wlr_box *full_area, - struct wlr_box *usable_area, struct wlr_scene_tree *tree) { + struct wlr_box *usable_area, struct wlr_scene_tree *tree, bool exclusive) { struct wlr_scene_node *node; wl_list_for_each(node, &tree->children, link) { struct sway_layer_surface *surface = scene_descriptor_try_get(node, @@ -68,6 +68,10 @@ static void arrange_surface(struct sway_output *output, const struct wlr_box *fu continue; } + if ((surface->scene->layer_surface->current.exclusive_zone > 0) != exclusive) { + continue; + } + wlr_scene_layer_surface_v1_configure(surface->scene, full_area, usable_area); } } @@ -78,10 +82,14 @@ void arrange_layers(struct sway_output *output) { &usable_area.width, &usable_area.height); const struct wlr_box full_area = usable_area; - arrange_surface(output, &full_area, &usable_area, output->layers.shell_background); - arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom); - arrange_surface(output, &full_area, &usable_area, output->layers.shell_top); - arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay); + arrange_surface(output, &full_area, &usable_area, output->layers.shell_background, true); + arrange_surface(output, &full_area, &usable_area, output->layers.shell_background, false); + arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom, true); + arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom, false); + arrange_surface(output, &full_area, &usable_area, output->layers.shell_top, true); + arrange_surface(output, &full_area, &usable_area, output->layers.shell_top, false); + arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay, true); + arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay, false); if (!wlr_box_equal(&usable_area, &output->usable_area)) { sway_log(SWAY_DEBUG, "Usable area changed, rearranging output"); From 65779cc6edaa4988e23964abaa5a453549b7fe63 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 17 Oct 2024 10:10:02 -0400 Subject: [PATCH 70/71] layer_shell: Restore sway 1.9 ordering (cherry picked from commit 8363699f145fca844772643ceedcdaa7c6b90982) --- sway/desktop/layer_shell.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 62c6a5118..333c09b49 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -82,14 +82,15 @@ void arrange_layers(struct sway_output *output) { &usable_area.width, &usable_area.height); const struct wlr_box full_area = usable_area; - arrange_surface(output, &full_area, &usable_area, output->layers.shell_background, true); - arrange_surface(output, &full_area, &usable_area, output->layers.shell_background, false); - arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom, true); - arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom, false); - arrange_surface(output, &full_area, &usable_area, output->layers.shell_top, true); - arrange_surface(output, &full_area, &usable_area, output->layers.shell_top, false); arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay, true); + arrange_surface(output, &full_area, &usable_area, output->layers.shell_top, true); + arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom, true); + arrange_surface(output, &full_area, &usable_area, output->layers.shell_background, true); + arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay, false); + arrange_surface(output, &full_area, &usable_area, output->layers.shell_top, false); + arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom, false); + arrange_surface(output, &full_area, &usable_area, output->layers.shell_background, false); if (!wlr_box_equal(&usable_area, &output->usable_area)) { sway_log(SWAY_DEBUG, "Usable area changed, rearranging output"); From 8c4cec92dac354b92fb4c585958c3b88e8f737e2 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 20 Oct 2024 22:13:37 +0200 Subject: [PATCH 71/71] build: bump version to 1.10-rc4 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 61981f45a..d41ed1301 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'sway', 'c', - version: '1.10-rc3', + version: '1.10-rc4', license: 'MIT', meson_version: '>=0.60.0', default_options: [