From 9a7b745a0e1c10704be0b6b2d6e140c5d83fbdb9 Mon Sep 17 00:00:00 2001 From: dailz Date: Thu, 9 Jul 2026 14:48:10 +0800 Subject: [PATCH] refactor(state): make output probe readiness transform-only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drops PartialOutputInfo.physical_size and .logical_position. After the warning cleanup in 6332472 these fields were probe-time-only gates with no downstream consumer (encoder reads geometry from the dmabuf frame itself, not from wl_output description). Readiness simplification (try_finalize_output): - xdg-output path (Sway/Hyprland): done_count >= 2 + name + transform - wlr-output-management path (niri): done_count >= 1 + wlr_manager_done + transform Safe because Wayland protocol guarantees Geometry/Mode/Position events fire before Done, so done_count >= N implies the prior events arrived. done_count is the real signal; the per-field .is_none() checks were redundant belt-and-suspenders. Cascading cleanup of writers that only fed the deleted fields: - WlOutput::Geometry handler — drop physical_size write, keep transform - XdgOutputEvent::LogicalPosition arm — deleted - WlrHeadEvent::Position arm — deleted (was the only reader of wlr_head_proxy_to_name; both maps now write-only markers) - WlrHeadInfo.position field — deleted; struct becomes empty marker Behavior change risk: probe may finalize slightly earlier in cases where a compositor fires Done before physical_size/logical_position events (protocol violation, but possible). Verified with cargo test --release (79 unit + 3 integration, 1 ignored). Hardware/Wayland-session test deferred to user. Net: -48 lines. --- src/state.rs | 65 ++++++++-------------------------------------------- 1 file changed, 9 insertions(+), 56 deletions(-) diff --git a/src/state.rs b/src/state.rs index 47c9343..960d4e6 100644 --- a/src/state.rs +++ b/src/state.rs @@ -85,20 +85,17 @@ pub struct PartialOutputInfo { /// Name from wl_output::Name (v4) — used to match wlr-output-management heads pub wl_name: Option, pub transform: Option, - pub physical_size: Option<(i32, i32)>, - pub logical_position: Option<(i32, i32)>, // Pixel dimensions from Mode event — preparatory for Phase 2 resolution logic pub mode_size: Option<(i32, i32)>, pub done_count: u32, } -/// Stores head info from wlr-output-management for name-based matching with wl_output. +/// Marker for wlr-output-management heads seen during probing; tracked by name +/// in `EncConstructionStage::ProbingOutputs.wlr_heads`. // `pub(crate)` (not module-private): exposed via `EncConstructionStage::ProbingOutputs.wlr_heads` // which is reached from main.rs during the wlr-screencopy probing loop. -pub(crate) struct WlrHeadInfo { - position: Option<(i32, i32)>, -} +pub(crate) struct WlrHeadInfo {} /// User data for XdgOutput dispatch to identify which WlOutput it belongs to. pub struct OutputId(pub u32); @@ -832,22 +829,6 @@ impl State { } fn try_finalize_output(&mut self, _idx: usize) -> bool { - // Merge wlr head position info into outputs (needed for niri path) - if let EncConstructionStage::ProbingOutputs { - outputs, wlr_heads, .. - } = &mut self.stage - { - for info in outputs.iter_mut() { - if info.logical_position.is_none() { - if let Some(ref wl_name) = info.wl_name { - if let Some(head_info) = wlr_heads.get(wl_name) { - info.logical_position = head_info.position; - } - } - } - } - } - let (target_idx, output_count) = match &self.stage { EncConstructionStage::ProbingOutputs { outputs, @@ -890,24 +871,19 @@ impl State { Some(i) => { let info = &outputs[i]; if has_xdg { - // xdg-output path (Sway/Hyprland) — strict checks + // done_count >= 2 implies physical_size and logical_position + // already arrived (Wayland: Geometry/Mode/Position fire before Done). if info.done_count < 2 || info.name.is_none() || info.transform.is_none() - || info.physical_size.is_none() - || info.logical_position.is_none() { return false; } } else { - // wlr-output-management path (niri) — relaxed checks - if info.done_count < 1 || !wlr_manager_done { + // done_count >= 1 implies transform arrived (Geometry precedes Done). + if info.done_count < 1 || !wlr_manager_done || info.transform.is_none() { return false; } - if info.transform.is_none() || info.physical_size.is_none() { - return false; - } - // name and logical_position can use defaults } (i, output_count) } @@ -1180,8 +1156,6 @@ impl Dispatch for State { match event { OutputEvent::Geometry { transform, - physical_width, - physical_height, .. } => { let t = match transform { @@ -1198,7 +1172,6 @@ impl Dispatch for State { if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage { if let Some(info) = outputs.get_mut(idx) { info.transform = Some(t); - info.physical_size = Some((physical_width, physical_height)); } } } @@ -1272,13 +1245,6 @@ impl Dispatch for State { } } } - XdgOutputEvent::LogicalPosition { x, y } => { - if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage { - if let Some(info) = outputs.get_mut(idx) { - info.logical_position = Some((x, y)); - } - } - } XdgOutputEvent::LogicalSize { .. } => {} XdgOutputEvent::Done => { if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage { @@ -1563,24 +1529,11 @@ impl Dispatch for State { { wlr_heads .entry(name.clone()) - .or_insert(WlrHeadInfo { position: None }); + .or_insert(WlrHeadInfo {}); wlr_head_proxy_to_name.insert(proxy.id(), name); } } - WlrHeadEvent::Position { x, y } => { - if let EncConstructionStage::ProbingOutputs { - wlr_heads, - wlr_head_proxy_to_name, - .. - } = &mut state.stage - { - if let Some(name) = wlr_head_proxy_to_name.get(&proxy.id()) { - if let Some(head) = wlr_heads.get_mut(name) { - head.position = Some((x, y)); - } - } - } - } + WlrHeadEvent::Position { .. } => {} WlrHeadEvent::Finished => { tracing::debug!("zwlr_output_head_v1::Finished received"); }