From fd9ab9ee0659d5b4c2bd148e25b8bc6378f604d6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 5 Mar 2024 08:44:04 +0100 Subject: [PATCH 01/25] config: error out on keysym translation XKB state failure If we can't create the XKB keymap used for keysym translation, gracefully error out instead of crashing. This can happen if the XKB_DEFAULT_LAYOUT is set to an invalid value, for instance. Closes: https://github.com/swaywm/sway/issues/7789 --- sway/config.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/sway/config.c b/sway/config.c index 568c8b534..d46b81ee5 100644 --- a/sway/config.c +++ b/sway/config.c @@ -43,13 +43,20 @@ static struct xkb_state *keysym_translation_state_create( context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); - xkb_context_unref(context); + if (xkb_keymap == NULL) { + sway_log(SWAY_ERROR, "Failed to compile keysym translation XKB keymap"); + return NULL; + } + return xkb_state_new(xkb_keymap); } static void keysym_translation_state_destroy( struct xkb_state *state) { + if (state == NULL) { + return; + } xkb_keymap_unref(xkb_state_get_keymap(state)); xkb_state_unref(state); } @@ -339,6 +346,9 @@ static void config_defaults(struct sway_config *config) { struct xkb_rule_names rules = {0}; config->keysym_translation_state = keysym_translation_state_create(rules); + if (config->keysym_translation_state == NULL) { + goto cleanup; + } return; cleanup: @@ -987,6 +997,11 @@ void translate_keysyms(struct input_config *input_config) { input_config_fill_rule_names(input_config, &rules); config->keysym_translation_state = keysym_translation_state_create(rules); + if (config->keysym_translation_state == NULL) { + sway_log(SWAY_ERROR, "Failed to create keysym translation XKB state " + "for device '%s'", input_config->identifier); + return; + } for (int i = 0; i < config->modes->length; ++i) { struct sway_mode *mode = config->modes->items[i]; From 59f629238309e230b0e353e73d4f37a7de7fe820 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 5 Mar 2024 08:47:21 +0100 Subject: [PATCH 02/25] config: add fallback without env vars for keysym translation XKB keymap --- sway/config.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sway/config.c b/sway/config.c index d46b81ee5..72fc41e78 100644 --- a/sway/config.c +++ b/sway/config.c @@ -37,8 +37,8 @@ struct sway_config *config = NULL; static struct xkb_state *keysym_translation_state_create( - struct xkb_rule_names rules) { - struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_SECURE_GETENV); + struct xkb_rule_names rules, uint32_t context_flags) { + struct xkb_context *context = xkb_context_new(context_flags | XKB_CONTEXT_NO_SECURE_GETENV); struct xkb_keymap *xkb_keymap = xkb_keymap_new_from_names( context, &rules, @@ -344,8 +344,11 @@ static void config_defaults(struct sway_config *config) { // The keysym to keycode translation struct xkb_rule_names rules = {0}; - config->keysym_translation_state = - keysym_translation_state_create(rules); + config->keysym_translation_state = keysym_translation_state_create(rules, 0); + if (config->keysym_translation_state == NULL) { + config->keysym_translation_state = keysym_translation_state_create(rules, + XKB_CONTEXT_NO_ENVIRONMENT_NAMES); + } if (config->keysym_translation_state == NULL) { goto cleanup; } @@ -995,8 +998,7 @@ void translate_keysyms(struct input_config *input_config) { struct xkb_rule_names rules = {0}; input_config_fill_rule_names(input_config, &rules); - config->keysym_translation_state = - keysym_translation_state_create(rules); + config->keysym_translation_state = keysym_translation_state_create(rules, 0); if (config->keysym_translation_state == NULL) { sway_log(SWAY_ERROR, "Failed to create keysym translation XKB state " "for device '%s'", input_config->identifier); From f2a0e81b2438853e12a2b8fe9bddde154852d85d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 7 Mar 2024 12:16:11 +0100 Subject: [PATCH 03/25] Fetch input device vendor/product from libinput References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4582 --- sway/input/input-manager.c | 11 +++++++++-- sway/ipc-json.c | 8 ++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 056cc3ea8..089e1e718 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -65,8 +65,15 @@ struct sway_seat *input_manager_sway_seat_from_wlr_seat(struct wlr_seat *wlr_sea } char *input_device_get_identifier(struct wlr_input_device *device) { - int vendor = device->vendor; - int product = device->product; + int vendor = 0, product = 0; +#if WLR_HAS_LIBINPUT_BACKEND + if (wlr_input_device_is_libinput(device)) { + struct libinput_device *libinput_dev = wlr_libinput_get_device_handle(device); + vendor = libinput_device_get_id_vendor(libinput_dev); + product = libinput_device_get_id_product(libinput_dev); + } +#endif + char *name = strdup(device->name ? device->name : ""); strip_whitespace(name); diff --git a/sway/ipc-json.c b/sway/ipc-json.c index dfbb7a6ec..81ca34831 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -1097,10 +1097,6 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) { json_object_new_string(device->identifier)); json_object_object_add(object, "name", json_object_new_string(device->wlr_device->name)); - json_object_object_add(object, "vendor", - json_object_new_int(device->wlr_device->vendor)); - json_object_object_add(object, "product", - json_object_new_int(device->wlr_device->product)); json_object_object_add(object, "type", json_object_new_string( input_device_get_type(device))); @@ -1154,6 +1150,10 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) { libinput_dev = wlr_libinput_get_device_handle(device->wlr_device); json_object_object_add(object, "libinput", describe_libinput_device(libinput_dev)); + json_object_object_add(object, "vendor", + json_object_new_int(libinput_device_get_id_vendor(libinput_dev))); + json_object_object_add(object, "product", + json_object_new_int(libinput_device_get_id_product(libinput_dev))); } #endif From 4e6d7612ffbd8e29713ae063937c8460e091bb75 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 27 Feb 2024 15:04:31 +0100 Subject: [PATCH 04/25] xdg-shell: implement popup repositioning --- include/sway/tree/view.h | 1 + sway/desktop/xdg_shell.c | 8 ++++++++ sway/server.c | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index ef1a26b8c..7faacdcc2 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -192,6 +192,7 @@ struct sway_xdg_popup { struct wl_listener surface_commit; struct wl_listener new_popup; + struct wl_listener reposition; struct wl_listener destroy; }; diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 27a73f8a0..47ab902e5 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -35,6 +35,7 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&popup->new_popup.link); wl_list_remove(&popup->destroy.link); wl_list_remove(&popup->surface_commit.link); + wl_list_remove(&popup->reposition.link); wlr_scene_node_destroy(&popup->scene_tree->node); free(popup); } @@ -70,6 +71,11 @@ static void popup_handle_surface_commit(struct wl_listener *listener, void *data } } +static void popup_handle_reposition(struct wl_listener *listener, void *data) { + struct sway_xdg_popup *popup = wl_container_of(listener, popup, reposition); + popup_unconstrain(popup); +} + static struct sway_xdg_popup *popup_create(struct wlr_xdg_popup *wlr_popup, struct sway_view *view, struct wlr_scene_tree *parent) { struct wlr_xdg_surface *xdg_surface = wlr_popup->base; @@ -116,6 +122,8 @@ static struct sway_xdg_popup *popup_create(struct wlr_xdg_popup *wlr_popup, popup->surface_commit.notify = popup_handle_surface_commit; wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup); popup->new_popup.notify = popup_handle_new_popup; + wl_signal_add(&wlr_popup->events.reposition, &popup->reposition); + popup->reposition.notify = popup_handle_reposition; wl_signal_add(&wlr_popup->events.destroy, &popup->destroy); popup->destroy.notify = popup_handle_destroy; diff --git a/sway/server.c b/sway/server.c index 684b1dbde..cb8bdbf94 100644 --- a/sway/server.c +++ b/sway/server.c @@ -65,7 +65,7 @@ #include #endif -#define SWAY_XDG_SHELL_VERSION 2 +#define SWAY_XDG_SHELL_VERSION 3 #define SWAY_LAYER_SHELL_VERSION 4 #define SWAY_FOREIGN_TOPLEVEL_LIST_VERSION 1 From 3ef5abd405a6fd32aeeffb2f48a6cadd9fc14574 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 27 Feb 2024 15:10:09 +0100 Subject: [PATCH 05/25] xdg-shell: send WM capabilities --- sway/desktop/xdg_shell.c | 4 ++++ sway/server.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 47ab902e5..7c4178910 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -289,6 +289,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { } // XXX: https://github.com/swaywm/sway/issues/2176 wlr_xdg_surface_schedule_configure(xdg_surface); + // TODO: wlr_xdg_toplevel_set_bounds() return; } @@ -574,4 +575,7 @@ void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data) { wlr_scene_xdg_surface_create(xdg_shell_view->view.content_tree, xdg_toplevel->base); xdg_toplevel->base->data = xdg_shell_view; + + wlr_xdg_toplevel_set_wm_capabilities(xdg_toplevel, + XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); } diff --git a/sway/server.c b/sway/server.c index cb8bdbf94..2a0dc1e72 100644 --- a/sway/server.c +++ b/sway/server.c @@ -65,7 +65,7 @@ #include #endif -#define SWAY_XDG_SHELL_VERSION 3 +#define SWAY_XDG_SHELL_VERSION 5 #define SWAY_LAYER_SHELL_VERSION 4 #define SWAY_FOREIGN_TOPLEVEL_LIST_VERSION 1 From 23389ebd1f301403e4b2331855a224dff89e1ad1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 8 Mar 2024 12:35:10 +0100 Subject: [PATCH 06/25] config/output: drop enabling flag This was useful when wlroots backends were updating the current mode on their own. This is no longer the case. --- include/sway/output.h | 2 +- sway/config/output.c | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/include/sway/output.h b/include/sway/output.h index 30595f545..d546d4884 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -50,7 +50,7 @@ struct sway_output { enum wl_output_subpixel detected_subpixel; enum scale_filter_mode scale_filter; - bool enabling, enabled; + bool enabled; list_t *workspaces; struct sway_output_state current; diff --git a/sway/config/output.c b/sway/config/output.c index 557797710..1b2332e95 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -510,9 +510,6 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { struct wlr_output *wlr_output = output->wlr_output; - // Flag to prevent the output mode event handler from calling us - output->enabling = (!oc || oc->enabled); - struct wlr_output_state pending = {0}; queue_output_config(oc, output, &pending); @@ -522,12 +519,9 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { // Leave the output disabled for now and try again when the output gets // the mode we asked for. sway_log(SWAY_ERROR, "Failed to commit output %s", wlr_output->name); - output->enabling = false; return false; } - output->enabling = false; - if (oc && !oc->enabled) { sway_log(SWAY_DEBUG, "Disabling output %s", oc->name); if (output->enabled) { From 2e951163c5a5f24fe9cf7ee348e56b09719a99a9 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 7 Mar 2024 18:03:40 -0500 Subject: [PATCH 07/25] Force bilinear scaling when scaling down --- sway/desktop/output.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 600423bcf..b8f2d32d2 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -183,7 +183,15 @@ static void send_frame_done_iterator(struct wlr_scene_buffer *buffer, } } -static enum wlr_scale_filter_mode get_scale_filter(struct sway_output *output) { +static enum wlr_scale_filter_mode get_scale_filter(struct sway_output *output, + struct wlr_scene_buffer *buffer) { + // if we are scaling down, we should always choose linear + if (buffer->dst_width > 0 && buffer->dst_height > 0 && ( + buffer->dst_width < buffer->buffer_width || + buffer->dst_height < buffer->buffer_height)) { + return WLR_SCALE_FILTER_BILINEAR; + } + switch (output->scale_filter) { case SCALE_FILTER_LINEAR: return WLR_SCALE_FILTER_BILINEAR; @@ -212,7 +220,7 @@ static void output_configure_scene(struct sway_output *output, // 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 // we're configuring - buffer->filter_mode = get_scale_filter(output); + buffer->filter_mode = get_scale_filter(output, buffer); wlr_scene_buffer_set_opacity(buffer, opacity); } else if (node->type == WLR_SCENE_NODE_TREE) { From 2b08e79061db583d0ffe46114c48f958a0d3e6ed Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 4 Mar 2024 13:51:27 +0100 Subject: [PATCH 08/25] server: fix wlr_seat use-after-free on exit Same as [1]. I originally tried to properly handle seat destruction, but that turned out to be a can of worms [2]. [1]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4590 [2]: https://github.com/swaywm/sway/pull/8034 --- sway/server.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sway/server.c b/sway/server.c index 2a0dc1e72..94d0fae29 100644 --- a/sway/server.c +++ b/sway/server.c @@ -399,6 +399,7 @@ void server_fini(struct sway_server *server) { wlr_xwayland_destroy(server->xwayland.wlr_xwayland); #endif wl_display_destroy_clients(server->wl_display); + wlr_backend_destroy(server->backend); wl_display_destroy(server->wl_display); list_free(server->dirty_nodes); } From 3bc75221bc0074b2e96e14cb88140c95406472c3 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 14 Mar 2024 13:54:08 +0100 Subject: [PATCH 09/25] Re-create renderer when lost --- include/sway/server.h | 1 + sway/server.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/include/sway/server.h b/include/sway/server.h index b2eb2c365..c71851f68 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -46,6 +46,7 @@ struct sway_server { struct wl_listener new_output; struct wl_listener output_layout_change; + struct wl_listener renderer_lost; struct wlr_idle_notifier_v1 *idle_notifier_v1; struct sway_idle_inhibit_manager_v1 idle_inhibit_manager_v1; diff --git a/sway/server.c b/sway/server.c index 94d0fae29..51bde794f 100644 --- a/sway/server.c +++ b/sway/server.c @@ -172,6 +172,45 @@ static void detect_proprietary(struct wlr_backend *backend, void *data) { drmFreeVersion(version); } +static void handle_renderer_lost(struct wl_listener *listener, void *data) { + struct sway_server *server = wl_container_of(listener, server, renderer_lost); + + sway_log(SWAY_INFO, "Re-creating renderer after GPU reset"); + + struct wlr_renderer *renderer = wlr_renderer_autocreate(server->backend); + if (renderer == NULL) { + sway_log(SWAY_ERROR, "Unable to create renderer"); + return; + } + + struct wlr_allocator *allocator = + wlr_allocator_autocreate(server->backend, renderer); + if (allocator == NULL) { + sway_log(SWAY_ERROR, "Unable to create allocator"); + wlr_renderer_destroy(renderer); + return; + } + + struct wlr_renderer *old_renderer = server->renderer; + struct wlr_allocator *old_allocator = server->allocator; + server->renderer = renderer; + server->allocator = allocator; + + wl_list_remove(&server->renderer_lost.link); + wl_signal_add(&server->renderer->events.lost, &server->renderer_lost); + + wlr_compositor_set_renderer(server->compositor, renderer); + + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + wlr_output_init_render(output->wlr_output, + server->allocator, server->renderer); + } + + wlr_allocator_destroy(old_allocator); + wlr_renderer_destroy(old_renderer); +} + bool server_init(struct sway_server *server) { sway_log(SWAY_DEBUG, "Initializing Wayland server"); server->wl_display = wl_display_create(); @@ -195,6 +234,9 @@ bool server_init(struct sway_server *server) { return false; } + server->renderer_lost.notify = handle_renderer_lost; + wl_signal_add(&server->renderer->events.lost, &server->renderer_lost); + wlr_renderer_init_wl_shm(server->renderer, server->wl_display); if (wlr_renderer_get_dmabuf_texture_formats(server->renderer) != NULL) { From 9139da6149ad4e5bff6cc67d4f2abc2126a66c25 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 11 Mar 2024 19:20:17 +0100 Subject: [PATCH 10/25] man: drop fractional scale warning With the fractional-scale protocol, clients can render without being downscaled. --- sway/sway-output.5.scd | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd index 028cb7abc..727b40282 100644 --- a/sway/sway-output.5.scd +++ b/sway/sway-output.5.scd @@ -72,13 +72,10 @@ must be separated by one space. For example: *output* scale Scales the specified output by the specified scale _factor_. An integer is - recommended, but fractional values are also supported. If a fractional - value are specified, be warned that it is not possible to faithfully - represent the contents of your windows - they will be rendered at the next - highest integer scale factor and downscaled. You may be better served by - setting an integer scale factor and adjusting the font size of your - applications to taste. HiDPI isn't supported with Xwayland clients (windows - will blur). + recommended, but fractional values are also supported. You may be better + served by setting an integer scale factor and adjusting the font size of + your applications to taste. HiDPI isn't supported with Xwayland clients + (windows will blur). *output* scale_filter linear|nearest|smart Indicates how to scale application buffers that are rendered at a scale From dc9f21730735a8700d972e096dc5ec58aec82a3b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 11 Mar 2024 19:22:36 +0100 Subject: [PATCH 11/25] man: document that the scale might be adjusted fractional-scale only supports representing fractions of 120. References: https://github.com/swaywm/sway/issues/8057 --- sway/sway-output.5.scd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd index 727b40282..7d088d5db 100644 --- a/sway/sway-output.5.scd +++ b/sway/sway-output.5.scd @@ -75,7 +75,8 @@ must be separated by one space. For example: recommended, but fractional values are also supported. You may be better served by setting an integer scale factor and adjusting the font size of your applications to taste. HiDPI isn't supported with Xwayland clients - (windows will blur). + (windows will blur). A fractional scale may be slightly adjusted to match + requirements of the protocol. *output* scale_filter linear|nearest|smart Indicates how to scale application buffers that are rendered at a scale From 5a7477cb8f568ce4aeb852215ad40899f18f3d91 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Sat, 8 Feb 2020 18:17:42 +0000 Subject: [PATCH 12/25] Implement transient seat management --- include/sway/input/input-manager.h | 3 +++ include/sway/input/seat.h | 1 + sway/input/input-manager.c | 25 +++++++++++++++++++++++++ sway/input/seat.c | 11 ++++++++++- sway/server.c | 3 ++- 5 files changed, 41 insertions(+), 2 deletions(-) diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index 145edd4b6..45c751994 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "sway/server.h" #include "sway/config.h" #include "list.h" @@ -24,6 +25,7 @@ struct sway_input_manager { struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard; struct wlr_virtual_pointer_manager_v1 *virtual_pointer; struct wlr_pointer_gestures_v1 *pointer_gestures; + struct wlr_transient_seat_manager_v1 *transient_seat_manager; struct wl_listener new_input; struct wl_listener inhibit_activate; @@ -31,6 +33,7 @@ struct sway_input_manager { struct wl_listener keyboard_shortcuts_inhibit_new_inhibitor; struct wl_listener virtual_keyboard_new; struct wl_listener virtual_pointer_new; + struct wl_listener transient_seat_create; }; struct sway_input_manager *input_manager_create(struct sway_server *server); diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 475753d8a..428f96796 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -124,6 +124,7 @@ struct sway_seat { struct wl_listener start_drag; struct wl_listener request_set_selection; struct wl_listener request_set_primary_selection; + struct wl_listener destroy; struct wl_list devices; // sway_seat_device::link struct wl_list keyboard_groups; // sway_keyboard_group::link diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 089e1e718..248ca34ee 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -2,7 +2,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -431,6 +433,20 @@ void handle_virtual_pointer(struct wl_listener *listener, void *data) { } } +static void handle_transient_seat_manager_create_seat( + struct wl_listener *listener, void *data) { + struct wlr_transient_seat_v1 *transient_seat = data; + static uint64_t i; + char name[256]; + snprintf(name, sizeof(name), "transient-%"PRIx64, i++); + struct sway_seat *seat = seat_create(name); + if (seat && seat->wlr_seat) { + wlr_transient_seat_v1_ready(transient_seat, seat->wlr_seat); + } else { + wlr_transient_seat_v1_deny(transient_seat); + } +} + struct sway_input_manager *input_manager_create(struct sway_server *server) { struct sway_input_manager *input = calloc(1, sizeof(struct sway_input_manager)); @@ -466,6 +482,15 @@ struct sway_input_manager *input_manager_create(struct sway_server *server) { input->pointer_gestures = wlr_pointer_gestures_v1_create(server->wl_display); + input->transient_seat_manager = + wlr_transient_seat_manager_v1_create(server->wl_display); + assert(input->transient_seat_manager); + + input->transient_seat_create.notify = + handle_transient_seat_manager_create_seat; + wl_signal_add(&input->transient_seat_manager->events.create_seat, + &input->transient_seat_create); + return input; } diff --git a/sway/input/seat.c b/sway/input/seat.c index f24868935..0c5672bca 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -67,6 +67,12 @@ static void seat_node_destroy(struct sway_seat_node *seat_node) { } void seat_destroy(struct sway_seat *seat) { + wlr_seat_destroy(seat->wlr_seat); +} + +static void handle_seat_destroy(struct wl_listener *listener, void *data) { + struct sway_seat *seat = wl_container_of(listener, seat, destroy); + if (seat == config->handler_context.seat) { config->handler_context.seat = input_manager_get_default_seat(); } @@ -87,7 +93,7 @@ void seat_destroy(struct sway_seat *seat) { wl_list_remove(&seat->request_set_selection.link); wl_list_remove(&seat->request_set_primary_selection.link); wl_list_remove(&seat->link); - wlr_seat_destroy(seat->wlr_seat); + wl_list_remove(&seat->destroy.link); for (int i = 0; i < seat->deferred_bindings->length; i++) { free_sway_binding(seat->deferred_bindings->items[i]); } @@ -534,6 +540,9 @@ struct sway_seat *seat_create(const char *seat_name) { return NULL; } + seat->destroy.notify = handle_seat_destroy; + wl_signal_add(&seat->wlr_seat->events.destroy, &seat->destroy); + seat->idle_inhibit_sources = seat->idle_wake_sources = IDLE_SOURCE_KEYBOARD | IDLE_SOURCE_POINTER | diff --git a/sway/server.c b/sway/server.c index 51bde794f..d159dc9bd 100644 --- a/sway/server.c +++ b/sway/server.c @@ -112,7 +112,8 @@ static bool is_privileged(const struct wl_global *global) { global == server.session_lock.manager->global || global == server.input->keyboard_shortcuts_inhibit->global || global == server.input->virtual_keyboard->global || - global == server.input->virtual_pointer->global; + global == server.input->virtual_pointer->global || + global == server.input->transient_seat_manager->global; } static bool filter_global(const struct wl_client *client, From 125c74338ac8bf8c15323a49730352b82d6d51bd Mon Sep 17 00:00:00 2001 From: Ferdinand Bachmann Date: Sun, 24 Mar 2024 12:20:05 +0100 Subject: [PATCH 13/25] man: document supported modifier names --- sway/sway.5.scd | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 7e58b5286..f73db3ba3 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -400,6 +400,12 @@ runtime. only be available for that group. By default, if you overwrite a binding, swaynag will give you a warning. To silence this, use the _--no-warn_ flag. + For specifying modifier keys, you can use the XKB modifier names _Shift_, + _Lock_ (for Caps Lock), _Control_, _Mod1_ (for Alt), _Mod2_ (for Num Lock), + _Mod3_ (for XKB modifier Mod3), _Mod4_ (for the Logo key), and _Mod5_ (for + AltGr). In addition, you can use the aliases _Ctrl_ (for Control) and _Alt_ + (for Alt). + Unless the flag _--locked_ is set, the command will not be run when a screen locking program is active. If there is a matching binding with and without _--locked_, the one with will be preferred when locked and the From e2f3ebad8c1943800dd5f017d547d9d98bfb8bb1 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 16 Mar 2024 00:37:06 +0100 Subject: [PATCH 14/25] config/output: Split apply_output_config Applying an output config has two stages: Atomic application of wlr_output_state, and applicaiton of non-atomic state like output layout. Split the latter out into finalize_output_config for use in a later commit. --- sway/config/output.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/sway/config/output.c b/sway/config/output.c index 1b2332e95..fd1d6e3c8 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -503,25 +503,12 @@ static void queue_output_config(struct output_config *oc, } } -bool apply_output_config(struct output_config *oc, struct sway_output *output) { +static bool finalize_output_config(struct output_config *oc, struct sway_output *output) { if (output == root->fallback_output) { return false; } struct wlr_output *wlr_output = output->wlr_output; - - struct wlr_output_state pending = {0}; - queue_output_config(oc, output, &pending); - - sway_log(SWAY_DEBUG, "Committing output %s", wlr_output->name); - if (!wlr_output_commit_state(wlr_output, &pending)) { - // Failed to commit output changes, maybe the output is missing a CRTC. - // Leave the output disabled for now and try again when the output gets - // the mode we asked for. - sway_log(SWAY_ERROR, "Failed to commit output %s", wlr_output->name); - return false; - } - if (oc && !oc->enabled) { sway_log(SWAY_DEBUG, "Disabling output %s", oc->name); if (output->enabled) { @@ -577,6 +564,30 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { output->max_render_time = oc->max_render_time; } + return true; +} + +bool apply_output_config(struct output_config *oc, struct sway_output *output) { + if (output == root->fallback_output) { + return false; + } + + struct wlr_output_state pending = {0}; + queue_output_config(oc, output, &pending); + + sway_log(SWAY_DEBUG, "Committing output %s", output->wlr_output->name); + if (!wlr_output_commit_state(output->wlr_output, &pending)) { + // Failed to commit output changes, maybe the output is missing a CRTC. + // Leave the output disabled for now and try again when the output gets + // the mode we asked for. + sway_log(SWAY_ERROR, "Failed to commit output %s", output->wlr_output->name); + return false; + } + + if (!finalize_output_config(oc, output)) { + return false; + } + // Reconfigure all devices, since input config may have been applied before // this output came online, and some config items (like map_to_output) are // dependent on an output being present. From 3e03eb3a017d144137dbe6591891f3a51a61dea0 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 16 Mar 2024 00:48:56 +0100 Subject: [PATCH 15/25] config/output: Introduce apply_output_configs Introduce apply_output_configs, which applies the specified matched output configs as a single backend commit. Reimplement apply_output_config_to_outputs using apply_output_configs. --- include/sway/config.h | 11 ++++ sway/config/output.c | 148 +++++++++++++++++++++++++++++++++++------- 2 files changed, 135 insertions(+), 24 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index f9da19675..d23fe578a 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -291,6 +291,14 @@ 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 */ @@ -684,6 +692,9 @@ void merge_output_config(struct output_config *dst, struct output_config *src); bool apply_output_config(struct output_config *oc, struct sway_output *output); +bool apply_output_configs(struct matched_output_config *configs, + size_t configs_len, bool test_only); + bool test_output_config(struct output_config *oc, struct sway_output *output); struct output_config *store_output_config(struct output_config *oc); diff --git a/sway/config/output.c b/sway/config/output.c index fd1d6e3c8..de9515e21 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "sway/config.h" #include "sway/input/cursor.h" #include "sway/output.h" @@ -716,39 +717,138 @@ struct output_config *find_output_config(struct sway_output *output) { return get_output_config(id, output); } -void apply_output_config_to_outputs(struct output_config *oc) { - // Try to find the output container and apply configuration now. If - // this is during startup then there will be no container and config - // will be applied during normal "new output" event from wlroots. - bool wildcard = strcmp(oc->name, "*") == 0; - struct sway_output *sway_output, *tmp; - wl_list_for_each_safe(sway_output, tmp, &root->all_outputs, link) { - if (output_match_name_or_id(sway_output, oc->name)) { - char id[128]; - output_get_identifier(id, sizeof(id), sway_output); - struct output_config *current = get_output_config(id, sway_output); - if (!current) { - // No stored output config matched, apply oc directly - sway_log(SWAY_DEBUG, "Applying oc directly"); - current = new_output_config(oc->name); - merge_output_config(current, oc); - } - apply_output_config(current, sway_output); - free_output_config(current); +bool apply_output_configs(struct matched_output_config *configs, + size_t configs_len, bool test_only) { + struct wlr_backend_output_state *states = calloc(configs_len, sizeof(*states)); + if (!states) { + return false; + } - if (!wildcard) { - // Stop looking if the output config isn't applicable to all - // outputs - break; - } + sway_log(SWAY_DEBUG, "Committing %zd outputs", configs_len); + for (size_t idx = 0; idx < configs_len; idx++) { + struct matched_output_config *cfg = &configs[idx]; + struct wlr_backend_output_state *backend_state = &states[idx]; + + 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); + } + + struct wlr_output_swapchain_manager swapchain_mgr; + wlr_output_swapchain_manager_init(&swapchain_mgr, server.backend); + + bool ok = wlr_output_swapchain_manager_prepare(&swapchain_mgr, states, configs_len); + if (!ok) { + sway_log(SWAY_ERROR, "Swapchain prepare failed"); + goto out; + } + + if (test_only) { + // The swapchain manager already did a test for us + goto out; + } + + for (size_t idx = 0; idx < configs_len; idx++) { + struct matched_output_config *cfg = &configs[idx]; + struct wlr_backend_output_state *backend_state = &states[idx]; + + struct wlr_scene_output_state_options opts = { + .swapchain = wlr_output_swapchain_manager_get_swapchain( + &swapchain_mgr, backend_state->output), + }; + struct wlr_scene_output *scene_output = cfg->output->scene_output; + struct wlr_output_state *state = &backend_state->base; + if (!wlr_scene_output_build_state(scene_output, state, &opts)) { + sway_log(SWAY_ERROR, "Building output state for '%s' failed", + backend_state->output->name); + goto out; } } + ok = wlr_backend_commit(server.backend, states, configs_len); + if (!ok) { + sway_log(SWAY_ERROR, "Backend commit failed"); + goto out; + } + + sway_log(SWAY_DEBUG, "Commit of %zd outputs succeeded", configs_len); + + wlr_output_swapchain_manager_apply(&swapchain_mgr); + + for (size_t idx = 0; idx < configs_len; idx++) { + struct matched_output_config *cfg = &configs[idx]; + sway_log(SWAY_DEBUG, "Finalizing config for %s", + cfg->output->wlr_output->name); + finalize_output_config(cfg->config, cfg->output); + } + +out: + wlr_output_swapchain_manager_finish(&swapchain_mgr); + for (size_t idx = 0; idx < configs_len; idx++) { + struct wlr_backend_output_state *backend_state = &states[idx]; + wlr_output_state_finish(&backend_state->base); + } + free(states); + + // Reconfigure all devices, since input config may have been applied before + // this output came online, and some config items (like map_to_output) are + // dependent on an output being present. + input_manager_configure_all_input_mappings(); + // Reconfigure the cursor images, since the scale may have changed. + input_manager_configure_xcursor(); + struct sway_seat *seat; wl_list_for_each(seat, &server.input->seats, link) { wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); cursor_rebase(seat->cursor); } + + return ok; +} + +void apply_output_config_to_outputs(struct output_config *oc) { + size_t configs_len = wl_list_length(&root->all_outputs); + struct matched_output_config *configs = calloc(configs_len, sizeof(*configs)); + if (!configs) { + return; + } + + // Try to find the output container and apply configuration now. If + // this is during startup then there will be no container and config + // will be applied during normal "new output" event from wlroots. + 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 *config = &configs[config_idx++]; + config->output = sway_output; + config->config = find_output_config(sway_output); + + if (!output_match_name_or_id(sway_output, oc->name)) { + continue; + } + + if (!config->config && oc) { + // No stored output config matched, apply oc directly + sway_log(SWAY_DEBUG, "Applying oc directly"); + config->config = new_output_config(oc->name); + merge_output_config(config->config, oc); + } + } + + apply_output_configs(configs, configs_len, false); + for (size_t idx = 0; idx < configs_len; idx++) { + struct matched_output_config *cfg = &configs[idx]; + free_output_config(cfg->config); + } + free(configs); } void reset_outputs(void) { From 923f642b704022442cc3245a2fa13278341c14e0 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 16 Mar 2024 00:57:11 +0100 Subject: [PATCH 16/25] output/config: Add apply_all_output_configs Apply all output configs as they are. This differs from apply_output_config_to_outputs, which tries to apply a specific output config. --- include/sway/config.h | 2 ++ sway/config/output.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/include/sway/config.h b/include/sway/config.h index d23fe578a..eff7cfbbd 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -695,6 +695,8 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output); bool apply_output_configs(struct matched_output_config *configs, size_t configs_len, bool test_only); +void apply_all_output_configs(void); + bool test_output_config(struct output_config *oc, struct sway_output *output); struct output_config *store_output_config(struct output_config *oc); diff --git a/sway/config/output.c b/sway/config/output.c index de9515e21..5bf5bed58 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -809,6 +809,34 @@ out: return ok; } +void apply_all_output_configs(void) { + size_t configs_len = wl_list_length(&root->all_outputs); + struct matched_output_config *configs = calloc(configs_len, sizeof(*configs)); + if (!configs) { + return; + } + + 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 *config = &configs[config_idx++]; + config->output = sway_output; + config->config = find_output_config(sway_output); + } + + apply_output_configs(configs, configs_len, false); + for (size_t idx = 0; idx < configs_len; idx++) { + struct matched_output_config *cfg = &configs[idx]; + free_output_config(cfg->config); + } + free(configs); +} + void apply_output_config_to_outputs(struct output_config *oc) { size_t configs_len = wl_list_length(&root->all_outputs); struct matched_output_config *configs = calloc(configs_len, sizeof(*configs)); From 98be797356876153e74405dbef36e3e71875ca2e Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 16 Mar 2024 01:00:46 +0100 Subject: [PATCH 17/25] Use apply_all_output_configs to light up outputs This allows us to test and if necessary degrade the entire backend configuration to light everything up. --- sway/commands/output.c | 4 ++-- sway/desktop/output.c | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/sway/commands/output.c b/sway/commands/output.c index 462dffd23..5e5d31b3e 100644 --- a/sway/commands/output.c +++ b/sway/commands/output.c @@ -103,13 +103,13 @@ struct cmd_results *cmd_output(int argc, char **argv) { bool background = output->background; - output = store_output_config(output); + 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_output_config_to_outputs(output); + apply_all_output_configs(); if (background) { if (!spawn_swaybg()) { return cmd_results_new(CMD_FAILURE, diff --git a/sway/desktop/output.c b/sway/desktop/output.c index b8f2d32d2..b2647219c 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -521,9 +521,7 @@ void handle_new_output(struct wl_listener *listener, void *data) { sway_session_lock_add_output(server->session_lock.lock, output); } - struct output_config *oc = find_output_config(output); - apply_output_config(oc, output); - free_output_config(oc); + apply_all_output_configs(); transaction_commit_dirty(); @@ -652,6 +650,6 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener, oc->power = 1; break; } - oc = store_output_config(oc); - apply_output_config(oc, output); + store_output_config(oc); + apply_all_output_configs(); } From 3b419020a32f4f8385e49d2137ceb4d9b8262176 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 16 Mar 2024 01:01:56 +0100 Subject: [PATCH 18/25] desktop/output: Use apply_output_configs for output mgmt --- sway/desktop/output.c | 113 ++++++++++++++++++++++++++---------------- 1 file changed, 69 insertions(+), 44 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index b2647219c..bd3de3fe1 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -550,63 +550,88 @@ void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data) { wlr_output_schedule_frame(output->wlr_output); } +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); + oc->enabled = config_head->state.enabled; + if (!oc->enabled) { + return oc; + } + + if (config_head->state.mode != NULL) { + struct wlr_output_mode *mode = config_head->state.mode; + oc->width = mode->width; + oc->height = mode->height; + oc->refresh_rate = mode->refresh / 1000.f; + } else { + oc->width = config_head->state.custom_mode.width; + oc->height = config_head->state.custom_mode.height; + oc->refresh_rate = + config_head->state.custom_mode.refresh / 1000.f; + } + oc->x = config_head->state.x; + oc->y = config_head->state.y; + oc->transform = config_head->state.transform; + oc->scale = config_head->state.scale; + oc->adaptive_sync = config_head->state.adaptive_sync_enabled; + return oc; +} + static void output_manager_apply(struct sway_server *server, struct wlr_output_configuration_v1 *config, bool test_only) { - // TODO: perform atomic tests on the whole backend atomically + size_t configs_len = wl_list_length(&root->all_outputs); + struct matched_output_config *configs = calloc(configs_len, sizeof(*configs)); + if (!configs) { + return; + } - struct wlr_output_configuration_head_v1 *config_head; - // First disable outputs we need to disable - bool ok = true; - wl_list_for_each(config_head, &config->heads, link) { - struct wlr_output *wlr_output = config_head->state.output; - struct sway_output *output = wlr_output->data; - if (!output->enabled || config_head->state.enabled) { + 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 output_config *oc = new_output_config(output->wlr_output->name); - oc->enabled = false; - if (test_only) { - ok &= test_output_config(oc, output); - } else { - oc = store_output_config(oc); - ok &= apply_output_config(oc, output); + 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); } } - // Then enable outputs that need to - wl_list_for_each(config_head, &config->heads, link) { - struct wlr_output *wlr_output = config_head->state.output; - struct sway_output *output = wlr_output->data; - if (!config_head->state.enabled) { - continue; - } - struct output_config *oc = new_output_config(output->wlr_output->name); - oc->enabled = true; - if (config_head->state.mode != NULL) { - struct wlr_output_mode *mode = config_head->state.mode; - oc->width = mode->width; - oc->height = mode->height; - oc->refresh_rate = mode->refresh / 1000.f; - } else { - oc->width = config_head->state.custom_mode.width; - oc->height = config_head->state.custom_mode.height; - oc->refresh_rate = - config_head->state.custom_mode.refresh / 1000.f; - } - oc->x = config_head->state.x; - oc->y = config_head->state.y; - oc->transform = config_head->state.transform; - oc->scale = config_head->state.scale; - oc->adaptive_sync = config_head->state.adaptive_sync_enabled; + bool ok = apply_output_configs(configs, configs_len, test_only); + for (size_t idx = 0; idx < configs_len; idx++) { + struct matched_output_config *cfg = &configs[idx]; - if (test_only) { - ok &= test_output_config(oc, output); + // Only store new configs for successful non-test commits. Old configs, + // test-only and failed commits just get freed. + bool store_config = false; + 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 == sway_output->wlr_output) { + store_config = true; + break; + } + } + } + if (store_config) { + store_output_config(cfg->config); } else { - oc = store_output_config(oc); - ok &= apply_output_config(oc, output); + free_output_config(cfg->config); } } + free(configs); if (ok) { wlr_output_configuration_v1_send_succeeded(config); From 56e97b7d60e3723f79fd972061191117bf544f08 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 16 Mar 2024 01:03:37 +0100 Subject: [PATCH 19/25] config/output: Remove apply_output_config --- include/sway/config.h | 2 -- sway/config/output.c | 30 ------------------------------ 2 files changed, 32 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index eff7cfbbd..69b144461 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -690,8 +690,6 @@ struct output_config *new_output_config(const char *name); void merge_output_config(struct output_config *dst, struct output_config *src); -bool apply_output_config(struct output_config *oc, struct sway_output *output); - bool apply_output_configs(struct matched_output_config *configs, size_t configs_len, bool test_only); diff --git a/sway/config/output.c b/sway/config/output.c index 5bf5bed58..cb12683d8 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -568,36 +568,6 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output return true; } -bool apply_output_config(struct output_config *oc, struct sway_output *output) { - if (output == root->fallback_output) { - return false; - } - - struct wlr_output_state pending = {0}; - queue_output_config(oc, output, &pending); - - sway_log(SWAY_DEBUG, "Committing output %s", output->wlr_output->name); - if (!wlr_output_commit_state(output->wlr_output, &pending)) { - // Failed to commit output changes, maybe the output is missing a CRTC. - // Leave the output disabled for now and try again when the output gets - // the mode we asked for. - sway_log(SWAY_ERROR, "Failed to commit output %s", output->wlr_output->name); - return false; - } - - if (!finalize_output_config(oc, output)) { - return false; - } - - // Reconfigure all devices, since input config may have been applied before - // this output came online, and some config items (like map_to_output) are - // dependent on an output being present. - input_manager_configure_all_input_mappings(); - // Reconfigure the cursor images, since the scale may have changed. - input_manager_configure_xcursor(); - return true; -} - bool test_output_config(struct output_config *oc, struct sway_output *output) { if (output == root->fallback_output) { return false; From 9becff0ba56ac7da8b1235aa5740fb04414636a2 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 16 Mar 2024 01:11:35 +0100 Subject: [PATCH 20/25] output/config: Remove reset_outputs and co. apply_output_config_to_outputs uses the specified output config to check which outputs to apply to, and to use as backup when no config is found. If any config matches the output, the specified config will be disregarded. The only remaining user of apply_output_config_to_outputs is reset_outputs, which called apply_output_config_to_outputs with either the first stored wildcard config, or a new empty wildcard config. Providing a stored or empty wildcard config is practically the same as calling `apply_all_output_configs`. Replace uses of `reset_outputs` with `apply_all_output_configs` and remove the now unused functions. --- include/sway/config.h | 4 ---- sway/config.c | 2 +- sway/config/output.c | 53 ------------------------------------------- 3 files changed, 1 insertion(+), 58 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index 69b144461..7e67ba218 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -701,10 +701,6 @@ struct output_config *store_output_config(struct output_config *oc); struct output_config *find_output_config(struct sway_output *output); -void apply_output_config_to_outputs(struct output_config *oc); - -void reset_outputs(void); - void free_output_config(struct output_config *oc); bool spawn_swaybg(void); diff --git a/sway/config.c b/sway/config.c index 72fc41e78..f9131e0f7 100644 --- a/sway/config.c +++ b/sway/config.c @@ -532,7 +532,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) { } sway_switch_retrigger_bindings_for_all(); - reset_outputs(); + apply_all_output_configs(); spawn_swaybg(); config->reloading = false; diff --git a/sway/config/output.c b/sway/config/output.c index cb12683d8..a7c2f9b8b 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -807,59 +807,6 @@ void apply_all_output_configs(void) { free(configs); } -void apply_output_config_to_outputs(struct output_config *oc) { - size_t configs_len = wl_list_length(&root->all_outputs); - struct matched_output_config *configs = calloc(configs_len, sizeof(*configs)); - if (!configs) { - return; - } - - // Try to find the output container and apply configuration now. If - // this is during startup then there will be no container and config - // will be applied during normal "new output" event from wlroots. - 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 *config = &configs[config_idx++]; - config->output = sway_output; - config->config = find_output_config(sway_output); - - if (!output_match_name_or_id(sway_output, oc->name)) { - continue; - } - - if (!config->config && oc) { - // No stored output config matched, apply oc directly - sway_log(SWAY_DEBUG, "Applying oc directly"); - config->config = new_output_config(oc->name); - merge_output_config(config->config, oc); - } - } - - apply_output_configs(configs, configs_len, false); - for (size_t idx = 0; idx < configs_len; idx++) { - struct matched_output_config *cfg = &configs[idx]; - free_output_config(cfg->config); - } - free(configs); -} - -void reset_outputs(void) { - struct output_config *oc = NULL; - int i = list_seq_find(config->output_configs, output_name_cmp, "*"); - if (i >= 0) { - oc = config->output_configs->items[i]; - } else { - oc = store_output_config(new_output_config("*")); - } - apply_output_config_to_outputs(oc); -} - void free_output_config(struct output_config *oc) { if (!oc) { return; From c3fca26d303617614bee67ad766fd3cb95609245 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 16 Mar 2024 13:25:23 +0100 Subject: [PATCH 21/25] config/output: Make merge_output_config static --- include/sway/config.h | 2 -- sway/config/output.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index 7e67ba218..5a303d9fe 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -688,8 +688,6 @@ const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filt struct output_config *new_output_config(const char *name); -void merge_output_config(struct output_config *dst, struct output_config *src); - bool apply_output_configs(struct matched_output_config *configs, size_t configs_len, bool test_only); diff --git a/sway/config/output.c b/sway/config/output.c index a7c2f9b8b..72cbf2618 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -79,7 +79,7 @@ struct output_config *new_output_config(const char *name) { return oc; } -void merge_output_config(struct output_config *dst, struct output_config *src) { +static void merge_output_config(struct output_config *dst, struct output_config *src) { if (src->enabled != -1) { dst->enabled = src->enabled; } From 26a9a6b4792a1b2b00406ae6c20ea88325e7c7aa Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 16 Mar 2024 13:25:45 +0100 Subject: [PATCH 22/25] output/config: Remove unused test_output_config --- include/sway/config.h | 2 -- sway/config/output.c | 10 ---------- 2 files changed, 12 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index 5a303d9fe..40710199a 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -693,8 +693,6 @@ bool apply_output_configs(struct matched_output_config *configs, void apply_all_output_configs(void); -bool test_output_config(struct output_config *oc, struct sway_output *output); - struct output_config *store_output_config(struct output_config *oc); struct output_config *find_output_config(struct sway_output *output); diff --git a/sway/config/output.c b/sway/config/output.c index 72cbf2618..3f1c3126b 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -568,16 +568,6 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output return true; } -bool test_output_config(struct output_config *oc, struct sway_output *output) { - if (output == root->fallback_output) { - return false; - } - - struct wlr_output_state pending = {0}; - queue_output_config(oc, output, &pending); - return wlr_output_test_state(output->wlr_output, &pending); -} - static void default_output_config(struct output_config *oc, struct wlr_output *wlr_output) { oc->enabled = 1; From a4ef37752fd6ae9e84d60cbe4eaead07f71f9435 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 16 Mar 2024 17:55:07 +0100 Subject: [PATCH 23/25] commands/output/toggle: Use free_output_config --- sway/commands/output/toggle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/commands/output/toggle.c b/sway/commands/output/toggle.c index 6342d526b..c6b72845b 100644 --- a/sway/commands/output/toggle.c +++ b/sway/commands/output/toggle.c @@ -29,7 +29,7 @@ struct cmd_results *output_cmd_toggle(int argc, char **argv) { config->handler_context.output_config->enabled = 1; } - free(oc); + free_output_config(oc); config->handler_context.leftovers.argc = argc; config->handler_context.leftovers.argv = argv; return NULL; From 9e1465107788af2c8ce93e2a288e9d32bc09711c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 28 Mar 2024 11:45:46 +0100 Subject: [PATCH 24/25] input: pass wlr_seat_client to wlr_seat_touch_notify_cancel() References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4613 --- sway/input/seatop_down.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c index 35fd3bcb2..340e334bf 100644 --- a/sway/input/seatop_down.c +++ b/sway/input/seatop_down.c @@ -117,7 +117,11 @@ static void handle_touch_cancel(struct sway_seat *seat, } if (e->surface) { - wlr_seat_touch_notify_cancel(seat->wlr_seat, e->surface); + struct wl_client *client = wl_resource_get_client(e->surface->resource); + struct wlr_seat_client *seat_client = wlr_seat_client_for_wl_client(seat->wlr_seat, client); + if (seat_client != NULL) { + wlr_seat_touch_notify_cancel(seat->wlr_seat, seat_client); + } } if (wl_list_empty(&e->point_events)) { From dcb142bf5e390250939544075b5852ca21eaf721 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Fri, 29 Mar 2024 18:46:08 -0400 Subject: [PATCH 25/25] sway-ipc(7): Escape backslashes correctly in GET_CONFIG output Without this change, i see the following in the sway-ipc manpage: ``` 9. GET_CONFIG MESSAGE Retrieve the contents of the config that was last loaded REPLY An object with a single string property containing the contents of the config Example Reply: { "config": "set $mod Mod4nbindsym $mod+q exitn" } ``` --- sway/sway-ipc.7.scd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/sway-ipc.7.scd b/sway/sway-ipc.7.scd index c9895e52c..2f6972489 100644 --- a/sway/sway-ipc.7.scd +++ b/sway/sway-ipc.7.scd @@ -1046,7 +1046,7 @@ An object with a single string property containing the contents of the config *Example Reply:* ``` { - "config": "set $mod Mod4\nbindsym $mod+q exit\n" + "config": "set $mod Mod4\\nbindsym $mod+q exit\\n" } ```