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

@@ -84,15 +84,23 @@ pub( crate ) fn apply_input_region(
wl_surface: &WlSurface,
compositor: &CompositorState,
input_region: Option<&[Rect]>,
scale: u32,
)
{
if let Some( regions ) = input_region
{
if let Ok( region ) = Region::new( compositor )
{
// `Rect`s are physical (layout space); `wl_region` is logical.
let s = scale.max( 1 ) as f32;
for r in regions
{
region.add( r.x as i32, r.y as i32, r.width as i32, r.height as i32 );
region.add(
( r.x / s ).round() as i32,
( r.y / s ).round() as i32,
( r.width / s ).round() as i32,
( r.height / s ).round() as i32,
);
}
wl_surface.set_input_region( Some( region.wl_region() ) );
}

View File

@@ -141,7 +141,7 @@ pub( crate ) fn draw_surface_full_gpu<Msg: Clone>(
ss.content_dirty = false;
let wl_surface = ss.surface.wl_surface();
apply_input_region( wl_surface, compositor, input_region );
apply_input_region( wl_surface, compositor, input_region, scale );
// Frame callback request must precede the implicit commit done by
// `swap_buffers_with_damage`, so the compositor can attach it to this
// frame and not the previous one.
@@ -241,7 +241,7 @@ pub( crate ) fn draw_surface_partial_gpu<Msg: Clone>(
ss.content_dirty = false;
let wl_surface = ss.surface.wl_surface();
apply_input_region( wl_surface, compositor, input_region );
apply_input_region( wl_surface, compositor, input_region, scale );
request_frame( wl_surface );
// Convert top-left dirty rects to EGL bottom-left coords for the
// swap-with-damage call.

View File

@@ -167,7 +167,7 @@ pub( crate ) fn draw_surface_full<Msg: Clone>(
}
}
apply_input_region( wl_surface, compositor, input_region );
apply_input_region( wl_surface, compositor, input_region, scale );
// Request a frame callback BEFORE commit so the compositor schedules it
// against this exact frame; sets `frame_pending` so the run loop won't
// try to draw this surface again until the callback fires.
@@ -282,7 +282,7 @@ pub( crate ) fn draw_surface_partial<Msg: Clone>(
wl_surface.damage_buffer( r.x as i32, r.y as i32, r.width as i32, r.height as i32 );
}
apply_input_region( wl_surface, compositor, input_region );
apply_input_region( wl_surface, compositor, input_region, scale );
request_frame( wl_surface );
wl_surface.commit();
ss.frame_pending = true;