event_loop: cover every output with a session-lock surface, with the app's backdrop on the secondary ones
ext-session-lock-v1 obliges the compositor to blank any output that has no lock surface, and the runtime only ever created one, on the first output — so on a multi-monitor session the extended screens went black the moment the lock engaged. The lock grant now creates one lock surface per advertised output: the first keeps hosting the app's main surface exactly as before, and each remaining output gets its own surface tracked in `lock_extras`, paired with its `WlOutput` so configure, scale and teardown can be routed per surface. What those extra surfaces show is up to the app: a new `App::lock_secondary_view( width, height )` returns the content for a secondary output of that physical size, and the default `None` paints the surface with `background_color()`. The draw pass renders them without requesting frame callbacks — their content is static between invalidations, and a callback that is never re-requested would leave `frame_pending` stuck — and invalidations that touch the main surface also mark the extras, so a backdrop that follows main-surface state (wallpaper swaps, theme changes) stays in sync. The per-surface plumbing that only ever knew about the main surface learns to route: `SessionLockHandler::configure` matches the surface against main and the extras instead of assuming main (an extra's configure used to resize the main surface's target), and the scale-change resize moves into an `apply_surface_scale` helper shared by main, overlays and the lock extras, so a HiDPI secondary gets a correctly scaled buffer instead of staying at factor 1. `new_output` creates a lock surface for an output hotplugged while locked — the compositor would blank it otherwise — and `output_destroyed` drops the matching extra. Input on the extras is deliberately inert, with one asymmetry: pointer and touch events landing on them are discarded rather than falling back to `Main`, because their coordinates would hit-test the main surface's widgets and a click on a secondary screen could press whatever sits at those coordinates on the form — the power button included. Keyboard keeps its existing fall-through to `Main`, so typing works wherever the compositor decides to put the lock focus.
This commit is contained in:
@@ -320,6 +320,8 @@ pub( crate ) fn try_run<A: App>( app: A ) -> Result<(), RunError>
|
||||
pending_size_hint_unpin,
|
||||
main: SurfaceState::<A::Message>::new( surface_kind, titlebar_height, titlebar_title ),
|
||||
overlays: std::collections::HashMap::new(),
|
||||
lock_extras: Vec::new(),
|
||||
main_lock_output: None,
|
||||
subsurfaces: std::collections::HashMap::new(),
|
||||
subsurface_gles_canvas: None,
|
||||
pointer_focus: SurfaceFocus::Main,
|
||||
@@ -597,7 +599,8 @@ pub( crate ) fn try_run<A: App>( app: A ) -> Result<(), RunError>
|
||||
// on a frame callback. The compositor decides our cadence — when no
|
||||
// surface qualifies we just loop back to `dispatch(None)` and sleep.
|
||||
let any_drawable = ( data.main.configured && data.main.needs_redraw && !data.main.frame_pending )
|
||||
|| data.overlays.values().any( |ss| ss.configured && ss.needs_redraw && !ss.frame_pending );
|
||||
|| data.overlays.values().any( |ss| ss.configured && ss.needs_redraw && !ss.frame_pending )
|
||||
|| data.lock_extras.iter().any( |( _, ss )| ss.configured && ss.needs_redraw && !ss.frame_pending );
|
||||
if any_drawable
|
||||
{
|
||||
// Rebuild while motion is in progress and on the first frame
|
||||
|
||||
Reference in New Issue
Block a user