diff --git a/src/wayland/xdg/backend.rs b/src/wayland/xdg/backend.rs index 5aed2a2..bca3a00 100644 --- a/src/wayland/xdg/backend.rs +++ b/src/wayland/xdg/backend.rs @@ -34,7 +34,7 @@ impl XdgBackend { fn surface_from_id(&self, id: SurfaceId) -> Option> { match id { - SurfaceId::Toplevel(_) => Some(self.toplevel().wl_surface()), + SurfaceId::Toplevel(_) => Some(self.toplevel().wl_surface().clone()), SurfaceId::Child(_) => None, } } @@ -222,24 +222,24 @@ impl Backend for XdgBackend { position.x, position.y ); - let surface = self.toplevel().wl_surface(); - let _ = surface.message_sink.send(Message::Seat( + let toplevel = self.toplevel(); + let _ = toplevel.wl_surface().message_sink.send(Message::Seat( crate::wayland::core::seat::SeatMessage::TouchMove { id, position }, )); } fn touch_up(&self, id: u32) { tracing::debug!("Backend: Touch up {}", id); - let surface = self.toplevel().wl_surface(); - let _ = surface.message_sink.send(Message::Seat( + let toplevel = self.toplevel(); + let _ = toplevel.wl_surface().message_sink.send(Message::Seat( crate::wayland::core::seat::SeatMessage::TouchUp { id }, )); } fn reset_input(&self) { tracing::debug!("Backend: Reset input"); - let surface = self.toplevel().wl_surface(); - let _ = surface.message_sink.send(Message::Seat( + let toplevel = self.toplevel(); + let _ = toplevel.wl_surface().message_sink.send(Message::Seat( crate::wayland::core::seat::SeatMessage::Reset, )); } diff --git a/src/wayland/xdg/popup.rs b/src/wayland/xdg/popup.rs index 9482f02..7fade2a 100644 --- a/src/wayland/xdg/popup.rs +++ b/src/wayland/xdg/popup.rs @@ -20,7 +20,7 @@ pub struct Popup { id: ObjectId, version: u32, parent: Arc, - surface: Weak, + surface: Arc, pub panel_item: Weak>, positioner_data: Mutex, geometry: DoubleBuffer, @@ -32,11 +32,11 @@ impl Popup { version: u32, parent: Arc, panel_item: &Arc>, - xdg_surface: &Arc, + surface: Arc, positioner: &Positioner, ) -> Self { - let _ = xdg_surface - .wl_surface() + let _ = surface + .wl_surface .surface_id .set(SurfaceId::Child(rand::thread_rng().gen_range(0..u64::MAX))); @@ -45,7 +45,7 @@ impl Popup { id, version, parent, - surface: Arc::downgrade(xdg_surface), + surface, panel_item: Arc::downgrade(panel_item), positioner_data: Mutex::new(positioner_data), geometry: DoubleBuffer::new(positioner_data.infinite_geometry()), @@ -89,7 +89,7 @@ impl XdgPopup for Popup { geometry.size.y as i32, ) .await?; - self.surface.upgrade().unwrap().reconfigure(client).await?; + self.surface.reconfigure(client).await?; Ok(()) } diff --git a/src/wayland/xdg/surface.rs b/src/wayland/xdg/surface.rs index d997cc5..eb4fdff 100644 --- a/src/wayland/xdg/surface.rs +++ b/src/wayland/xdg/surface.rs @@ -5,7 +5,7 @@ use crate::wayland::{ display::Display, xdg::{toplevel::Toplevel, wm_base::XdgSurfaceRole}, }; -use std::sync::{Arc, OnceLock, Weak}; +use std::sync::{Arc, OnceLock}; pub use waynest::server::protocol::stable::xdg_shell::xdg_surface::*; use waynest::{ server::{Client, Dispatcher, Result}, @@ -16,7 +16,7 @@ use waynest::{ pub struct Surface { id: ObjectId, version: u32, - wl_surface: Weak, + pub wl_surface: Arc, configured: Arc, } impl Surface { @@ -28,18 +28,11 @@ impl Surface { Self { id, version, - wl_surface: Arc::downgrade(&wl_surface), + wl_surface, configured: Arc::new(std::sync::atomic::AtomicBool::new(false)), } } - pub fn wl_surface(&self) -> Arc { - // We can safely unwrap as the surface must exist for the lifetime of the xdg_surface - self.wl_surface - .upgrade() - .expect("Surface was dropped before xdg_surface") - } - pub async fn reconfigure(&self, client: &mut Client) -> Result<()> { let serial = client.next_event_serial(); self.configure(client, self.id, serial).await @@ -59,33 +52,17 @@ impl XdgSurface for Surface { sender_id: ObjectId, toplevel_id: ObjectId, ) -> Result<()> { - let surface = self.wl_surface(); let toplevel = client.insert( toplevel_id, Toplevel::new( toplevel_id, - surface.clone(), + self.wl_surface.clone(), client.get::(sender_id).unwrap(), ), ); - // Set up the XDG role if not already done - if surface.role.get().is_none() { - let xdg_role = SurfaceRole::Xdg(OnceLock::new()); - - if surface.role.set(xdg_role).is_err() { - return client - .protocol_error( - sender_id, - toplevel_id, - 1, // XDG_WM_BASE_ERROR_ROLE - "Failed to set surface role (race condition)".to_string(), - ) - .await; - } - } // Check if the surface already has an XDG role - let surface_role = surface.role.get().unwrap(); + let surface_role = self.wl_surface.role.get().unwrap(); // Now check if this is an XDG surface and set the sub-role if let SurfaceRole::Xdg(role) = surface_role { @@ -128,7 +105,7 @@ impl XdgSurface for Surface { let pid = client.get::(ObjectId::DISPLAY).unwrap().pid; let configured = self.configured.clone(); - surface.add_commit_handler(move |surface, state| { + self.wl_surface.add_commit_handler(move |surface, state| { let Some(role_ref) = surface.role.get() else { return true; }; @@ -184,7 +161,7 @@ impl XdgSurface for Surface { .await; }; let parent = client.get::(parent).unwrap(); - let panel_item = match parent.wl_surface().role.get().unwrap() { + let panel_item = match parent.wl_surface.role.get().unwrap() { SurfaceRole::Xdg(role) => match role.get().unwrap() { XdgSurfaceRole::Toplevel(toplevel) => { if let Some(toplevel) = toplevel.upgrade() { @@ -238,17 +215,16 @@ impl XdgSurface for Surface { self.version, parent, &panel_item, - &surface, + surface, &positioner, ), ); // Set up the XDG role if not already done - let wl_surface = self.wl_surface(); - if wl_surface.role.get().is_none() { + if self.wl_surface.role.get().is_none() { let xdg_role = SurfaceRole::Xdg(OnceLock::new()); - if wl_surface.role.set(xdg_role).is_err() { + if self.wl_surface.role.set(xdg_role).is_err() { return client .protocol_error( sender_id, @@ -261,7 +237,7 @@ impl XdgSurface for Surface { } // Now check if this is an XDG surface and set the sub-role - match wl_surface.role.get().unwrap() { + match self.wl_surface.role.get().unwrap() { SurfaceRole::Xdg(role) => { if role.get().is_some() { return client diff --git a/src/wayland/xdg/toplevel.rs b/src/wayland/xdg/toplevel.rs index b957490..c1a81a2 100644 --- a/src/wayland/xdg/toplevel.rs +++ b/src/wayland/xdg/toplevel.rs @@ -9,7 +9,6 @@ use crate::{ use mint::Vector2; use parking_lot::Mutex; use std::sync::Arc; -use std::sync::Weak; pub use waynest::server::protocol::stable::xdg_shell::xdg_toplevel::*; use waynest::{ server::{Client, Dispatcher, Result}, @@ -58,8 +57,7 @@ impl Default for ToplevelData { #[derive(Debug, Dispatcher)] pub struct Toplevel { pub id: ObjectId, - wl_surface: Weak, - xdg_surface: Weak, + xdg_surface: Arc, pub mapped: Mutex>, data: Mutex, } @@ -73,18 +71,14 @@ impl Toplevel { Toplevel { id: object_id, - wl_surface: Arc::downgrade(&wl_surface), - xdg_surface: Arc::downgrade(&xdg_surface), + xdg_surface, mapped: Mutex::new(None), data: Mutex::new(ToplevelData::default()), } } - pub fn wl_surface(&self) -> Arc { - // We can safely unwrap as the surface must exist for the lifetime of the toplevel - self.wl_surface - .upgrade() - .expect("Surface was dropped before toplevel") + pub fn wl_surface(&self) -> &Arc { + &self.xdg_surface.wl_surface } pub fn title(&self) -> Option { @@ -153,9 +147,7 @@ impl Toplevel { .collect(), ) .await?; - if let Some(xdg_surface) = self.xdg_surface.upgrade() { - xdg_surface.reconfigure(client).await?; - } + self.xdg_surface.reconfigure(client).await?; Ok(()) } } @@ -269,7 +261,8 @@ impl XdgToplevel for Toplevel { width: i32, height: i32, ) -> Result<()> { - self.wl_surface().pending_state().pending.min_size = if width == 0 && height == 0 { + self.xdg_surface.wl_surface.pending_state().pending.min_size = if width == 0 && height == 0 + { None } else { Some([width as u32, height as u32].into()) diff --git a/src/wayland/xdg/wm_base.rs b/src/wayland/xdg/wm_base.rs index 57dba1b..1e71611 100644 --- a/src/wayland/xdg/wm_base.rs +++ b/src/wayland/xdg/wm_base.rs @@ -1,8 +1,8 @@ use super::popup::Popup; use super::positioner::Positioner; use super::toplevel::Toplevel; -use crate::wayland::xdg::surface::Surface; -use std::sync::Weak; +use crate::wayland::{core::surface::SurfaceRole, xdg::surface::Surface}; +use std::sync::{OnceLock, Weak}; pub use waynest::server::protocol::stable::xdg_shell::xdg_wm_base::*; use waynest::{ server::{Client, Dispatcher, Result}, @@ -46,6 +46,7 @@ impl XdgWmBase for WmBase { .ok_or(waynest::server::Error::Custom( "can't get wayland surface id".to_string(), ))?; + let _ = wl_surface.role.set(SurfaceRole::Xdg(OnceLock::new())); let xdg_surface = Surface::new(xdg_surface_id, self.version, wl_surface); client.insert(xdg_surface_id, xdg_surface);