From 0c95e88a96caf1760385e7b8e0a21cc048102777 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 24 Aug 2024 23:43:12 +0200 Subject: [PATCH] tree/view: Send configure before mapping Sending 0,0 as configure dimensions indicate that the client is free to pick its own dimensions. When tiling, the client needs to strictly adhere to the tile dimensions. Sway's handling of this has been to send a the appropriate dimensions in a new configure when the surface is mapped, leading to the first buffer most likely being incorrectly sized. Move the majority of the mapping logic to view_premap, issued on the initial role commit rather than when mapping the view. This allow the first configure to be driven by a tree transaction with the appropriate geometr, and allows container siblings to start preparing earlier as well, reducing the new window latency. Fixes: https://github.com/swaywm/sway/issues/2176 --- include/sway/tree/view.h | 15 +++++++++++++++ sway/desktop/xdg_shell.c | 19 +++++++++++++++++-- sway/tree/arrange.c | 1 + sway/tree/view.c | 25 +++++++++++++++---------- 4 files changed, 48 insertions(+), 12 deletions(-) diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 14aad1a183..047eefe1d4 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -297,6 +297,21 @@ void view_begin_destroy(struct sway_view *view); void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, bool fullscreen, struct wlr_output *fullscreen_output, bool decoration); +/** + * Prepare the view for its upcoming mapping, sending the intended dimensions + * so that the first frame has a chance of being correct. If CSD preferences or + * floating tendency changes, this may turn out to be inaccurate but no worse + * than skipping the step. + * + * `fullscreen` should be set to true (and optionally `fullscreen_output` + * should be populated) if the view should be made fullscreen immediately. + * + * `decoration` should be set to true if the client prefers CSD. The client's + * preference may be ignored. + */ +void view_premap(struct sway_view *view, struct wlr_surface *wlr_surface, + bool fullscreen, struct wlr_output *fullscreen_output, bool decoration); + void view_unmap(struct sway_view *view); void view_update_size(struct sway_view *view); diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 3aed4ec7eb..104b6fbef5 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -287,10 +287,25 @@ static void handle_commit(struct wl_listener *listener, void *data) { if (view->xdg_decoration != NULL) { set_xdg_decoration_mode(view->xdg_decoration); } - // XXX: https://github.com/swaywm/sway/issues/2176 + + bool csd = false; + if (view->xdg_decoration) { + enum wlr_xdg_toplevel_decoration_v1_mode mode = + view->xdg_decoration->wlr_xdg_decoration->requested_mode; + csd = mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; + } else { + struct sway_server_decoration *deco = + decoration_from_surface(xdg_surface->surface); + csd = !deco || deco->wlr_server_decoration->mode == + WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT; + } + wlr_xdg_surface_schedule_configure(xdg_surface); wlr_xdg_toplevel_set_wm_capabilities(view->wlr_xdg_toplevel, XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); + view_premap(&xdg_shell_view->view, xdg_surface->surface, false, NULL, csd); + transaction_commit_dirty(); + // TODO: wlr_xdg_toplevel_set_bounds() return; } @@ -518,7 +533,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, destroy); struct sway_view *view = &xdg_shell_view->view; - if (!sway_assert(view->surface == NULL, "Tried to destroy a mapped view")) { + if (!sway_assert(view->surface == NULL || !view->surface->mapped, "Tried to destroy a mapped view")) { return; } wl_list_remove(&xdg_shell_view->destroy.link); diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index d4003fe65a..5fe0bf72ca 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/sway/tree/view.c b/sway/tree/view.c index d25a09c2a2..f83d59cdd0 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -714,10 +714,10 @@ static void handle_foreign_destroy( wl_list_remove(&view->foreign_destroy.link); } -void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, +void view_premap(struct sway_view *view, struct wlr_surface *wlr_surface, bool fullscreen, struct wlr_output *fullscreen_output, bool decoration) { - if (!sway_assert(view->surface == NULL, "cannot map mapped view")) { + if (!sway_assert(view->surface == NULL, "cannot premap mapped view")) { return; } view->surface = wlr_surface; @@ -846,6 +846,19 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, view_execute_criteria(view); + const char *app_id; + const char *class; + if ((app_id = view_get_app_id(view)) != NULL) { + wlr_foreign_toplevel_handle_v1_set_app_id(view->foreign_toplevel, app_id); + } else if ((class = view_get_class(view)) != NULL) { + wlr_foreign_toplevel_handle_v1_set_app_id(view->foreign_toplevel, class); + } +} + +void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, + bool fullscreen, struct wlr_output *fullscreen_output, + bool decoration) { + bool set_focus = should_focus(view); #if WLR_HAS_XWAYLAND @@ -863,14 +876,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, if (view->ext_foreign_toplevel) { update_ext_foreign_toplevel(view); } - - const char *app_id; - const char *class; - if ((app_id = view_get_app_id(view)) != NULL) { - wlr_foreign_toplevel_handle_v1_set_app_id(view->foreign_toplevel, app_id); - } else if ((class = view_get_class(view)) != NULL) { - wlr_foreign_toplevel_handle_v1_set_app_id(view->foreign_toplevel, class); - } } void view_unmap(struct sway_view *view) {