From 87fee21c0463383467025d71da7a9c2ddd6f5620 Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Mon, 5 Jan 2026 00:14:32 -0500 Subject: [PATCH] view: use midpoint of actual geometry to pick output after layout change This ensures that maximized/fullscreen/tiled views are restored to the correct output after it is disconnected and reconnected, including: - initially maximized/fullscreen xdg-shell views (which have invalid natural geometry until after being un-maximized/un-fullscreened) - views which were maximized/tiled via snap-to-edge on a different output than the natural/floating geometry --- include/view.h | 9 +++++++++ src/view.c | 29 ++++++++++++++++------------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/include/view.h b/include/view.h index 239eb2db..3e6e3127 100644 --- a/include/view.h +++ b/include/view.h @@ -7,6 +7,7 @@ #include #include #include +#include "common/box.h" #include "common/edge.h" #include "config.h" #include "config/types.h" @@ -219,6 +220,14 @@ struct view { * layout change. False if it was due to user-initiated action. */ bool adjusted_for_layout_change; + /* + * Midpoint of the view's actual geometry prior to adjusting + * for a layout change. For floating views, this will match the + * natural_geometry, but for maximized/tiled/fullscreen views it + * could be on a different output, in which case it is needed to + * restore those views to the correct output. + */ + struct point saved_midpoint; /* used by xdg-shell views */ uint32_t pending_configure_serial; diff --git a/src/view.c b/src/view.c index 391e7d64..d598e705 100644 --- a/src/view.c +++ b/src/view.c @@ -446,18 +446,12 @@ view_get_edge_snap_box(struct view *view, struct output *output, } static bool -view_discover_output(struct view *view, struct wlr_box *geometry) +view_discover_output(struct view *view, struct point midpoint) { assert(view); - if (!geometry) { - geometry = &view->current; - } - struct output *output = - output_nearest_to(view->server, - geometry->x + geometry->width / 2, - geometry->y + geometry->height / 2); + output_nearest_to(view->server, midpoint.x, midpoint.y); if (output && output != view->output) { view->output = output; @@ -571,7 +565,7 @@ view_moved(struct view *view) * output when they enter that state. */ if (view_is_floating(view)) { - view_discover_output(view, NULL); + view_discover_output(view, box_midpoint(&view->current)); } view_update_outputs(view); ssd_update_geometry(view->ssd); @@ -1730,9 +1724,7 @@ view_adjust_for_layout_change(struct view *view) * - Any view without a usable output needs to be repositioned * - Any fullscreen/tiled/maximized view which was previously * handled through this path (i.e. previously lost its output) - * is also checked again. For these, the logic is not quite - * right since the output is chosen based on the natural - * (floating) geometry, but it's better than nothing. + * should be moved back if the output is reconnected. */ if (is_floating || adjusted || !output_is_usable(view->output)) { /* @@ -1742,13 +1734,24 @@ view_adjust_for_layout_change(struct view *view) * the point is to be able to restore to the original * location after multiple layout changes (e.g. output * disconnected and then reconnected). + * + * Also save midpoint of actual geometry, which is needed + * to restore non-floating views to the correct output. */ if (!adjusted) { view_store_natural_geometry(view); + view->saved_midpoint = box_midpoint(&view->pending); adjusted = true; } - view_discover_output(view, &view->natural_geometry); + /* + * Now try to find the "nearest" output (in terms of + * layout coordinates) to the original position of the + * view. Other strategies might be possible here -- for + * example, trying to match the same physical output the + * view was on previously -- but this is simplest. + */ + view_discover_output(view, view->saved_midpoint); } if (is_floating) {