test: introspect Wayland globals exposés par le compositor

Mini-binaire redox-wl-test-introspect (~210 lignes) qui se connecte
au socket, énumère via wl_registry tous les globals advertised,
compare à un catalogue de 21 protocoles attendus par les toolkits
modernes (COSMIC, GTK4, Qt5) et rapporte présents / manquants
critiques / manquants optionnels.

Rapport runtime (docs/phase7-9-introspect-report.txt) :
- 4 présents : wl_compositor v5, wl_shm v1, wl_seat v7, xdg_wm_base v5
- 6 critiques manquants pour COSMIC :
  • wl_subcompositor   • wl_output   • wl_data_device_manager
  • zxdg_decoration_manager_v1   • zwp_linux_dmabuf_v1
  • zwlr_layer_shell_v1
- 11 optionnels manquants : viewporter, fractional_scale,
  presentation, tablet, primary_selection, output_manager,
  activation, cursor_shape, exporter, relative_pointer,
  pointer_constraints

Utilisé pour anticiper les manques avant d'attaquer COSMIC. Roadmap
proche : prioriser wl_output + wl_subcompositor + wl_data_device
(core 8.x), puis decoration + dmabuf + layer_shell pour COSMIC.

Leyoda 2026 – GPLv3
This commit is contained in:
Votre Nom 2026-05-13 21:29:37 +02:00
parent 1689b93d9b
commit 2150f31d82
3 changed files with 350 additions and 0 deletions

View file

@ -0,0 +1,9 @@
[package]
name = "redox-wl-test-introspect"
version = "0.1.0"
edition = "2021"
[dependencies]
wayland-client = { path = "../../../wayland-rs/wayland-client", default-features = false }
wayland-backend = { path = "../../../wayland-rs/wayland-backend", default-features = false }
libc = "0.2"

View file

@ -0,0 +1,279 @@
//! Introspection des globals Wayland exposés par le compositor.
//!
//! Se connecte à `/tmp/redox-wl-comp.sock`, fait un roundtrip pour
//! capturer tous les `wl_registry.global` events, puis :
//! 1. Liste les globals advertised (name + version)
//! 2. Compare à un catalogue de protocoles attendus pour
//! COSMIC / GTK4 / Qt5 / divers toolkits Wayland modernes
//! 3. Imprime un rapport OK / MISSING / EXTRA
//!
//! Sert à anticiper les manques avant d'attaquer un vrai toolkit.
use std::fs::OpenOptions;
use std::io::Write;
use std::os::unix::net::UnixStream;
use std::process::ExitCode;
use std::sync::{Mutex, OnceLock};
use std::thread;
use std::time::Duration;
use wayland_client::{
Connection, Dispatch, EventQueue, QueueHandle,
backend::Backend,
protocol::wl_registry,
};
const SOCKET_PATH: &str = "/tmp/redox-wl-comp.sock";
struct DebugSink(Mutex<Option<std::fs::File>>);
impl DebugSink {
fn new() -> Self {
Self(Mutex::new(
OpenOptions::new().write(true).open("/scheme/debug").ok(),
))
}
fn writeln(&self, s: &str) {
println!("{s}");
if let Ok(mut g) = self.0.lock() {
if let Some(f) = g.as_mut() {
let _ = writeln!(f, "{s}");
}
}
}
}
fn dlog(s: &str) {
static SINK: OnceLock<DebugSink> = OnceLock::new();
SINK.get_or_init(DebugSink::new).writeln(s);
}
#[derive(Default)]
struct Introspect {
globals: Vec<(String, u32)>,
}
impl Dispatch<wl_registry::WlRegistry, ()> for Introspect {
fn event(
state: &mut Self,
_r: &wl_registry::WlRegistry,
event: wl_registry::Event,
_data: &(),
_conn: &Connection,
_qh: &QueueHandle<Self>,
) {
if let wl_registry::Event::Global {
name: _,
interface,
version,
} = event
{
state.globals.push((interface, version));
}
}
}
/// Catalogue de protocoles attendus par les toolkits modernes.
/// Le 3e élément est une description courte de pourquoi c'est utile.
const EXPECTED: &[(&str, &str, &str)] = &[
// --- core wayland ---
("wl_compositor", "core", "surfaces + regions"),
("wl_shm", "core", "shared memory buffers"),
("wl_seat", "core", "input devices (kbd/ptr)"),
("wl_subcompositor", "core", "sub-surfaces"),
("wl_output", "core", "monitors info (geometry, scale, mode)"),
("wl_data_device_manager", "core", "clipboard + DnD"),
// --- xdg-shell ---
("xdg_wm_base", "stable", "window management (toplevel + popup)"),
// --- protocoles externes très demandés ---
(
"zxdg_decoration_manager_v1",
"unstable v1",
"CSD vs SSD — GTK/Qt négocient ici qui dessine la barre de titre",
),
(
"wp_viewporter",
"stable",
"HiDPI cropping/scaling — beaucoup de toolkits l'utilisent",
),
(
"wp_fractional_scale_manager_v1",
"v1",
"fractional scaling (125%, 150%) — COSMIC, GNOME récent",
),
(
"zwp_linux_dmabuf_v1",
"unstable v1",
"dmabuf import (GPU buffers) — requis pour tout GL/Vulkan",
),
(
"wp_presentation",
"stable",
"timing précis de présentation — média players, jeux",
),
(
"zwp_tablet_manager_v2",
"unstable v2",
"tablettes graphiques + stylus",
),
(
"zwp_primary_selection_device_manager_v1",
"unstable v1",
"clipboard middle-click (style X11)",
),
(
"zxdg_output_manager_v1",
"unstable v1",
"monitor info riche (xdg_output : logical position + size)",
),
(
"zwlr_layer_shell_v1",
"wlroots v1",
"barres de tâches / overlays — REQUIS pour COSMIC panel",
),
(
"xdg_activation_v1",
"v1",
"focus stealing prevention — toolkits modernes",
),
(
"wp_cursor_shape_manager_v1",
"v1",
"curseurs serveur-side (alternative à set_cursor)",
),
(
"zxdg_exporter_v2",
"unstable v2",
"exporter de handle pour foreign-toplevel",
),
(
"zwp_relative_pointer_manager_v1",
"unstable v1",
"pointeur relatif (jeux, FPS)",
),
(
"zwp_pointer_constraints_v1",
"unstable v1",
"lock/confine pointer (jeux)",
),
];
fn run() -> Result<(), Box<dyn std::error::Error>> {
dlog("[introspect] connect to compositor");
for _ in 0..50 {
if std::path::Path::new(SOCKET_PATH).exists() {
break;
}
thread::sleep(Duration::from_millis(100));
}
let stream = UnixStream::connect(SOCKET_PATH)?;
let backend = Backend::connect(stream)?;
let conn = Connection::from_backend(backend);
let mut event_queue: EventQueue<Introspect> = conn.new_event_queue();
let qh = event_queue.handle();
let _registry = conn.display().get_registry(&qh, ());
let mut state = Introspect::default();
// 2 roundtrips pour être sûr d'avoir tous les globals (le serveur
// peut les advertise en plusieurs batches)
event_queue.roundtrip(&mut state)?;
event_queue.roundtrip(&mut state)?;
dlog("");
dlog("==================================================");
dlog("Introspection compositor Wayland — rapport");
dlog("==================================================");
dlog("");
dlog(&format!(
"Globals annoncés par le compositor ({}):",
state.globals.len()
));
let mut sorted: Vec<(String, u32)> = state.globals.clone();
sorted.sort_by(|a, b| a.0.cmp(&b.0));
for (iface, ver) in &sorted {
dlog(&format!("{iface} v{ver}"));
}
dlog("");
dlog("Comparaison au catalogue COSMIC/GTK4/Qt5 :");
dlog("");
let mut present_count = 0usize;
let mut missing_critical = Vec::new();
let mut missing_optional = Vec::new();
for (iface, kind, why) in EXPECTED {
let found = state.globals.iter().find(|(i, _)| i == iface);
match found {
Some((_, v)) => {
dlog(&format!(" [ OK ] {iface} v{v}{why}"));
present_count += 1;
}
None => {
let line = format!(" [MISS] {iface} ({kind}) — {why}");
dlog(&line);
// Critiques pour COSMIC = layer-shell + dmabuf + decoration
if iface.contains("layer_shell")
|| iface.contains("dmabuf")
|| iface.contains("decoration")
|| iface.contains("data_device")
|| iface.contains("wl_output")
|| iface.contains("wl_subcompositor")
{
missing_critical.push(*iface);
} else {
missing_optional.push(*iface);
}
}
}
}
// Globaux exposés non listés (potentiellement spécifiques au compositor)
let extras: Vec<&(String, u32)> = state
.globals
.iter()
.filter(|(i, _)| !EXPECTED.iter().any(|(e, _, _)| e == i))
.collect();
if !extras.is_empty() {
dlog("");
dlog("Globaux exposés hors catalogue (custom / non listés ici) :");
for (i, v) in &extras {
dlog(&format!("{i} v{v}"));
}
}
dlog("");
dlog("==================================================");
dlog(&format!(
"RÉSUMÉ : {} présents / {} attendus",
present_count,
EXPECTED.len()
));
dlog(&format!(
" ❌ Critiques manquants pour COSMIC : {}",
missing_critical.len()
));
for i in &missing_critical {
dlog(&format!(" - {i}"));
}
dlog(&format!(
" ⚠ Optionnels manquants (toolkits dégradent) : {}",
missing_optional.len()
));
for i in &missing_optional {
dlog(&format!(" - {i}"));
}
dlog("==================================================");
Ok(())
}
fn main() -> ExitCode {
match run() {
Ok(()) => {
dlog("[introspect] PASS");
ExitCode::SUCCESS
}
Err(e) => {
dlog(&format!("[introspect] FAIL: {e}"));
ExitCode::FAILURE
}
}
}

View file

@ -0,0 +1,62 @@
QEMU done
==================================================
[introspect] connect to compositor
==================================================
Introspection compositor Wayland — rapport
==================================================
Globals annoncés par le compositor (4):
• wl_compositor v5
• wl_seat v7
• wl_shm v1
• xdg_wm_base v5
Comparaison au catalogue COSMIC/GTK4/Qt5 :
[ OK ] wl_compositor v5 — surfaces + regions
[ OK ] wl_shm v1 — shared memory buffers
[ OK ] wl_seat v7 — input devices (kbd/ptr)
[MISS] wl_subcompositor (core) — sub-surfaces
[MISS] wl_output (core) — monitors info (geometry, scale, mode)
[MISS] wl_data_device_manager (core) — clipboard + DnD
[ OK ] xdg_wm_base v5 — window management (toplevel + popup)
[MISS] zxdg_decoration_manager_v1 (unstable v1) — CSD vs SSD — GTK/Qt négocient ici qui dessine la barre de titre
[MISS] wp_viewporter (stable) — HiDPI cropping/scaling — beaucoup de toolkits l'utilisent
[MISS] wp_fractional_scale_manager_v1 (v1) — fractional scaling (125%, 150%) — COSMIC, GNOME récent
[MISS] zwp_linux_dmabuf_v1 (unstable v1) — dmabuf import (GPU buffers) — requis pour tout GL/Vulkan
[MISS] wp_presentation (stable) — timing précis de présentation — média players, jeux
[MISS] zwp_tablet_manager_v2 (unstable v2) — tablettes graphiques + stylus
[MISS] zwp_primary_selection_device_manager_v1 (unstable v1) — clipboard middle-click (style X11)
[MISS] zxdg_output_manager_v1 (unstable v1) — monitor info riche (xdg_output : logical position + size)
[MISS] zwlr_layer_shell_v1 (wlroots v1) — barres de tâches / overlays — REQUIS pour COSMIC panel
[MISS] xdg_activation_v1 (v1) — focus stealing prevention — toolkits modernes
[MISS] wp_cursor_shape_manager_v1 (v1) — curseurs serveur-side (alternative à set_cursor)
[MISS] zxdg_exporter_v2 (unstable v2) — exporter de handle pour foreign-toplevel
[MISS] zwp_relative_pointer_manager_v1 (unstable v1) — pointeur relatif (jeux, FPS)
[MISS] zwp_pointer_constraints_v1 (unstable v1) — lock/confine pointer (jeux)
==================================================
RÉSUMÉ : 4 présents / 21 attendus
❌ Critiques manquants pour COSMIC : 6
- wl_subcompositor
- wl_output
- wl_data_device_manager
- zxdg_decoration_manager_v1
- zwp_linux_dmabuf_v1
- zwlr_layer_shell_v1
⚠ Optionnels manquants (toolkits dégradent) : 11
- wp_viewporter
- wp_fractional_scale_manager_v1
- wp_presentation
- zwp_tablet_manager_v2
- zwp_primary_selection_device_manager_v1
- zxdg_output_manager_v1
- xdg_activation_v1
- wp_cursor_shape_manager_v1
- zxdg_exporter_v2
- zwp_relative_pointer_manager_v1
- zwp_pointer_constraints_v1
==================================================
[introspect] PASS
==================================================