From 0a9ff774ad77d5c650c03c0ac3501983f3cb0d19 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Mon, 28 Jan 2019 16:00:34 +1000 Subject: [PATCH] Center surface inside container when it's too small The goal here is to center fullscreen views when they are both too small for the output and refuse to resize to the output's dimensions. It has the side effect of also centering the view when it's too small for its container. Example clients that have this behaviour are emersion's hello-wayland and weston. It works by introducing surface_{x,y,width,height} properties to the container struct. The x and y represent layout-local coordinates where the surface will be rendered. The width and height are only used to track the surface's previous dimensions so we can detect when the client has resized it and recenter and apply damage accordingly. The new surface properties are calculated when a transaction is applied, as well as when a view resizes itself unexpectedly. The latter is done in view_update_size. This function was previously restricted to views which are floating, but can now be called for any views. For views which refuse to resize *smaller* than a particular size, such as gnome-calculator, the surface is still anchored to the top left as per the current behaviour. --- include/sway/tree/container.h | 7 +++++++ sway/desktop/render.c | 9 ++++----- sway/desktop/transaction.c | 20 ++++++++++++++++++++ sway/desktop/xdg_shell.c | 7 +++---- sway/desktop/xdg_shell_v6.c | 7 +++---- sway/desktop/xwayland.c | 7 +++---- sway/tree/container.c | 4 ++-- sway/tree/view.c | 23 +++++++++++++++-------- 8 files changed, 57 insertions(+), 27 deletions(-) diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index f0d0b3ce2..543bd2cc0 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -88,9 +88,16 @@ struct sway_container { double saved_x, saved_y; double saved_width, saved_height; + // These are in layout coordinates. double content_x, content_y; int content_width, content_height; + // In most cases this is the same as the content x and y, but if the view + // refuses to resize to the content dimensions then it can be smaller. + // These are in layout coordinates. + double surface_x, surface_y; + double surface_width, surface_height; + enum sway_fullscreen_mode fullscreen_mode; enum sway_container_border border; diff --git a/sway/desktop/render.c b/sway/desktop/render.c index fa27500ec..9102dc344 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -204,9 +204,9 @@ static void render_view_toplevels(struct sway_view *view, .alpha = alpha, }; // Render all toplevels without descending into popups - double ox = view->container->current.content_x - + double ox = view->container->surface_x - output->wlr_output->lx - view->geometry.x; - double oy = view->container->current.content_y - + double oy = view->container->surface_y - output->wlr_output->ly - view->geometry.y; output_surface_for_each_surface(output, view->surface, ox, oy, render_surface_iterator, &data); @@ -240,9 +240,9 @@ static void render_saved_view(struct sway_view *view, return; } struct wlr_box box = { - .x = view->container->current.content_x - output->wlr_output->lx - + .x = view->container->surface_x - output->wlr_output->lx - view->saved_geometry.x, - .y = view->container->current.content_y - output->wlr_output->ly - + .y = view->container->surface_y - output->wlr_output->ly - view->saved_geometry.y, .width = view->saved_buffer_width, .height = view->saved_buffer_height, @@ -1004,7 +1004,6 @@ void output_render(struct sway_output *output, struct timespec *when, wlr_renderer_clear(renderer, clear_color); } - // TODO: handle views smaller than the output if (fullscreen_con->view) { if (fullscreen_con->view->saved_buffer) { render_saved_view(fullscreen_con->view, output, damage, 1.0f); diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 9155f0a17..e0c3a5d1e 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -249,6 +249,26 @@ static void apply_container_state(struct sway_container *container, desktop_damage_box(&box); } + // If the view hasn't responded to the configure, center it within + // the container. This is important for fullscreen views which + // refuse to resize to the size of the output. + if (view && view->surface) { + if (view->surface->current.width < container->width) { + container->surface_x = container->content_x + + (container->content_width - view->surface->current.width) / 2; + } else { + container->surface_x = container->content_x; + } + if (view->surface->current.height < container->height) { + container->surface_y = container->content_y + + (container->content_height - view->surface->current.height) / 2; + } else { + container->surface_y = container->content_y; + } + container->surface_width = view->surface->current.width; + container->surface_height = view->surface->current.height; + } + if (!container->node.destroying) { container_discover_outputs(container); } diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 007b0a94d..b5dcfb0fb 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -291,10 +291,9 @@ static void handle_commit(struct wl_listener *listener, void *data) { wlr_xdg_surface_get_geometry(xdg_surface, &new_geo); struct sway_container *con = view->container; - if ((new_geo.width != con->content_width || - new_geo.height != con->content_height) && - container_is_floating(con)) { - // A floating view has unexpectedly sent a new size + if ((new_geo.width != con->surface_width || + new_geo.height != con->surface_height)) { + // The view has unexpectedly sent a new size desktop_damage_view(view); view_update_size(view, new_geo.width, new_geo.height); memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 386e350ea..a7ea163f5 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -284,10 +284,9 @@ static void handle_commit(struct wl_listener *listener, void *data) { wlr_xdg_surface_v6_get_geometry(xdg_surface_v6, &new_geo); struct sway_container *con = view->container; - if ((new_geo.width != con->content_width || - new_geo.height != con->content_height) && - container_is_floating(con)) { - // A floating view has unexpectedly sent a new size + if ((new_geo.width != con->surface_width || + new_geo.height != con->surface_height)) { + // The view has unexpectedly sent a new size desktop_damage_view(view); view_update_size(view, new_geo.width, new_geo.height); memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index d9e1b0a91..e0d307e86 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -333,10 +333,9 @@ static void handle_commit(struct wl_listener *listener, void *data) { get_geometry(view, &new_geo); struct sway_container *con = view->container; - if ((new_geo.width != con->content_width || - new_geo.height != con->content_height) && - container_is_floating(con)) { - // A floating view has unexpectedly sent a new size + if ((new_geo.width != con->surface_width || + new_geo.height != con->surface_height)) { + // The view has unexpectedly sent a new size // eg. The Firefox "Save As" dialog when downloading a file desktop_damage_view(view); view_update_size(view, new_geo.width, new_geo.height); diff --git a/sway/tree/container.c b/sway/tree/container.c index d8ad3bc04..1cf5c8e75 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -169,8 +169,8 @@ static struct sway_container *surface_at_view(struct sway_container *con, double return NULL; } struct sway_view *view = con->view; - double view_sx = lx - con->content_x + view->geometry.x; - double view_sy = ly - con->content_y + view->geometry.y; + double view_sx = lx - con->surface_x + view->geometry.x; + double view_sy = ly - con->surface_y + view->geometry.y; double _sx, _sy; struct wlr_surface *_surface = NULL; diff --git a/sway/tree/view.c b/sway/tree/view.c index 561c6ef1f..9ccb2a31c 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -673,15 +673,22 @@ void view_unmap(struct sway_view *view) { } void view_update_size(struct sway_view *view, int width, int height) { - if (!sway_assert(container_is_floating(view->container), - "Expected a floating container")) { - return; + struct sway_container *con = view->container; + + if (container_is_floating(con)) { + con->content_width = width; + con->content_height = height; + con->current.content_width = width; + con->current.content_height = height; + container_set_geometry_from_content(con); + } else { + con->surface_x = con->content_x + (con->content_width - width) / 2; + con->surface_y = con->content_y + (con->content_height - height) / 2; + con->surface_x = fmax(con->surface_x, con->content_x); + con->surface_y = fmax(con->surface_y, con->content_y); } - view->container->content_width = width; - view->container->content_height = height; - view->container->current.content_width = width; - view->container->current.content_height = height; - container_set_geometry_from_content(view->container); + con->surface_width = width; + con->surface_width = height; } static const struct sway_view_child_impl subsurface_impl;