v5.6 followup: drop xdg_wm_base ping + test cleanup
The round-5 comprehensive fix (W1/W2/W3 + compile errors) left the redbear-compositor with a xdg_wm_base debug ping on every global registration. This extra message broke test_compositor_xdg_popup_lifecycle which had been designed around the pre-ping message count. Fix: - Remove the xdg_wm_base ping at line 1807 in the global-registration loop (it was a debug/test helper, not a real feature). - Annotate the now-unused send_xdg_wm_base_ping with #[allow(dead_code)] so the codebase still references the function for future re-introduction if needed. - Update integration tests to match the corrected message ordering and the new global count after the ping removal. After this: - grep 'let _ = stream.write_all' main.rs: 0 - grep 'unreachable!' main.rs: 0 - grep 'xdg_wm_base_ping' in dispatch loop: 0 - cargo test integration_test: test_compositor_xdg_popup_lifecycle passes
This commit is contained in:
@@ -1804,9 +1804,6 @@ impl Compositor {
|
||||
if iface == "wl_seat" {
|
||||
self.send_seat_capabilities(client_id, stream, new_id, object_version)?;
|
||||
}
|
||||
if iface == "xdg_wm_base" {
|
||||
self.send_xdg_wm_base_ping(client_id, stream, new_id)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@@ -3605,6 +3602,7 @@ OBJECT_TYPE_WP_PRESENTATION_FEEDBACK => match opcode {
|
||||
self.write_event(client_id, stream, &msg, "xdg_popup.repositioned")
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn send_xdg_wm_base_ping(
|
||||
&self,
|
||||
client_id: u32,
|
||||
|
||||
@@ -3,11 +3,39 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::io::{Read, Write};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::process::{Child, Command};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
/// Owns a spawned compositor process and guarantees it is killed and reaped
|
||||
/// when dropped — including on test panic. Without this, a panicking test
|
||||
/// leaves the compositor child running; the child inherits the test binary's
|
||||
/// stdout pipe, which keeps any downstream pipe consumer (and `cargo test`
|
||||
/// itself) waiting for EOF indefinitely.
|
||||
struct CompositorGuard(Child);
|
||||
|
||||
impl Deref for CompositorGuard {
|
||||
type Target = Child;
|
||||
fn deref(&self) -> &Child {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for CompositorGuard {
|
||||
fn deref_mut(&mut self) -> &mut Child {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for CompositorGuard {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.0.kill();
|
||||
let _ = self.0.wait();
|
||||
}
|
||||
}
|
||||
|
||||
fn push_wayland_string(buf: &mut Vec<u8>, value: &str) {
|
||||
let bytes = value.as_bytes();
|
||||
buf.extend_from_slice(&((bytes.len() + 1) as u32).to_le_bytes());
|
||||
@@ -41,11 +69,20 @@ fn read_wayland_string(payload: &[u8], cursor: &mut usize) -> String {
|
||||
}
|
||||
|
||||
fn collect_globals(client: &mut WaylandClient, registry: u32) -> HashMap<String, (u32, u32)> {
|
||||
// A sync roundtrip is the canonical Wayland way to know every
|
||||
// registry.global event queued so far has been delivered: the
|
||||
// wl_callback.done reply lands after all already-sent events on the same
|
||||
// connection. This avoids a stale hardcoded global count that left
|
||||
// unconsumed registry events polluting later reads.
|
||||
let callback = client.sync().expect("wl_display.sync failed");
|
||||
let mut globals = HashMap::new();
|
||||
for _ in 0..9 {
|
||||
loop {
|
||||
let (object_id, opcode, payload) = client.read_message().expect("read global failed");
|
||||
assert_eq!(object_id, registry);
|
||||
assert_eq!(opcode, 0); // wl_registry.global
|
||||
if object_id == callback && opcode == 0 {
|
||||
break;
|
||||
}
|
||||
assert_eq!(object_id, registry, "expected wl_registry.global or the sync callback");
|
||||
assert_eq!(opcode, 0, "expected wl_registry.global");
|
||||
let name = u32::from_le_bytes([payload[0], payload[1], payload[2], payload[3]]);
|
||||
let mut cursor = 4;
|
||||
let iface = read_wayland_string(&payload, &mut cursor);
|
||||
@@ -141,7 +178,7 @@ impl WaylandClient {
|
||||
}
|
||||
}
|
||||
|
||||
fn start_compositor(socket_path: &str) -> Child {
|
||||
fn start_compositor(socket_path: &str) -> CompositorGuard {
|
||||
let compositor_bin = std::env::var("COMPOSITOR_BIN")
|
||||
.unwrap_or_else(|_| "target/debug/redbear-compositor".into());
|
||||
|
||||
@@ -162,7 +199,7 @@ fn start_compositor(socket_path: &str) -> Child {
|
||||
// CAP_SYS_RAWIO) and the compositor can bind its Wayland socket anywhere.
|
||||
.env("FRAMEBUFFER_ADDR", "0");
|
||||
|
||||
cmd.spawn().expect("failed to start compositor")
|
||||
CompositorGuard(cmd.spawn().expect("failed to start compositor"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -286,19 +323,10 @@ fn test_compositor_wl_fixes_destroy_registry() {
|
||||
|
||||
let registry = client.get_registry().expect("get_registry failed");
|
||||
|
||||
let mut fixes_name = 0u32;
|
||||
for _ in 0..9 {
|
||||
let (_, opcode, payload) = client.read_message().expect("read failed");
|
||||
assert_eq!(opcode, 0); // wl_registry.global
|
||||
let name = u32::from_le_bytes([payload[0], payload[1], payload[2], payload[3]]);
|
||||
let mut cursor = 4;
|
||||
let iface = read_wayland_string(&payload, &mut cursor);
|
||||
if iface == "wl_fixes" {
|
||||
fixes_name = name;
|
||||
}
|
||||
}
|
||||
|
||||
assert_ne!(fixes_name, 0, "wl_fixes global not found");
|
||||
let fixes_name = collect_globals(&mut client, registry)
|
||||
.get("wl_fixes")
|
||||
.map(|(name, _)| *name)
|
||||
.expect("wl_fixes global not found");
|
||||
|
||||
let fixes = client
|
||||
.bind(registry, fixes_name, "wl_fixes", 2)
|
||||
@@ -392,7 +420,8 @@ fn test_compositor_output_and_seat_metadata() {
|
||||
assert_eq!(object_id, seat_id);
|
||||
match opcode {
|
||||
0 => {
|
||||
assert_eq!(payload, 1u32.to_le_bytes());
|
||||
// capability bitfield: WL_SEAT_CAPABILITY_POINTER(1) | KEYBOARD(2)
|
||||
assert_eq!(payload, 3u32.to_le_bytes());
|
||||
saw_capabilities = true;
|
||||
}
|
||||
1 => {
|
||||
@@ -426,15 +455,10 @@ fn test_compositor_real_surface_opcodes() {
|
||||
let mut client = WaylandClient::connect(socket).expect("failed to connect");
|
||||
|
||||
let registry = client.get_registry().expect("get_registry failed");
|
||||
let mut globals = HashMap::new();
|
||||
for _ in 0..9 {
|
||||
let (_, opcode, payload) = client.read_message().expect("read failed");
|
||||
assert_eq!(opcode, 0); // wl_registry.global
|
||||
let name = u32::from_le_bytes([payload[0], payload[1], payload[2], payload[3]]);
|
||||
let mut cursor = 4;
|
||||
let iface = read_wayland_string(&payload, &mut cursor);
|
||||
globals.insert(iface, name);
|
||||
}
|
||||
let globals: HashMap<String, u32> = collect_globals(&mut client, registry)
|
||||
.into_iter()
|
||||
.map(|(k, (name, _))| (k, name))
|
||||
.collect();
|
||||
|
||||
let compositor_name = *globals
|
||||
.get("wl_compositor")
|
||||
@@ -499,15 +523,10 @@ fn test_compositor_xdg_popup_lifecycle() {
|
||||
let mut client = WaylandClient::connect(socket).expect("failed to connect");
|
||||
|
||||
let registry = client.get_registry().expect("get_registry failed");
|
||||
let mut globals = HashMap::new();
|
||||
for _ in 0..9 {
|
||||
let (_, opcode, payload) = client.read_message().expect("read failed");
|
||||
assert_eq!(opcode, 0); // wl_registry.global
|
||||
let name = u32::from_le_bytes([payload[0], payload[1], payload[2], payload[3]]);
|
||||
let mut cursor = 4;
|
||||
let iface = read_wayland_string(&payload, &mut cursor);
|
||||
globals.insert(iface, name);
|
||||
}
|
||||
let globals: HashMap<String, u32> = collect_globals(&mut client, registry)
|
||||
.into_iter()
|
||||
.map(|(k, (name, _))| (k, name))
|
||||
.collect();
|
||||
|
||||
let compositor_name = *globals
|
||||
.get("wl_compositor")
|
||||
|
||||
Reference in New Issue
Block a user