ltk: convert physical sizes to logical for overlays and input regions on HiDPI
Some checks failed
CI / build + test (push) Has been cancelled
CI / cargo audit (push) Has been cancelled

Overlay `set_size` and input regions were handed physical (layout-space) pixels straight to layer-shell and `wl_region`, both of which expect logical coordinates. They only coincide at scale 1, so on a scale-2 output every overlay requested a surface twice its intended size and the input region covered the wrong area.
`apply_input_region` now takes the surface scale and divides each `Rect` down to logical before adding it to the region; the four draw paths (software and gles, full and partial) forward their scale. `reconcile_overlays` converts `OverlaySpec::size` to logical for both `set_size` and the initial `OverlayConfig` (0 = fill survives the divide), and seeds the new surface's `scale_factor` from the parent so the first configure allocates a HiDPI buffer instead of rendering at scale 1 until `scale_factor_changed` lands a frame or two later.
This commit is contained in:
2026-05-26 22:22:18 +02:00
parent fc045a9c22
commit 1e2cb836f4
4 changed files with 34 additions and 8 deletions

View File

@@ -99,7 +99,19 @@ pub( super ) fn reconcile_overlays<A: App>( data: &mut AppData<A> )
SurfaceKind::Window( ref w ) => Some( w.xdg_surface().clone() ),
_ => None,
};
let parent_scale = data.main.scale_factor.max( 1 ) as f32;
let parent_scale_i = data.main.scale_factor.max( 1 );
let parent_scale = parent_scale_i as f32;
// `OverlaySpec::size` is physical pixels (the app's layout space); the
// layer-shell `set_size` is logical. They only coincide at scale 1, so
// convert here — without it a scale-2 overlay requests a surface twice
// its intended size. `0 = fill` survives the divide.
let to_logical_size = move | ( w, h ): ( u32, u32 ) | -> ( u32, u32 )
{
(
( w as f32 / parent_scale ).round() as u32,
( h as f32 / parent_scale ).round() as u32,
)
};
// Snapshot the previous-frame anchor lookup table so we can resolve
// `anchor_widget_id` → `Rect` without holding a borrow on `data.main`
// across the overlay-mut loop below.
@@ -122,7 +134,8 @@ pub( super ) fn reconcile_overlays<A: App>( data: &mut AppData<A> )
{
if let SurfaceKind::Layer( ref layer_surface ) = ss.surface
{
layer_surface.set_size( spec.size.0, spec.size.1 );
let ( lw, lh ) = to_logical_size( spec.size );
layer_surface.set_size( lw, lh );
layer_surface.commit();
ss.last_requested_size = spec.size;
}
@@ -272,7 +285,7 @@ pub( super ) fn reconcile_overlays<A: App>( data: &mut AppData<A> )
layer: spec.layer.to_wlr_layer(),
exclusive_zone: spec.exclusive_zone,
anchor: spec.anchor,
size: spec.size,
size: to_logical_size( spec.size ),
keyboard_exclusive: spec.keyboard_exclusive,
namespace: "ltk-overlay",
};
@@ -282,6 +295,11 @@ pub( super ) fn reconcile_overlays<A: App>( data: &mut AppData<A> )
surface.materialize( cs, layer_shell, qh, output );
}
let mut ss = SurfaceState::<A::Message>::new( surface, 0.0, String::new() );
// Inherit the parent's scale so the first configure allocates a
// HiDPI buffer and lays out at the right size from frame one,
// instead of rendering at scale 1 until `scale_factor_changed`
// lands a frame or two later.
ss.scale_factor = parent_scale_i;
ss.last_requested_size = spec.size;
ss.layer_anchor = Some( spec.anchor );
overlays_m.insert( spec.id, ss );