Phase 13.2.b.1 — wl_subcompositor protocole (sans rendering)
Implémentation minimale du global wl_subcompositor v1 côté compositor. Couvre uniquement le protocole : bind, GetSubsurface, et tous les requests wl_subsurface (SetPosition, PlaceAbove/Below, SetSync/SetDesync, Destroy). Les données sont stockées dans SubsurfaceData mais ne sont pas encore consommées par le rendering — c'est le scope de 13.2.b.2. Ce qui marche maintenant : - Un client qui bind wl_subcompositor le trouve à v1 - get_subsurface(child, parent) ne crashe pas, retourne un wl_subsurface valide avec SubsurfaceData attaché (parent ref, child ref, position pending, sync mode default true) - Toutes les requests subséquentes sont acceptées sans erreur protocole - destroy : no-op propre (la resource est nettoyée par wayland-server) Limitations explicites pour 13.2.b.2 : - Pas de role-tracking (la spec exige bad_surface si la wl_surface enfant a déjà un rôle ; on log debug seulement) - Pas de cascade sync : un commit du parent ne propage pas les states pending des subsurfaces - PlaceAbove/Below : no-op (single-subsurface use-case suffit pour 13.2.b) - compose_into ne sait pas dessiner les subsurfaces Test natif (cargo test, sans QEMU) : - Vérifie l'annonce du global à v1 - Bind + create_surface ×2 + get_subsurface + tous les requests wl_subsurface successifs + destroy - Roundtrip à chaque étape pour capter d'éventuelles erreurs protocole - PASS le 2026-05-16 sur CachyOS Leyoda 2026 – GPLv3
This commit is contained in:
parent
7413745dbe
commit
f9c3de13da
2 changed files with 518 additions and 1 deletions
364
crates/redox-wl-test-wl-output/tests/subcompositor_native.rs
Normal file
364
crates/redox-wl-test-wl-output/tests/subcompositor_native.rs
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
//! Test natif (CachyOS, hors QEMU) : wl_subcompositor protocole (phase
|
||||
//! 13.2.b.1).
|
||||
//!
|
||||
//! Vérifie que :
|
||||
//! 1. `wl_subcompositor` est annoncé comme global à v1
|
||||
//! 2. Le bind du global réussit
|
||||
//! 3. `get_subsurface(child, parent)` instancie un `wl_subsurface` sans
|
||||
//! erreur protocole
|
||||
//! 4. `set_position`, `set_sync`, `set_desync` ne génèrent pas d'erreur
|
||||
//! 5. `destroy` sur le wl_subsurface ne génère pas d'erreur
|
||||
//!
|
||||
//! Logique serveur dupliquée verbatim de redox-wl-wayland-frontend/src/lib.rs
|
||||
//! (GlobalDispatch + Dispatch pour wl_subcompositor et wl_subsurface +
|
||||
//! minimum pour wl_compositor pour pouvoir créer 2 wl_surfaces).
|
||||
//!
|
||||
//! Si une erreur protocole est envoyée (bad_surface, etc.), wayland-client
|
||||
//! propage en error sur l'event_queue, et le test panique avec un message
|
||||
//! clair.
|
||||
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use wayland_server::backend::{ClientData, ClientId, DisconnectReason};
|
||||
use wayland_server::{
|
||||
protocol::{
|
||||
wl_compositor as srv_wl_compositor, wl_subcompositor as srv_wl_subcompositor,
|
||||
wl_subsurface as srv_wl_subsurface, wl_surface as srv_wl_surface,
|
||||
},
|
||||
Client as SrvClient, DataInit, Display, DisplayHandle, GlobalDispatch,
|
||||
};
|
||||
|
||||
use wayland_client::{
|
||||
backend::Backend,
|
||||
protocol::{wl_compositor, wl_registry, wl_subcompositor, wl_subsurface, wl_surface},
|
||||
Connection, Dispatch as CliDispatch, QueueHandle,
|
||||
};
|
||||
|
||||
const COMPOSITOR_VERSION: u32 = 5;
|
||||
const SUBCOMPOSITOR_VERSION: u32 = 1;
|
||||
|
||||
// ============= server-side: state minimal =============
|
||||
|
||||
struct ServerState;
|
||||
|
||||
struct StubClientData;
|
||||
impl ClientData for StubClientData {
|
||||
fn initialized(&self, _: ClientId) {}
|
||||
fn disconnected(&self, _: ClientId, _: DisconnectReason) {}
|
||||
}
|
||||
|
||||
// Données par-wl_subsurface, duplicate de notre prod code.
|
||||
#[allow(dead_code)]
|
||||
struct SubsurfaceData {
|
||||
parent: srv_wl_surface::WlSurface,
|
||||
child: srv_wl_surface::WlSurface,
|
||||
position: Mutex<(i32, i32)>,
|
||||
sync: AtomicBool,
|
||||
}
|
||||
|
||||
// --- wl_compositor (minimum pour fabriquer des wl_surfaces) ---
|
||||
|
||||
impl GlobalDispatch<srv_wl_compositor::WlCompositor, ()> for ServerState {
|
||||
fn bind(
|
||||
_state: &mut Self,
|
||||
_handle: &DisplayHandle,
|
||||
_client: &SrvClient,
|
||||
resource: wayland_server::New<srv_wl_compositor::WlCompositor>,
|
||||
_data: &(),
|
||||
data_init: &mut DataInit<'_, Self>,
|
||||
) {
|
||||
data_init.init(resource, ());
|
||||
}
|
||||
}
|
||||
|
||||
impl wayland_server::Dispatch<srv_wl_compositor::WlCompositor, ()> for ServerState {
|
||||
fn request(
|
||||
_state: &mut Self,
|
||||
_client: &SrvClient,
|
||||
_r: &srv_wl_compositor::WlCompositor,
|
||||
request: srv_wl_compositor::Request,
|
||||
_data: &(),
|
||||
_dh: &DisplayHandle,
|
||||
data_init: &mut DataInit<'_, Self>,
|
||||
) {
|
||||
if let srv_wl_compositor::Request::CreateSurface { id } = request {
|
||||
data_init.init(id, ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl wayland_server::Dispatch<srv_wl_surface::WlSurface, ()> for ServerState {
|
||||
fn request(
|
||||
_state: &mut Self,
|
||||
_client: &SrvClient,
|
||||
_r: &srv_wl_surface::WlSurface,
|
||||
_request: srv_wl_surface::Request,
|
||||
_data: &(),
|
||||
_dh: &DisplayHandle,
|
||||
_data_init: &mut DataInit<'_, Self>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
// --- wl_subcompositor (sous test) ---
|
||||
|
||||
impl GlobalDispatch<srv_wl_subcompositor::WlSubcompositor, ()> for ServerState {
|
||||
fn bind(
|
||||
_state: &mut Self,
|
||||
_handle: &DisplayHandle,
|
||||
_client: &SrvClient,
|
||||
resource: wayland_server::New<srv_wl_subcompositor::WlSubcompositor>,
|
||||
_data: &(),
|
||||
data_init: &mut DataInit<'_, Self>,
|
||||
) {
|
||||
data_init.init(resource, ());
|
||||
}
|
||||
}
|
||||
|
||||
impl wayland_server::Dispatch<srv_wl_subcompositor::WlSubcompositor, ()> for ServerState {
|
||||
fn request(
|
||||
_state: &mut Self,
|
||||
_client: &SrvClient,
|
||||
_r: &srv_wl_subcompositor::WlSubcompositor,
|
||||
request: srv_wl_subcompositor::Request,
|
||||
_data: &(),
|
||||
_dh: &DisplayHandle,
|
||||
data_init: &mut DataInit<'_, Self>,
|
||||
) {
|
||||
match request {
|
||||
srv_wl_subcompositor::Request::Destroy => {}
|
||||
srv_wl_subcompositor::Request::GetSubsurface {
|
||||
id,
|
||||
surface,
|
||||
parent,
|
||||
} => {
|
||||
let data = Arc::new(SubsurfaceData {
|
||||
parent,
|
||||
child: surface,
|
||||
position: Mutex::new((0, 0)),
|
||||
sync: AtomicBool::new(true),
|
||||
});
|
||||
data_init.init(id, data);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl wayland_server::Dispatch<srv_wl_subsurface::WlSubsurface, Arc<SubsurfaceData>>
|
||||
for ServerState
|
||||
{
|
||||
fn request(
|
||||
_state: &mut Self,
|
||||
_client: &SrvClient,
|
||||
_r: &srv_wl_subsurface::WlSubsurface,
|
||||
request: srv_wl_subsurface::Request,
|
||||
data: &Arc<SubsurfaceData>,
|
||||
_dh: &DisplayHandle,
|
||||
_data_init: &mut DataInit<'_, Self>,
|
||||
) {
|
||||
match request {
|
||||
srv_wl_subsurface::Request::Destroy => {}
|
||||
srv_wl_subsurface::Request::SetPosition { x, y } => {
|
||||
*data.position.lock().unwrap() = (x, y);
|
||||
}
|
||||
srv_wl_subsurface::Request::PlaceAbove { sibling: _ }
|
||||
| srv_wl_subsurface::Request::PlaceBelow { sibling: _ } => {}
|
||||
srv_wl_subsurface::Request::SetSync => {
|
||||
data.sync.store(true, Ordering::Relaxed);
|
||||
}
|
||||
srv_wl_subsurface::Request::SetDesync => {
|
||||
data.sync.store(false, Ordering::Relaxed);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============= client-side =============
|
||||
|
||||
#[derive(Default)]
|
||||
struct ClientState {
|
||||
compositor_global: Option<u32>,
|
||||
subcompositor_global: Option<u32>,
|
||||
subcompositor_version: Option<u32>,
|
||||
last_error: Option<String>,
|
||||
}
|
||||
|
||||
impl CliDispatch<wl_registry::WlRegistry, ()> for ClientState {
|
||||
fn event(
|
||||
state: &mut Self,
|
||||
_: &wl_registry::WlRegistry,
|
||||
event: wl_registry::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
if let wl_registry::Event::Global {
|
||||
name,
|
||||
interface,
|
||||
version,
|
||||
} = event
|
||||
{
|
||||
if interface == "wl_compositor" {
|
||||
state.compositor_global = Some(name);
|
||||
} else if interface == "wl_subcompositor" {
|
||||
state.subcompositor_global = Some(name);
|
||||
state.subcompositor_version = Some(version);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CliDispatch<wl_compositor::WlCompositor, ()> for ClientState {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
_: &wl_compositor::WlCompositor,
|
||||
_: wl_compositor::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl CliDispatch<wl_surface::WlSurface, ()> for ClientState {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
_: &wl_surface::WlSurface,
|
||||
_: wl_surface::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl CliDispatch<wl_subcompositor::WlSubcompositor, ()> for ClientState {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
_: &wl_subcompositor::WlSubcompositor,
|
||||
_: wl_subcompositor::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl CliDispatch<wl_subsurface::WlSubsurface, ()> for ClientState {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
_: &wl_subsurface::WlSubsurface,
|
||||
_: wl_subsurface::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
// ============= test =============
|
||||
|
||||
#[test]
|
||||
fn wl_subcompositor_protocol_full_cycle() {
|
||||
let (s_stream, c_stream) = UnixStream::pair().expect("UnixStream::pair");
|
||||
|
||||
let server_thread = thread::spawn(move || {
|
||||
let mut display: Display<ServerState> = Display::new().unwrap();
|
||||
let dh = display.handle();
|
||||
dh.create_global::<ServerState, srv_wl_compositor::WlCompositor, _>(
|
||||
COMPOSITOR_VERSION,
|
||||
(),
|
||||
);
|
||||
dh.create_global::<ServerState, srv_wl_subcompositor::WlSubcompositor, _>(
|
||||
SUBCOMPOSITOR_VERSION,
|
||||
(),
|
||||
);
|
||||
|
||||
s_stream.set_nonblocking(true).unwrap();
|
||||
let _client = display
|
||||
.handle()
|
||||
.insert_client(s_stream, Arc::new(StubClientData))
|
||||
.unwrap();
|
||||
|
||||
let mut state = ServerState;
|
||||
let start = std::time::Instant::now();
|
||||
while start.elapsed() < Duration::from_secs(5) {
|
||||
let _ = display.dispatch_clients(&mut state);
|
||||
let _ = display.flush_clients();
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
});
|
||||
|
||||
c_stream.set_nonblocking(false).unwrap();
|
||||
let backend = Backend::connect(c_stream).unwrap();
|
||||
let conn = Connection::from_backend(backend);
|
||||
let mut event_queue = conn.new_event_queue::<ClientState>();
|
||||
let qh = event_queue.handle();
|
||||
let display = conn.display();
|
||||
let _reg = display.get_registry(&qh, ());
|
||||
|
||||
let mut state = ClientState::default();
|
||||
event_queue
|
||||
.roundtrip(&mut state)
|
||||
.expect("roundtrip registry");
|
||||
|
||||
// 1. Vérifs annonces globals
|
||||
let compositor_name = state.compositor_global.expect("wl_compositor non annoncé");
|
||||
let subcomp_name = state
|
||||
.subcompositor_global
|
||||
.expect("wl_subcompositor non annoncé");
|
||||
assert_eq!(
|
||||
state.subcompositor_version,
|
||||
Some(1),
|
||||
"wl_subcompositor doit être annoncé à v1, got {:?}",
|
||||
state.subcompositor_version
|
||||
);
|
||||
|
||||
// 2. Bind wl_compositor pour créer 2 surfaces
|
||||
let registry = display.get_registry(&qh, ());
|
||||
let compositor =
|
||||
registry.bind::<wl_compositor::WlCompositor, _, _>(compositor_name, 5, &qh, ());
|
||||
let parent = compositor.create_surface(&qh, ());
|
||||
let child = compositor.create_surface(&qh, ());
|
||||
|
||||
// 3. Bind wl_subcompositor + get_subsurface
|
||||
let subcomp =
|
||||
registry.bind::<wl_subcompositor::WlSubcompositor, _, _>(subcomp_name, 1, &qh, ());
|
||||
let subsurface = subcomp.get_subsurface(&child, &parent, &qh, ());
|
||||
|
||||
// 4. Exercer set_position / set_sync / set_desync
|
||||
subsurface.set_position(50, 50);
|
||||
subsurface.set_sync();
|
||||
subsurface.set_desync();
|
||||
subsurface.place_above(&parent); // valable même si parent n'est pas sibling — on no-op côté serveur
|
||||
subsurface.set_position(100, 100);
|
||||
|
||||
// 5. Roundtrip pour driver tous les events et capter d'éventuelles erreurs
|
||||
for _ in 0..5 {
|
||||
event_queue
|
||||
.roundtrip(&mut state)
|
||||
.expect("roundtrip pendant exercise");
|
||||
}
|
||||
|
||||
// 6. Destroy
|
||||
subsurface.destroy();
|
||||
event_queue
|
||||
.roundtrip(&mut state)
|
||||
.expect("roundtrip après destroy");
|
||||
|
||||
// 7. Cleanup
|
||||
drop(conn);
|
||||
server_thread.join().unwrap();
|
||||
|
||||
assert!(
|
||||
state.last_error.is_none(),
|
||||
"Erreur protocole détectée : {:?}",
|
||||
state.last_error
|
||||
);
|
||||
}
|
||||
|
|
@ -37,7 +37,7 @@ use wayland_server::{
|
|||
backend::{ClientData, ClientId, DisconnectReason},
|
||||
protocol::{
|
||||
wl_buffer, wl_callback, wl_compositor, wl_keyboard, wl_output, wl_pointer, wl_region,
|
||||
wl_seat, wl_shm, wl_shm_pool, wl_surface,
|
||||
wl_seat, wl_shm, wl_shm_pool, wl_subcompositor, wl_subsurface, wl_surface,
|
||||
},
|
||||
Client, DataInit, Display as WlDisplay, DisplayHandle, GlobalDispatch, Resource,
|
||||
};
|
||||
|
|
@ -51,6 +51,11 @@ const SEAT_VERSION: u32 = 7;
|
|||
// Phase 13.2.a : wl_output v3 (couvre geometry + mode + scale + done +
|
||||
// release request, sans v4 name/description qu'on ne fournit pas encore).
|
||||
const OUTPUT_VERSION: u32 = 3;
|
||||
// Phase 13.2.b.1 : wl_subcompositor v1 (la seule version qui existe ;
|
||||
// pas d'évolution depuis l'introduction du protocole). Implémentation
|
||||
// "protocole only" — bind + handlers ACK les requests, mais le rendering
|
||||
// des subsurfaces sera wiré en 13.2.b.2.
|
||||
const SUBCOMPOSITOR_VERSION: u32 = 1;
|
||||
|
||||
/// Taille suggérée par défaut pour les nouvelles fenêtres xdg_toplevel.
|
||||
/// Le client peut respecter ou non ; on utilise sa propre taille de buffer
|
||||
|
|
@ -193,6 +198,23 @@ struct XdgSurfaceData {
|
|||
acked_serial: Mutex<u32>,
|
||||
}
|
||||
|
||||
/// Phase 13.2.b.1 — Données par-wl_subsurface.
|
||||
///
|
||||
/// État protocolaire d'une subsurface : référence vers sa surface enfant
|
||||
/// et son parent, position en pending (modifiable via SetPosition),
|
||||
/// mode sync/desync. Pour 13.2.b.1 ces valeurs sont stockées mais pas
|
||||
/// encore consommées par compose_into (rendering wiré en 13.2.b.2).
|
||||
///
|
||||
/// Sync mode : default = true (synchronized) per spec. En mode sync,
|
||||
/// les changements de la subsurface n'apparaissent qu'au commit du
|
||||
/// parent. En desync, ils apparaissent au commit de la subsurface elle-même.
|
||||
struct SubsurfaceData {
|
||||
parent: wl_surface::WlSurface,
|
||||
child: wl_surface::WlSurface,
|
||||
position: Mutex<(i32, i32)>,
|
||||
sync: AtomicBool,
|
||||
}
|
||||
|
||||
/// Données par-xdg_toplevel : title, app_id, ref vers son xdg_surface.
|
||||
#[derive(Default)]
|
||||
struct XdgToplevelData {
|
||||
|
|
@ -442,6 +464,12 @@ impl WaylandFrontend {
|
|||
// mode/scale/done) sont envoyés dans le bind, cf GlobalDispatch
|
||||
// plus bas.
|
||||
dh.create_global::<Self, wl_output::WlOutput, _>(OUTPUT_VERSION, ());
|
||||
// Phase 13.2.b.1 : wl_subcompositor pour les surfaces parent-enfant.
|
||||
// Bind + acceptation des requests, pas encore de rendering (13.2.b.2).
|
||||
dh.create_global::<Self, wl_subcompositor::WlSubcompositor, _>(
|
||||
SUBCOMPOSITOR_VERSION,
|
||||
(),
|
||||
);
|
||||
|
||||
let listener = wayland_server::ListeningSocket::bind_absolute(socket_path.to_path_buf())?;
|
||||
|
||||
|
|
@ -2247,6 +2275,131 @@ impl wayland_server::Dispatch<wl_output::WlOutput, ()> for WaylandFrontend {
|
|||
}
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// wl_subcompositor / wl_subsurface (phase 13.2.b.1)
|
||||
// =====================================================================
|
||||
//
|
||||
// Scope 13.2.b.1 : implémentation protocolaire uniquement. On accepte le
|
||||
// bind du global, on instancie wl_subsurface dans GetSubsurface et on
|
||||
// route correctement les requests SetPosition / PlaceAbove,Below /
|
||||
// SetSync,Desync / Destroy. La donnée est stockée dans SubsurfaceData.
|
||||
//
|
||||
// Ce qui N'est PAS fait ici (reporté à 13.2.b.2) :
|
||||
// - rendering effectif des subsurfaces (compose_into ignore encore les
|
||||
// SubsurfaceData associés aux SurfaceData enfants) ;
|
||||
// - hit-test des subsurfaces ;
|
||||
// - cascade sync : un commit du parent doit valider tous les state
|
||||
// pending des subsurfaces en mode sync ;
|
||||
// - vérification du « rôle unique » (spec : une wl_surface ne peut
|
||||
// avoir qu'un seul rôle de vie ; on devrait refuser GetSubsurface
|
||||
// sur une surface déjà-xdg_toplevel). Pour l'instant on log un warn
|
||||
// si on détecte le cas, mais on n'envoie pas bad_surface.
|
||||
|
||||
impl GlobalDispatch<wl_subcompositor::WlSubcompositor, ()> for WaylandFrontend {
|
||||
fn bind(
|
||||
_state: &mut Self,
|
||||
_handle: &DisplayHandle,
|
||||
_client: &Client,
|
||||
resource: wayland_server::New<wl_subcompositor::WlSubcompositor>,
|
||||
_data: &(),
|
||||
data_init: &mut DataInit<'_, Self>,
|
||||
) {
|
||||
data_init.init(resource, ());
|
||||
}
|
||||
}
|
||||
|
||||
impl wayland_server::Dispatch<wl_subcompositor::WlSubcompositor, ()> for WaylandFrontend {
|
||||
fn request(
|
||||
_state: &mut Self,
|
||||
_client: &Client,
|
||||
_r: &wl_subcompositor::WlSubcompositor,
|
||||
request: wl_subcompositor::Request,
|
||||
_data: &(),
|
||||
_dh: &DisplayHandle,
|
||||
data_init: &mut DataInit<'_, Self>,
|
||||
) {
|
||||
match request {
|
||||
wl_subcompositor::Request::Destroy => {
|
||||
// No-op : wayland-server nettoie la resource automatiquement.
|
||||
}
|
||||
wl_subcompositor::Request::GetSubsurface {
|
||||
id,
|
||||
surface,
|
||||
parent,
|
||||
} => {
|
||||
// Vérif soft : rôle déjà attribué ? (xdg_toplevel notamment).
|
||||
// Pour 13.2.b.1 on se contente de logger ; le protocole exige
|
||||
// un bad_surface error mais on attendra 13.2.b.2 pour
|
||||
// l'enforcer car ça touche au design role-tracking.
|
||||
if let Some(child_data) = surface.data::<Arc<SurfaceData>>() {
|
||||
let id_lock = child_data.id.lock().unwrap();
|
||||
if id_lock.is_some() {
|
||||
// La surface a déjà été registered comme toplevel ?
|
||||
// Hmm, en fait avoir un SurfaceId ne signifie pas un
|
||||
// rôle xdg — c'est juste qu'elle vit dans le registry.
|
||||
// On ne fait rien de plus que log debug.
|
||||
tracing::debug!(
|
||||
"GetSubsurface: surface child déjà dans registry (id={:?})",
|
||||
*id_lock
|
||||
);
|
||||
}
|
||||
}
|
||||
let data = Arc::new(SubsurfaceData {
|
||||
parent,
|
||||
child: surface,
|
||||
position: Mutex::new((0, 0)),
|
||||
sync: AtomicBool::new(true), // default = sync per spec
|
||||
});
|
||||
data_init.init(id, data);
|
||||
tracing::debug!("wl_subcompositor.get_subsurface: subsurface créée");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl wayland_server::Dispatch<wl_subsurface::WlSubsurface, Arc<SubsurfaceData>>
|
||||
for WaylandFrontend
|
||||
{
|
||||
fn request(
|
||||
_state: &mut Self,
|
||||
_client: &Client,
|
||||
_r: &wl_subsurface::WlSubsurface,
|
||||
request: wl_subsurface::Request,
|
||||
data: &Arc<SubsurfaceData>,
|
||||
_dh: &DisplayHandle,
|
||||
_data_init: &mut DataInit<'_, Self>,
|
||||
) {
|
||||
match request {
|
||||
wl_subsurface::Request::Destroy => {
|
||||
// Spec : la wl_surface enfant est unmapped immédiatement,
|
||||
// perd sa position et son z-order. Pour 13.2.b.1 on no-op
|
||||
// (pas de mapping registered, donc rien à unmap côté
|
||||
// rendering qui n'existe pas encore).
|
||||
}
|
||||
wl_subsurface::Request::SetPosition { x, y } => {
|
||||
*data.position.lock().unwrap() = (x, y);
|
||||
tracing::debug!("wl_subsurface.set_position({x}, {y})");
|
||||
}
|
||||
wl_subsurface::Request::PlaceAbove { sibling: _ }
|
||||
| wl_subsurface::Request::PlaceBelow { sibling: _ } => {
|
||||
// z-order relatif entre subsurfaces siblings.
|
||||
// Single-subsurface use-case 13.2.b.1 : no-op.
|
||||
tracing::debug!("wl_subsurface.place_above/below (no-op pour 13.2.b.1)");
|
||||
}
|
||||
wl_subsurface::Request::SetSync => {
|
||||
data.sync.store(true, Ordering::Relaxed);
|
||||
tracing::debug!("wl_subsurface.set_sync");
|
||||
}
|
||||
wl_subsurface::Request::SetDesync => {
|
||||
data.sync.store(false, Ordering::Relaxed);
|
||||
tracing::debug!("wl_subsurface.set_desync");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Tests unitaires xdg-shell (sprint 0 point 4).
|
||||
//
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue