From 4e6d7612ffbd8e29713ae063937c8460e091bb75 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 27 Feb 2024 15:04:31 +0100 Subject: [PATCH 1/9] 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 ef1a26b8..7faacdcc 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 27a73f8a..47ab902e 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 684b1dbd..cb8bdbf9 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 2/9] 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 47ab902e..7c417891 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 cb8bdbf9..2a0dc1e7 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 3/9] 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 30595f54..d546d488 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 55779771..1b2332e9 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 4/9] 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 600423bc..b8f2d32d 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 5/9] 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 2a0dc1e7..94d0fae2 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 6/9] 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 b2eb2c36..c71851f6 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 94d0fae2..51bde794 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 7/9] 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 028cb7ab..727b4028 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 8/9] 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 727b4028..7d088d5d 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 9/9] 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 145edd4b..45c75199 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 475753d8..428f9679 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 089e1e71..248ca34e 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 f2486893..0c5672bc 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 51bde794..d159dc9b 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,