layer layout: reserve only exclusive-zone surfaces (two-pass, labwc-style)
Replace the layer_reserve_box self-reservation heuristic with labwc's layers_arrange(): configure exclusive-zone surfaces first (highest layer down) so they reserve, then the zero-exclusive-zone remainder (lowest layer up) positioned within the residue without shrinking it. A transient zero-ez surface (e.g. a panel notification) no longer resizes the tabs.
This commit is contained in:
parent
bc98746207
commit
5dc0c76cd1
1 changed files with 54 additions and 72 deletions
126
kick.c
126
kick.c
|
|
@ -4363,15 +4363,19 @@ found:
|
|||
Layer-shell surfaces are never tabs: each renders into server.layer_tree, a
|
||||
dedicated child of server.scene->tree that sits above every window tree and
|
||||
is never toggled by show_window()/set_active_tab(), so a bar stays visible
|
||||
across all tabs. The bar's exclusive zone shrinks the usable area the
|
||||
maximized tabs are sized into, mirroring sway (tabs never overlap the bar).
|
||||
across all tabs. Only a layer surface's own exclusive_zone shrinks the
|
||||
usable area the maximized tabs are sized into (delegated to wlroots' scene
|
||||
helper), mirroring sway and labwc: a transient zero-exclusive-zone surface
|
||||
(e.g. a panel notification) is positioned but never resizes the tabs.
|
||||
|
||||
wlroots' own scene helper (wlr_scene_layer_surface_v1_*) does the heavy
|
||||
lifting for us: it computes the surface's anchored/centered geometry from
|
||||
its pending state and, for mapped surfaces with a positive exclusive zone,
|
||||
shrinks a caller-supplied usable area for the next layer surface. We just
|
||||
drive that per-surface and then size every maximized tab to the residual
|
||||
usable box. */
|
||||
shrinks a caller-supplied usable area for the next layer surface. We drive
|
||||
that in two passes -- exclusive-zone surfaces first (highest layer first)
|
||||
so they always get preferred placement regardless of launch order, then the
|
||||
zero-exclusive-zone remainder within the residue (lowest layer first) --
|
||||
and size every maximized tab to the residual usable box. */
|
||||
|
||||
struct kick_layer {
|
||||
struct wl_list link;
|
||||
|
|
@ -4431,78 +4435,56 @@ static void layer_raise_above_windows(void) {
|
|||
wlr_scene_node_raise_to_top(&server.layer_tree->node);
|
||||
}
|
||||
|
||||
/* Run the layer layout pass: configure every layer surface against the given
|
||||
full area, letting each reservation shrink the shared usable box, then size
|
||||
all maximized tabs into the residual area. */
|
||||
/* Reserve the bar's own footprint along its anchored edge, independent of the
|
||||
client's exclusive_zone (which a panel like waybar may never send). The
|
||||
bar's rendered height is taken from its requested size, falling back to the
|
||||
mapped surface box. Only a mapped, positively-sized bar reserves space, so
|
||||
a still-starting client doesn't collapse the tabs. */
|
||||
static void layer_reserve_box(struct wlr_layer_surface_v1 *layer_surface,
|
||||
struct wlr_box *usable) {
|
||||
struct wlr_surface *s = layer_surface->surface;
|
||||
if (!s || !s->mapped) return;
|
||||
/* When the client already requests an exclusive zone, wlroots shrank
|
||||
usable by it during wlr_scene_layer_surface_v1_configure; reserving the
|
||||
footprint here too would double-shrink. Only self-reserve bars that do
|
||||
not ask for an exclusive zone (e.g. waybar defaulting to exclusive_zone
|
||||
0 while still occupying the edge). */
|
||||
if (layer_surface->current.exclusive_zone > 0) return;
|
||||
|
||||
uint32_t anchor = layer_surface->current.anchor;
|
||||
int h = (int)layer_surface->current.desired_height;
|
||||
int w = (int)layer_surface->current.desired_width;
|
||||
if (h == 0 && s->current.buffer_height > 0) {
|
||||
int scale = s->current.scale > 0 ? s->current.scale : 1;
|
||||
h = s->current.buffer_height / scale;
|
||||
}
|
||||
if (w == 0 && s->current.buffer_width > 0) {
|
||||
int scale = s->current.scale > 0 ? s->current.scale : 1;
|
||||
w = s->current.buffer_width / scale;
|
||||
}
|
||||
|
||||
if (anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP && h > 0) {
|
||||
usable->y += h;
|
||||
if (usable->height >= h)
|
||||
usable->height -= h;
|
||||
else
|
||||
usable->height = 0;
|
||||
} else if (anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM && h > 0) {
|
||||
if (usable->height >= h)
|
||||
usable->height -= h;
|
||||
else
|
||||
usable->height = 0;
|
||||
} else if (anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT && w > 0) {
|
||||
usable->x += w;
|
||||
if (usable->width >= w)
|
||||
usable->width -= w;
|
||||
else
|
||||
usable->width = 0;
|
||||
} else if (anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT && w > 0) {
|
||||
if (usable->width >= w)
|
||||
usable->width -= w;
|
||||
else
|
||||
usable->width = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void layer_apply_layout_box(const struct wlr_box *full) {
|
||||
struct wlr_box usable = *full;
|
||||
/* Layer orders for the two configure passes, mirroring labwc's
|
||||
layers_arrange(): exclusive-zone surfaces run from the highest layer down
|
||||
so they always get preferred placement, the zero-exclusive-zone remainder
|
||||
runs from the lowest layer up inside the residue. */
|
||||
static const enum zwlr_layer_shell_v1_layer layer_order_exclusive[] = {
|
||||
ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
|
||||
ZWLR_LAYER_SHELL_V1_LAYER_TOP,
|
||||
ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM,
|
||||
ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND,
|
||||
};
|
||||
static const enum zwlr_layer_shell_v1_layer layer_order_rest[] = {
|
||||
ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND,
|
||||
ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM,
|
||||
ZWLR_LAYER_SHELL_V1_LAYER_TOP,
|
||||
ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
|
||||
};
|
||||
|
||||
/* Configure every layer surface on `want` whose exclusive-zone class matches:
|
||||
exclusive=true means a non-zero exclusive_zone (including -1, the full-area
|
||||
request), exclusive=false the zero-exclusive-zone remainder. wlroots' scene
|
||||
helper shrinks the shared usable box inside the call for mapped surfaces
|
||||
with a positive exclusive zone, and positions everything else within the
|
||||
current residue without shrinking it. */
|
||||
static void layer_configure_class(enum zwlr_layer_shell_v1_layer want,
|
||||
bool exclusive, const struct wlr_box *full,
|
||||
struct wlr_box *usable) {
|
||||
struct kick_layer *sl;
|
||||
wl_list_for_each(sl, &server.layer_surfaces, link) {
|
||||
if (!sl->scene || !sl->seen_init) continue;
|
||||
wlr_scene_layer_surface_v1_configure(sl->scene, full, &usable);
|
||||
}
|
||||
/* Reserve the bars' footprint (see layer_reserve_box). This runs after
|
||||
wlroots has shrunk usable by any explicit exclusive_zone, but our own
|
||||
reservation is what actually guarantees tabs clear a bar that never
|
||||
requests an exclusive zone. */
|
||||
wl_list_for_each(sl, &server.layer_surfaces, link) {
|
||||
if (!sl->scene) continue;
|
||||
layer_reserve_box(sl->surface, &usable);
|
||||
if (sl->surface->current.layer != want) continue;
|
||||
if (!!sl->surface->current.exclusive_zone != exclusive) continue;
|
||||
wlr_scene_layer_surface_v1_configure(sl->scene, full, usable);
|
||||
}
|
||||
}
|
||||
|
||||
/* Run the layer layout pass: configure every layer surface against the given
|
||||
full area -- exclusive-zone surfaces first so they reserve, then the
|
||||
zero-exclusive-zone remainder within the residue -- and size all maximized
|
||||
tabs into the final usable box. */
|
||||
static void layer_apply_layout_box(const struct wlr_box *full) {
|
||||
struct wlr_box usable = *full;
|
||||
|
||||
for (size_t i = 0;
|
||||
i < sizeof(layer_order_exclusive) / sizeof(layer_order_exclusive[0]);
|
||||
i++)
|
||||
layer_configure_class(layer_order_exclusive[i], true, full, &usable);
|
||||
|
||||
for (size_t i = 0;
|
||||
i < sizeof(layer_order_rest) / sizeof(layer_order_rest[0]); i++)
|
||||
layer_configure_class(layer_order_rest[i], false, full, &usable);
|
||||
|
||||
server.layout_x = usable.x;
|
||||
server.layout_y = usable.y;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue