🎉 Phase 7.7 — move interactif xdg_toplevel validé runtime
Move interactif complet (Resize en stub log-only, reportable à 7.8).
Frontend additions :
- enum DragMode { Move, Resize(u32) } et struct InteractiveDrag
{ surface_id, xdg_toplevel_res, xdg_surface_res, mode,
start_cursor_x/y, start_x/y, start_w/h }
- WaylandFrontend : interactive_drag: Option<InteractiveDrag> +
last_button_serial: u32
- XdgToplevelData.xdg_surface: Mutex<Option<XdgSurface>> peuplé
dans xdg_surface.GetToplevel pour retrouver le wl_surface parent
depuis un toplevel.move/resize
- Handler xdg_toplevel.Move : valide serial != 0, refuse drag déjà
actif, retrouve SurfaceId via cascade UserData (xdg_surface →
wl_surface → SurfaceData), capture start_cursor + start_geom,
stocke InteractiveDrag
- Handler xdg_toplevel.Resize : stub log-only (à compléter 7.8)
- Handler xdg_toplevel.Destroy nettoie interactive_drag si on était
en train de drag cette surface
- Méthode apply_interactive_drag() : applique le delta (cursor -
start_cursor) à la position de la surface (Move) ou consume le
motion (Resize stub)
- forward_input(PointerMotion(Relative)) : apply au début, return
si drag actif (court-circuite l'envoi de motion au client pendant
un drag, conforme spec Wayland)
- forward_input(PointerButton release) : sort du mode drag
- set_cursor_position : appelle aussi apply_interactive_drag (sans
ça, les cycles de test programmatique ne déclenchent pas le drag
car ils court-circuitent forward_input)
- Tracking last_button_serial à chaque button LEFT Pressed
Test client modifications :
- redox-wl-test-client-shm-two bind wl_seat
- Si label=="A", déclenche toplevel.move(&seat, 1) 8s après le
commit initial (mécanisme "synthétique" : le client n'écoute pas
les pointer events, il envoie Move sans attendre un clic — assez
pour valider le pipeline serveur, durcissement client 7.8)
Validation runtime :
- Cycle compositor temporaire (retiré du binaire final) qui change
cursor_position à plusieurs positions pendant que le drag est
actif, screendumps à 3 positions distinctes
- Logs frontend :
[frontend] xdg_toplevel.move: enter drag sid=SurfaceId(0) start=(60,60) cursor=(500,400)
[frontend] left-release → exit interactive drag
- A déplacée visuellement entre les captures pos1, pos2 et
post-release ; sortie clipée sur les bords (pas de snap-to-edge,
WM policy reportable)
Limitations 7.7 :
- Resize non implémenté (stub)
- Validation serial laxiste (serial != 0)
- Pas de contrôle policy (snap-to-edge, min/max)
- Pas de check "surface du même client" (sécu)
- Pas d'event xdg_toplevel.configure([Resizing]) envoyé pendant le drag
Doc complète : docs/phase7-7-move-resize.md
Leyoda 2026 – GPLv3
This commit is contained in:
parent
a87de02555
commit
50f7a064e4
6 changed files with 468 additions and 8 deletions
|
|
@ -29,8 +29,8 @@ use wayland_client::{
|
|||
Connection, Dispatch, EventQueue, Proxy, QueueHandle,
|
||||
backend::Backend,
|
||||
protocol::{
|
||||
wl_buffer::WlBuffer, wl_compositor::WlCompositor, wl_registry, wl_shm::WlShm,
|
||||
wl_shm_pool::WlShmPool, wl_surface::WlSurface,
|
||||
wl_buffer::WlBuffer, wl_compositor::WlCompositor, wl_registry, wl_seat::WlSeat,
|
||||
wl_shm::WlShm, wl_shm_pool::WlShmPool, wl_surface::WlSurface,
|
||||
},
|
||||
};
|
||||
use wayland_protocols::xdg::shell::client::{
|
||||
|
|
@ -71,6 +71,7 @@ struct ClientState {
|
|||
compositor: Option<WlCompositor>,
|
||||
shm: Option<WlShm>,
|
||||
wm_base: Option<XdgWmBase>,
|
||||
seat: Option<WlSeat>,
|
||||
pending_serial: Option<u32>,
|
||||
configured: bool,
|
||||
label: String,
|
||||
|
|
@ -96,6 +97,9 @@ impl Dispatch<wl_registry::WlRegistry, ()> for ClientState {
|
|||
"xdg_wm_base" => {
|
||||
state.wm_base = Some(registry.bind(name, version.min(5), qh, ()));
|
||||
}
|
||||
"wl_seat" => {
|
||||
state.seat = Some(registry.bind(name, version.min(7), qh, ()));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -122,6 +126,7 @@ noop!(WlShm);
|
|||
noop!(WlShmPool);
|
||||
noop!(WlBuffer);
|
||||
noop!(WlSurface);
|
||||
noop!(WlSeat);
|
||||
|
||||
impl Dispatch<XdgWmBase, ()> for ClientState {
|
||||
fn event(
|
||||
|
|
@ -312,6 +317,16 @@ fn run_one(label: &str, base_color: u32, letter: char, shm_name: &str) -> Result
|
|||
event_queue.flush()?;
|
||||
dlog(&format!("[{label}] buffer commit POST-ack"));
|
||||
|
||||
// Phase 7.7 : la fenêtre A déclenche un interactive_move après 8 s.
|
||||
// Sert à valider que le compositor déplace la surface en suivant le
|
||||
// curseur (positionné par le cycle test du compositor lui-même).
|
||||
let move_at = if label == "A" {
|
||||
Some(std::time::Instant::now() + Duration::from_secs(8))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut move_done = false;
|
||||
|
||||
// Boucle vivante 160 s avec dispatch des events
|
||||
let start = std::time::Instant::now();
|
||||
while start.elapsed() < Duration::from_secs(160) {
|
||||
|
|
@ -321,6 +336,21 @@ fn run_one(label: &str, base_color: u32, letter: char, shm_name: &str) -> Result
|
|||
let _ = guard.read();
|
||||
}
|
||||
let _ = event_queue.dispatch_pending(&mut state);
|
||||
|
||||
// Phase 7.7 : déclencher toplevel.move après 8s pour la fenêtre A.
|
||||
if !move_done {
|
||||
if let Some(t) = move_at {
|
||||
if std::time::Instant::now() >= t {
|
||||
if let Some(seat) = state.seat.clone() {
|
||||
// Serial synthétique != 0 pour passer le garde compositor.
|
||||
toplevel._move(&seat, 1);
|
||||
let _ = event_queue.flush();
|
||||
dlog(&format!("[{label}] toplevel.move() envoyé"));
|
||||
move_done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
thread::sleep(Duration::from_millis(50));
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue