refactor(state): make output probe readiness transform-only
CI / Build + Clippy + Test (pull_request) Failing after 11s
CI / Security audit (RUSTSEC) (pull_request) Failing after 31s
CI / Build + Clippy + Test (pull_request) Failing after 11s
CI / Security audit (RUSTSEC) (pull_request) Failing after 31s
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.
This commit is contained in:
+9
-56
@@ -85,20 +85,17 @@ pub struct PartialOutputInfo {
|
|||||||
/// Name from wl_output::Name (v4) — used to match wlr-output-management heads
|
/// Name from wl_output::Name (v4) — used to match wlr-output-management heads
|
||||||
pub wl_name: Option<String>,
|
pub wl_name: Option<String>,
|
||||||
pub transform: Option<Transform>,
|
pub transform: Option<Transform>,
|
||||||
pub physical_size: Option<(i32, i32)>,
|
|
||||||
pub logical_position: Option<(i32, i32)>,
|
|
||||||
// Pixel dimensions from Mode event — preparatory for Phase 2 resolution logic
|
// Pixel dimensions from Mode event — preparatory for Phase 2 resolution logic
|
||||||
pub mode_size: Option<(i32, i32)>,
|
pub mode_size: Option<(i32, i32)>,
|
||||||
pub done_count: u32,
|
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`
|
// `pub(crate)` (not module-private): exposed via `EncConstructionStage::ProbingOutputs.wlr_heads`
|
||||||
// which is reached from main.rs during the wlr-screencopy probing loop.
|
// which is reached from main.rs during the wlr-screencopy probing loop.
|
||||||
pub(crate) struct WlrHeadInfo {
|
pub(crate) struct WlrHeadInfo {}
|
||||||
position: Option<(i32, i32)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// User data for XdgOutput dispatch to identify which WlOutput it belongs to.
|
/// User data for XdgOutput dispatch to identify which WlOutput it belongs to.
|
||||||
pub struct OutputId(pub u32);
|
pub struct OutputId(pub u32);
|
||||||
@@ -832,22 +829,6 @@ impl<S: CaptureSource> State<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn try_finalize_output(&mut self, _idx: usize) -> bool {
|
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 {
|
let (target_idx, output_count) = match &self.stage {
|
||||||
EncConstructionStage::ProbingOutputs {
|
EncConstructionStage::ProbingOutputs {
|
||||||
outputs,
|
outputs,
|
||||||
@@ -890,24 +871,19 @@ impl<S: CaptureSource> State<S> {
|
|||||||
Some(i) => {
|
Some(i) => {
|
||||||
let info = &outputs[i];
|
let info = &outputs[i];
|
||||||
if has_xdg {
|
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
|
if info.done_count < 2
|
||||||
|| info.name.is_none()
|
|| info.name.is_none()
|
||||||
|| info.transform.is_none()
|
|| info.transform.is_none()
|
||||||
|| info.physical_size.is_none()
|
|
||||||
|| info.logical_position.is_none()
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// wlr-output-management path (niri) — relaxed checks
|
// done_count >= 1 implies transform arrived (Geometry precedes Done).
|
||||||
if info.done_count < 1 || !wlr_manager_done {
|
if info.done_count < 1 || !wlr_manager_done || info.transform.is_none() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if info.transform.is_none() || info.physical_size.is_none() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// name and logical_position can use defaults
|
|
||||||
}
|
}
|
||||||
(i, output_count)
|
(i, output_count)
|
||||||
}
|
}
|
||||||
@@ -1180,8 +1156,6 @@ impl<S: CaptureSource> Dispatch<WlOutput, OutputId> for State<S> {
|
|||||||
match event {
|
match event {
|
||||||
OutputEvent::Geometry {
|
OutputEvent::Geometry {
|
||||||
transform,
|
transform,
|
||||||
physical_width,
|
|
||||||
physical_height,
|
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let t = match transform {
|
let t = match transform {
|
||||||
@@ -1198,7 +1172,6 @@ impl<S: CaptureSource> Dispatch<WlOutput, OutputId> for State<S> {
|
|||||||
if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage {
|
if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage {
|
||||||
if let Some(info) = outputs.get_mut(idx) {
|
if let Some(info) = outputs.get_mut(idx) {
|
||||||
info.transform = Some(t);
|
info.transform = Some(t);
|
||||||
info.physical_size = Some((physical_width, physical_height));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1272,13 +1245,6 @@ impl<S: CaptureSource> Dispatch<ZxdgOutputV1, OutputId> for State<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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::LogicalSize { .. } => {}
|
||||||
XdgOutputEvent::Done => {
|
XdgOutputEvent::Done => {
|
||||||
if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage {
|
if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage {
|
||||||
@@ -1563,24 +1529,11 @@ impl<S: CaptureSource> Dispatch<ZwlrOutputHeadV1, ()> for State<S> {
|
|||||||
{
|
{
|
||||||
wlr_heads
|
wlr_heads
|
||||||
.entry(name.clone())
|
.entry(name.clone())
|
||||||
.or_insert(WlrHeadInfo { position: None });
|
.or_insert(WlrHeadInfo {});
|
||||||
wlr_head_proxy_to_name.insert(proxy.id(), name);
|
wlr_head_proxy_to_name.insert(proxy.id(), name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WlrHeadEvent::Position { x, y } => {
|
WlrHeadEvent::Position { .. } => {}
|
||||||
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::Finished => {
|
WlrHeadEvent::Finished => {
|
||||||
tracing::debug!("zwlr_output_head_v1::Finished received");
|
tracing::debug!("zwlr_output_head_v1::Finished received");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user