1
0
Fork 0
forked from wry/wry

Merge pull request #689 from mahkoh/jorth/xdg-initial-commit-state

xdg-shell: make acked serial part of the pending state
This commit is contained in:
mahkoh 2025-12-14 23:26:49 +01:00 committed by GitHub
commit 3a4ca4defe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 85 additions and 36 deletions

View file

@ -486,6 +486,7 @@ struct PendingState {
commit_time: Option<u64>, commit_time: Option<u64>,
tray_item_ack_serial: Option<u32>, tray_item_ack_serial: Option<u32>,
color_description: Option<Option<Rc<ColorDescription>>>, color_description: Option<Option<Rc<ColorDescription>>>,
serial: Option<u64>,
} }
struct AttachedSubsurfaceState { struct AttachedSubsurfaceState {
@ -539,6 +540,7 @@ impl PendingState {
opt!(commit_time); opt!(commit_time);
opt!(tray_item_ack_serial); opt!(tray_item_ack_serial);
opt!(color_description); opt!(color_description);
opt!(serial);
{ {
let (dx1, dy1) = self.offset; let (dx1, dy1) = self.offset;
let (dx2, dy2) = mem::take(&mut next.offset); let (dx2, dy2) = mem::take(&mut next.offset);

View file

@ -87,8 +87,9 @@ pub struct XdgSurface {
base: Rc<XdgWmBase>, base: Rc<XdgWmBase>,
role: Cell<XdgSurfaceRole>, role: Cell<XdgSurfaceRole>,
pub surface: Rc<WlSurface>, pub surface: Rc<WlSurface>,
requested_serial: NumCell<u32>, requested_serial: NumCell<u64>,
acked_serial: Cell<Option<u32>>, acked_serial: Cell<u64>,
applied_serial: Cell<u64>,
geometry: Cell<Option<Rect>>, geometry: Cell<Option<Rect>>,
extents: Cell<Rect>, extents: Cell<Rect>,
effective_geometry: Cell<Rect>, effective_geometry: Cell<Rect>,
@ -99,11 +100,19 @@ pub struct XdgSurface {
popups: CopyHashMap<XdgPopupId, Rc<Popup>>, popups: CopyHashMap<XdgPopupId, Rc<Popup>>,
pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>, pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
pub tracker: Tracker<Self>, pub tracker: Tracker<Self>,
have_initial_commit: Cell<bool>, initial_commit_state: Cell<InitialCommitState>,
configure_scheduled: Cell<bool>, configure_scheduled: Cell<bool>,
destroyed: Cell<bool>, destroyed: Cell<bool>,
} }
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
enum InitialCommitState {
#[default]
Unmapped,
Sent,
Mapped,
}
struct Popup { struct Popup {
parent: Rc<XdgSurface>, parent: Rc<XdgSurface>,
popup: Rc<XdgPopup>, popup: Rc<XdgPopup>,
@ -209,8 +218,8 @@ impl PendingXdgSurfaceData {
} }
pub trait XdgSurfaceExt: Debug { pub trait XdgSurfaceExt: Debug {
fn initial_configure(self: Rc<Self>) -> Result<(), XdgSurfaceError> { fn initial_configure(self: Rc<Self>) {
Ok(()) // nothing
} }
fn post_commit(self: Rc<Self>) { fn post_commit(self: Rc<Self>) {
@ -250,7 +259,8 @@ impl XdgSurface {
role: Cell::new(XdgSurfaceRole::None), role: Cell::new(XdgSurfaceRole::None),
surface: surface.clone(), surface: surface.clone(),
requested_serial: NumCell::new(1), requested_serial: NumCell::new(1),
acked_serial: Cell::new(None), acked_serial: Cell::new(0),
applied_serial: Cell::new(0),
geometry: Cell::new(None), geometry: Cell::new(None),
extents: Cell::new(surface.extents.get()), extents: Cell::new(surface.extents.get()),
effective_geometry: Default::default(), effective_geometry: Default::default(),
@ -261,7 +271,7 @@ impl XdgSurface {
popups: Default::default(), popups: Default::default(),
workspace: Default::default(), workspace: Default::default(),
tracker: Default::default(), tracker: Default::default(),
have_initial_commit: Default::default(), initial_commit_state: Default::default(),
configure_scheduled: Default::default(), configure_scheduled: Default::default(),
destroyed: Default::default(), destroyed: Default::default(),
} }
@ -350,17 +360,34 @@ impl XdgSurface {
if self.configure_scheduled.replace(true) { if self.configure_scheduled.replace(true) {
return; return;
} }
let serial = self.requested_serial.add_fetch(1);
self.surface self.surface
.client .client
.state .state
.xdg_surface_configure_events .xdg_surface_configure_events
.push(XdgSurfaceConfigureEvent { .push(XdgSurfaceConfigureEvent {
xdg: self.clone(), xdg: self.clone(),
serial, serial: self.next_serial() as _,
}); });
} }
fn next_serial(&self) -> u64 {
let mut serial = self.requested_serial.add_fetch(1);
if serial as u32 == 0 {
serial = self.requested_serial.add_fetch(1);
}
serial
}
fn map_serial(&self, serial: u32) -> u64 {
let max = self.requested_serial.get();
let mask = u32::MAX as u64;
let mut serial = max & !mask | (serial as u64);
if serial > max {
serial = serial.saturating_sub(mask + 1);
}
serial
}
pub fn send_configure(&self, serial: u32) { pub fn send_configure(&self, serial: u32) {
self.surface.client.event(Configure { self.surface.client.event(Configure {
self_id: self.id, self_id: self.id,
@ -510,9 +537,13 @@ impl XdgSurfaceRequestHandler for XdgSurface {
} }
fn ack_configure(&self, req: AckConfigure, _slf: &Rc<Self>) -> Result<(), Self::Error> { fn ack_configure(&self, req: AckConfigure, _slf: &Rc<Self>) -> Result<(), Self::Error> {
if self.requested_serial.get() == req.serial { let serial = self.map_serial(req.serial);
self.acked_serial.set(Some(req.serial)); let last = self.acked_serial.get();
if serial <= last {
return Err(XdgSurfaceError::InvalidSerial(serial, last));
} }
self.acked_serial.set(serial);
self.surface.pending.borrow_mut().serial = Some(serial);
Ok(()) Ok(())
} }
} }
@ -616,26 +647,41 @@ impl SurfaceExt for XdgSurface {
self: Rc<Self>, self: Rc<Self>,
pending: &mut PendingState, pending: &mut PendingState,
) -> Result<(), WlSurfaceError> { ) -> Result<(), WlSurfaceError> {
if !self.have_initial_commit.get() if let Some(pending) = &mut pending.xdg_surface {
&& let Some(ext) = self.ext.get() if let Some(geometry) = pending.geometry.take() {
{ let prev = self.geometry.replace(Some(geometry));
ext.initial_configure()?; if prev != Some(geometry) {
self.schedule_configure(); self.update_effective_geometry();
self.have_initial_commit.set(true); self.update_extents();
} }
if let Some(pending) = &mut pending.xdg_surface
&& let Some(geometry) = pending.geometry.take()
{
let prev = self.geometry.replace(Some(geometry));
if prev != Some(geometry) {
self.update_effective_geometry();
self.update_extents();
} }
} }
if let Some(serial) = pending.serial.take() {
self.applied_serial.set(serial);
}
Ok(()) Ok(())
} }
fn after_apply_commit(self: Rc<Self>) { fn after_apply_commit(self: Rc<Self>) {
match self.initial_commit_state.get() {
InitialCommitState::Unmapped => {
if let Some(ext) = self.ext.get() {
ext.initial_configure();
self.schedule_configure();
self.initial_commit_state.set(InitialCommitState::Sent);
}
}
InitialCommitState::Sent => {
if self.surface.buffer.is_some() {
self.initial_commit_state.set(InitialCommitState::Mapped);
}
}
InitialCommitState::Mapped => {
if self.surface.buffer.is_none() {
self.initial_commit_state.set(InitialCommitState::Unmapped);
}
}
}
if let Some(ext) = self.ext.get() { if let Some(ext) = self.ext.get() {
ext.post_commit(); ext.post_commit();
} }
@ -682,6 +728,8 @@ pub enum XdgSurfaceError {
AlreadyConstructed, AlreadyConstructed,
#[error(transparent)] #[error(transparent)]
WlSurfaceError(Box<WlSurfaceError>), WlSurfaceError(Box<WlSurfaceError>),
#[error("The serial {0} is not larger than the previously acked serial {1}")]
InvalidSerial(u64, u64),
} }
efrom!(XdgSurfaceError, WlSurfaceError); efrom!(XdgSurfaceError, WlSurfaceError);
efrom!(XdgSurfaceError, ClientError); efrom!(XdgSurfaceError, ClientError);

View file

@ -7,7 +7,7 @@ use {
wl_seat::{NodeSeatState, WlSeatGlobal, tablet::TabletTool}, wl_seat::{NodeSeatState, WlSeatGlobal, tablet::TabletTool},
wl_surface::{ wl_surface::{
tray::TrayItemId, tray::TrayItemId,
xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceExt}, xdg_surface::{XdgSurface, XdgSurfaceExt},
}, },
xdg_positioner::{ xdg_positioner::{
CA_FLIP_X, CA_FLIP_Y, CA_RESIZE_X, CA_RESIZE_Y, CA_SLIDE_X, CA_SLIDE_Y, CA_FLIP_X, CA_FLIP_Y, CA_RESIZE_X, CA_RESIZE_Y, CA_SLIDE_X, CA_SLIDE_Y,
@ -417,13 +417,12 @@ impl StackedNode for XdgPopup {
} }
impl XdgSurfaceExt for XdgPopup { impl XdgSurfaceExt for XdgPopup {
fn initial_configure(self: Rc<Self>) -> Result<(), XdgSurfaceError> { fn initial_configure(self: Rc<Self>) {
if let Some(parent) = self.parent.get() { if let Some(parent) = self.parent.get() {
self.update_position(&*parent); self.update_position(&*parent);
let rel = self.relative_position.get(); let rel = self.relative_position.get();
self.send_configure(rel.x1(), rel.y1(), rel.width(), rel.height()); self.send_configure(rel.x1(), rel.y1(), rel.width(), rel.height());
} }
Ok(())
} }
fn post_commit(self: Rc<Self>) { fn post_commit(self: Rc<Self>) {

View file

@ -13,8 +13,7 @@ use {
wl_surface::{ wl_surface::{
WlSurface, WlSurface,
xdg_surface::{ xdg_surface::{
XdgSurface, XdgSurfaceError, XdgSurfaceExt, XdgSurface, XdgSurfaceExt, xdg_toplevel::xdg_dialog_v1::XdgDialogV1,
xdg_toplevel::xdg_dialog_v1::XdgDialogV1,
}, },
}, },
xdg_toplevel_drag_v1::XdgToplevelDragV1, xdg_toplevel_drag_v1::XdgToplevelDragV1,
@ -753,14 +752,13 @@ impl ToplevelNodeBase for XdgToplevel {
} }
impl XdgSurfaceExt for XdgToplevel { impl XdgSurfaceExt for XdgToplevel {
fn initial_configure(self: Rc<Self>) -> Result<(), XdgSurfaceError> { fn initial_configure(self: Rc<Self>) {
let rect = self.xdg.absolute_desired_extents.get(); let rect = self.xdg.absolute_desired_extents.get();
if rect.is_empty() { if rect.is_empty() {
self.send_configure(0, 0); self.send_configure(0, 0);
} else { } else {
self.send_configure_checked(rect.width(), rect.height()); self.send_configure_checked(rect.width(), rect.height());
} }
Ok(())
} }
fn post_commit(self: Rc<Self>) { fn post_commit(self: Rc<Self>) {

View file

@ -50,7 +50,7 @@ impl TestXdgWmBase {
tran: self.tran.clone(), tran: self.tran.clone(),
_server: server, _server: server,
destroyed: Cell::new(false), destroyed: Cell::new(false),
last_serial: Cell::new(0), last_serial: Default::default(),
}); });
self.tran.add_obj(xdg.clone())?; self.tran.add_obj(xdg.clone())?;
Ok(xdg) Ok(xdg)

View file

@ -19,7 +19,7 @@ pub struct TestXdgSurface {
pub tran: Rc<TestTransport>, pub tran: Rc<TestTransport>,
pub _server: Rc<XdgSurface>, pub _server: Rc<XdgSurface>,
pub destroyed: Cell<bool>, pub destroyed: Cell<bool>,
pub last_serial: Cell<u32>, pub last_serial: Cell<Option<u32>>,
} }
impl TestXdgSurface { impl TestXdgSurface {
@ -63,7 +63,7 @@ impl TestXdgSurface {
fn handle_configure(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> { fn handle_configure(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
let ev = Configure::parse_full(parser)?; let ev = Configure::parse_full(parser)?;
self.last_serial.set(ev.serial); self.last_serial.set(Some(ev.serial));
Ok(()) Ok(())
} }
} }

View file

@ -15,7 +15,9 @@ pub struct TestWindow {
impl TestWindow { impl TestWindow {
pub async fn map(&self) -> Result<(), TestError> { pub async fn map(&self) -> Result<(), TestError> {
self.xdg.ack_configure(self.xdg.last_serial.get())?; if let Some(serial) = self.xdg.last_serial.take() {
self.xdg.ack_configure(serial)?;
}
self.surface self.surface
.map(self.tl.core.width.get(), self.tl.core.height.get()) .map(self.tl.core.width.get(), self.tl.core.height.get())
.await?; .await?;