refactor(wayland): many things

This commit is contained in:
Nova
2025-09-06 23:56:29 -07:00
parent a0b014576e
commit 1c8aa93850
5 changed files with 174 additions and 106 deletions

View File

@@ -71,6 +71,13 @@ impl Default for SurfaceState {
} }
} }
} }
impl SurfaceState {
pub fn has_valid_buffer(&self) -> bool {
self.buffer
.as_ref()
.is_some_and(|b| b.buffer.size().x > 0 && b.buffer.size().y > 0)
}
}
// if returning false, don't run this callback again... just remove it // if returning false, don't run this callback again... just remove it
pub type OnCommitCallback = Box<dyn Fn(&Surface, &SurfaceState) -> bool + Send + Sync>; pub type OnCommitCallback = Box<dyn Fn(&Surface, &SurfaceState) -> bool + Send + Sync>;

View File

@@ -3,10 +3,16 @@ use crate::{
core::error::Result, core::error::Result,
nodes::{ nodes::{
drawable::model::ModelPart, drawable::model::ModelPart,
items::panel::{Backend, Geometry, PanelItemInitData, SurfaceId, ToplevelInfo}, items::panel::{
Backend, ChildInfo, Geometry, PanelItem, PanelItemInitData, SurfaceId, ToplevelInfo,
},
},
wayland::{
Message,
core::{seat::SeatMessage, surface::Surface},
}, },
wayland::{Message, core::surface::Surface},
}; };
use dashmap::DashMap;
use mint::Vector2; use mint::Vector2;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Weak; use std::sync::Weak;
@@ -15,12 +21,14 @@ use tracing;
#[derive(Debug)] #[derive(Debug)]
pub struct XdgBackend { pub struct XdgBackend {
toplevel: Weak<Toplevel>, toplevel: Weak<Toplevel>,
children: DashMap<u64, (Weak<Surface>, ChildInfo)>,
} }
impl XdgBackend { impl XdgBackend {
pub fn new(toplevel: Arc<Toplevel>) -> Self { pub fn new(toplevel: Arc<Toplevel>) -> Self {
Self { Self {
toplevel: Arc::downgrade(&toplevel), toplevel: Arc::downgrade(&toplevel),
children: DashMap::new(),
} }
} }
@@ -32,14 +40,59 @@ impl XdgBackend {
.expect("Toplevel should always be valid while XdgBackend exists") .expect("Toplevel should always be valid while XdgBackend exists")
} }
fn surface_from_id(&self, id: SurfaceId) -> Option<Arc<Surface>> { pub fn panel_item(&self) -> Option<Arc<PanelItem<XdgBackend>>> {
self.toplevel().wl_surface().panel_item.lock().upgrade()
}
fn surface_from_id(&self, id: &SurfaceId) -> Option<Arc<Surface>> {
match id { match id {
SurfaceId::Toplevel(_) => Some(self.toplevel().wl_surface().clone()), SurfaceId::Toplevel(_) => Some(self.toplevel().wl_surface().clone()),
SurfaceId::Child(_) => None, SurfaceId::Child(id) => self.children.get(id).as_deref().and_then(|c| c.0.upgrade()),
} }
} }
}
pub fn add_child(&self, surface: &Arc<Surface>, info: ChildInfo) {
let Some(SurfaceId::Child(id)) = surface.surface_id.get().cloned() else {
return;
};
self.children
.insert(id, (Arc::downgrade(surface), info.clone()));
let Some(panel_item) = self.panel_item() else {
tracing::error!("Couldn't find panel item in add_child");
return;
};
panel_item.create_child(id, &info);
}
pub fn reposition_child(&self, surface: &Arc<Surface>, geometry: Geometry) {
let Some(SurfaceId::Child(id)) = surface.surface_id.get() else {
return;
};
if let Some(mut child) = self.children.get_mut(&id) {
child.1.geometry = geometry;
}
let Some(panel_item) = self.panel_item() else {
tracing::error!("Couldn't find panel item in reposition_child");
return;
};
panel_item.reposition_child(*id, &geometry);
}
pub fn remove_child(&self, surface: &Surface) {
let Some(SurfaceId::Child(id)) = surface.surface_id.get() else {
return;
};
self.children.remove(id);
let Some(panel_item) = self.panel_item() else {
tracing::error!("Couldn't find panel item in remove_child");
return;
};
panel_item.destroy_child(*id);
}
}
impl Backend for XdgBackend { impl Backend for XdgBackend {
fn start_data(&self) -> Result<PanelItemInitData> { fn start_data(&self) -> Result<PanelItemInitData> {
let surface_state = self.toplevel().wl_surface().current_state(); let surface_state = self.toplevel().wl_surface().current_state();
@@ -76,7 +129,7 @@ impl Backend for XdgBackend {
fn apply_cursor_material(&self, _model_part: &Arc<ModelPart>) {} fn apply_cursor_material(&self, _model_part: &Arc<ModelPart>) {}
fn apply_surface_material(&self, surface: SurfaceId, model_part: &Arc<ModelPart>) { fn apply_surface_material(&self, surface: SurfaceId, model_part: &Arc<ModelPart>) {
if let Some(surface) = self.surface_from_id(surface) { if let Some(surface) = self.surface_from_id(&surface) {
surface.apply_material(model_part); surface.apply_material(model_part);
} }
} }
@@ -123,30 +176,29 @@ impl Backend for XdgBackend {
} }
fn pointer_motion(&self, surface: &SurfaceId, position: Vector2<f32>) { fn pointer_motion(&self, surface: &SurfaceId, position: Vector2<f32>) {
if let Some(surface) = self.surface_from_id(surface.clone()) { if let Some(surface) = self.surface_from_id(surface) {
let _ = self let _ = self
.toplevel() .toplevel()
.wl_surface() .wl_surface()
.message_sink .message_sink
.send(Message::Seat( .send(Message::Seat(SeatMessage::PointerMotion {
crate::wayland::core::seat::SeatMessage::PointerMotion { surface, position }, surface,
)); position,
}));
} }
} }
fn pointer_button(&self, surface: &SurfaceId, button: u32, pressed: bool) { fn pointer_button(&self, surface: &SurfaceId, button: u32, pressed: bool) {
if let Some(surface) = self.surface_from_id(surface.clone()) { if let Some(surface) = self.surface_from_id(surface) {
let _ = self let _ = self
.toplevel() .toplevel()
.wl_surface() .wl_surface()
.message_sink .message_sink
.send(Message::Seat( .send(Message::Seat(SeatMessage::PointerButton {
crate::wayland::core::seat::SeatMessage::PointerButton { surface,
surface, button,
button, pressed,
pressed, }));
},
));
} }
} }
@@ -156,18 +208,16 @@ impl Backend for XdgBackend {
scroll_distance: Option<Vector2<f32>>, scroll_distance: Option<Vector2<f32>>,
scroll_steps: Option<Vector2<f32>>, scroll_steps: Option<Vector2<f32>>,
) { ) {
if let Some(surface) = self.surface_from_id(surface.clone()) { if let Some(surface) = self.surface_from_id(surface) {
let _ = self let _ = self
.toplevel() .toplevel()
.wl_surface() .wl_surface()
.message_sink .message_sink
.send(Message::Seat( .send(Message::Seat(SeatMessage::PointerScroll {
crate::wayland::core::seat::SeatMessage::PointerScroll { surface,
surface, scroll_distance,
scroll_distance, scroll_steps,
scroll_steps, }));
},
));
} }
} }
@@ -177,19 +227,17 @@ impl Backend for XdgBackend {
key, key,
if pressed { "pressed" } else { "released" } if pressed { "pressed" } else { "released" }
); );
if let Some(surface) = self.surface_from_id(surface.clone()) { if let Some(surface) = self.surface_from_id(surface) {
let _ = self let _ = self
.toplevel() .toplevel()
.wl_surface() .wl_surface()
.message_sink .message_sink
.send(Message::Seat( .send(Message::Seat(SeatMessage::KeyboardKey {
crate::wayland::core::seat::SeatMessage::KeyboardKey { surface,
surface, keymap_id,
keymap_id, key,
key, pressed,
pressed, }));
},
));
} }
} }
@@ -200,18 +248,16 @@ impl Backend for XdgBackend {
position.x, position.x,
position.y position.y
); );
if let Some(surface) = self.surface_from_id(surface.clone()) { if let Some(surface) = self.surface_from_id(surface) {
let _ = self let _ = self
.toplevel() .toplevel()
.wl_surface() .wl_surface()
.message_sink .message_sink
.send(Message::Seat( .send(Message::Seat(SeatMessage::TouchDown {
crate::wayland::core::seat::SeatMessage::TouchDown { surface,
surface, id,
id, position,
position, }));
},
));
} }
} }
@@ -223,24 +269,27 @@ impl Backend for XdgBackend {
position.y position.y
); );
let toplevel = self.toplevel(); let toplevel = self.toplevel();
let _ = toplevel.wl_surface().message_sink.send(Message::Seat( let _ = toplevel
crate::wayland::core::seat::SeatMessage::TouchMove { id, position }, .wl_surface()
)); .message_sink
.send(Message::Seat(SeatMessage::TouchMove { id, position }));
} }
fn touch_up(&self, id: u32) { fn touch_up(&self, id: u32) {
tracing::debug!("Backend: Touch up {}", id); tracing::debug!("Backend: Touch up {}", id);
let toplevel = self.toplevel(); let toplevel = self.toplevel();
let _ = toplevel.wl_surface().message_sink.send(Message::Seat( let _ = toplevel
crate::wayland::core::seat::SeatMessage::TouchUp { id }, .wl_surface()
)); .message_sink
.send(Message::Seat(SeatMessage::TouchUp { id }));
} }
fn reset_input(&self) { fn reset_input(&self) {
tracing::debug!("Backend: Reset input"); tracing::debug!("Backend: Reset input");
let toplevel = self.toplevel(); let toplevel = self.toplevel();
let _ = toplevel.wl_surface().message_sink.send(Message::Seat( let _ = toplevel
crate::wayland::core::seat::SeatMessage::Reset, .wl_surface()
)); .message_sink
.send(Message::Seat(SeatMessage::Reset));
} }
} }

View File

@@ -1,15 +1,17 @@
use super::{ use super::{
backend::XdgBackend,
positioner::{Positioner, PositionerData}, positioner::{Positioner, PositionerData},
surface::Surface, surface::Surface,
}; };
use crate::{ use crate::{
nodes::items::panel::{Geometry, PanelItem, SurfaceId}, nodes::items::panel::{Geometry, SurfaceId},
wayland::util::DoubleBuffer, wayland::util::DoubleBuffer,
}; };
use parking_lot::Mutex; use parking_lot::Mutex;
use rand::Rng; use rand::Rng;
use std::sync::{Arc, Weak, atomic::AtomicBool}; use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
};
use waynest::{ use waynest::{
server::{Client, Dispatcher, Result, protocol::stable::xdg_shell::xdg_popup::XdgPopup}, server::{Client, Dispatcher, Result, protocol::stable::xdg_shell::xdg_popup::XdgPopup},
wire::ObjectId, wire::ObjectId,
@@ -20,8 +22,7 @@ pub struct Popup {
id: ObjectId, id: ObjectId,
version: u32, version: u32,
parent: Arc<Surface>, parent: Arc<Surface>,
surface: Arc<Surface>, pub surface: Arc<Surface>,
pub panel_item: Weak<PanelItem<XdgBackend>>,
positioner_data: Mutex<PositionerData>, positioner_data: Mutex<PositionerData>,
geometry: DoubleBuffer<Geometry>, geometry: DoubleBuffer<Geometry>,
mapped: AtomicBool, mapped: AtomicBool,
@@ -31,7 +32,6 @@ impl Popup {
id: ObjectId, id: ObjectId,
version: u32, version: u32,
parent: Arc<Surface>, parent: Arc<Surface>,
panel_item: &Arc<PanelItem<XdgBackend>>,
surface: Arc<Surface>, surface: Arc<Surface>,
positioner: &Positioner, positioner: &Positioner,
) -> Self { ) -> Self {
@@ -46,7 +46,6 @@ impl Popup {
version, version,
parent, parent,
surface, surface,
panel_item: Arc::downgrade(panel_item),
positioner_data: Mutex::new(positioner_data), positioner_data: Mutex::new(positioner_data),
geometry: DoubleBuffer::new(positioner_data.infinite_geometry()), geometry: DoubleBuffer::new(positioner_data.infinite_geometry()),
mapped: AtomicBool::new(false), mapped: AtomicBool::new(false),
@@ -90,6 +89,13 @@ impl XdgPopup for Popup {
) )
.await?; .await?;
self.surface.reconfigure(client).await?; self.surface.reconfigure(client).await?;
let Some(panel_item) = self.surface.wl_surface.panel_item.lock().upgrade() else {
return Ok(());
};
panel_item
.backend
.reposition_child(&self.surface.wl_surface, geometry);
Ok(()) Ok(())
} }
@@ -98,3 +104,14 @@ impl XdgPopup for Popup {
Ok(()) Ok(())
} }
} }
impl Drop for Popup {
fn drop(&mut self) {
if !self.mapped.load(Ordering::Relaxed) {
return;
}
let Some(panel_item) = self.surface.wl_surface.panel_item.lock().upgrade() else {
return;
};
panel_item.backend.remove_child(&self.surface.wl_surface);
}
}

View File

@@ -1,8 +1,8 @@
use super::{popup::Popup, positioner::Positioner, toplevel::MappedInner}; use super::{popup::Popup, positioner::Positioner, toplevel::MappedInner};
use crate::nodes::items::panel::{ChildInfo, SurfaceId};
use crate::wayland::util::ClientExt; use crate::wayland::util::ClientExt;
use crate::wayland::{core::surface::SurfaceRole, display::Display, xdg::toplevel::Toplevel}; use crate::wayland::{core::surface::SurfaceRole, display::Display, xdg::toplevel::Toplevel};
use std::sync::Arc; use std::sync::Arc;
use waynest::server;
pub use waynest::server::protocol::stable::xdg_shell::xdg_surface::*; pub use waynest::server::protocol::stable::xdg_shell::xdg_surface::*;
use waynest::{ use waynest::{
server::{Client, Dispatcher, Result}, server::{Client, Dispatcher, Result},
@@ -81,23 +81,19 @@ impl XdgSurface for Surface {
let toplevel_weak = Arc::downgrade(&toplevel); let toplevel_weak = Arc::downgrade(&toplevel);
let pid = client.get::<Display>(ObjectId::DISPLAY).unwrap().pid; let pid = client.get::<Display>(ObjectId::DISPLAY).unwrap().pid;
let configured = self.configured.clone(); let configured = self.configured.clone();
self.wl_surface.add_commit_handler(move |_surface, state| { self.wl_surface.add_commit_handler(move |surface, state| {
let Some(toplevel) = toplevel_weak.upgrade() else { let Some(toplevel) = toplevel_weak.upgrade() else {
return true; return true;
}; };
// Only proceed if configured and has valid buffer
let has_valid_buffer = state
.buffer
.as_ref()
.is_some_and(|b| b.buffer.size().x > 0 && b.buffer.size().y > 0);
let mut mapped_lock = toplevel.mapped.lock(); let mut mapped_lock = toplevel.mapped.lock();
if mapped_lock.is_none() if mapped_lock.is_none()
&& configured.load(std::sync::atomic::Ordering::SeqCst) && configured.load(std::sync::atomic::Ordering::SeqCst)
&& has_valid_buffer && state.has_valid_buffer()
{ {
mapped_lock.replace(MappedInner::create(toplevel.clone(), pid)); let mapped_inner = MappedInner::create(toplevel.clone(), pid);
*surface.panel_item.lock() = Arc::downgrade(&mapped_inner.panel_item);
mapped_lock.replace(mapped_inner);
return false; return false;
} }
true true
@@ -152,53 +148,52 @@ impl XdgSurface for Surface {
) )
.await; .await;
}; };
let Some(panel_item) = parent.wl_surface.panel_item.lock().upgrade() else { *self.wl_surface.panel_item.lock() = parent.wl_surface.panel_item.lock().clone();
return Err(server::Error::Custom(
"Parent surface does not have a panel item".to_string(),
));
};
let positioner = client.get::<Positioner>(positioner).unwrap(); let positioner = client.get::<Positioner>(positioner).unwrap();
let surface = client.get::<Surface>(self.id).unwrap(); let surface = client.get::<Surface>(self.id).unwrap();
let popup = client.insert( let popup = client.insert(
popup_id, popup_id,
Popup::new( Popup::new(popup_id, self.version, parent.clone(), surface, &positioner),
popup_id,
self.version,
parent,
&panel_item,
surface,
&positioner,
),
); );
let serial = client.next_event_serial(); let serial = client.next_event_serial();
self.configure(client, sender_id, serial).await?; self.configure(client, sender_id, serial).await?;
// let pid = client.get::<Display>(ObjectId::DISPLAY).unwrap().pid; let Some(SurfaceId::Child(id)) = self.wl_surface.surface_id.get() else {
// let configured = self.configured.clone(); return Ok(());
// surface.add_commit_handler(move |surface, state| { };
// let Some(SurfaceRole::XDGPopup(popup)) = &mut *surface.role.lock() else { let Some(parent_id) = parent.wl_surface.surface_id.get() else {
// return true; return Ok(());
// }; };
// // Only proceed if configured and has valid buffer let child_info = ChildInfo {
// let has_valid_buffer = state id: *id,
// .buffer parent: parent_id.clone(),
// .as_ref() geometry: positioner.data().infinite_geometry(),
// .is_some_and(|b| b.buffer.size().x > 0 && b.buffer.size().y > 0); z_order: 1,
receives_input: true,
};
// let mut mapped_lock = popup.mapped.lock(); let popup_weak = Arc::downgrade(&popup);
// if mapped_lock.is_none() let configured = self.configured.clone();
// && configured.load(std::sync::atomic::Ordering::SeqCst) self.wl_surface.add_commit_handler(move |surface, state| {
// && has_valid_buffer let Some(popup) = popup_weak.upgrade() else {
// { return true;
// mapped_lock.replace(Mapped::create(popup.clone(), pid)); };
// return false; let Some(panel_item) = surface.panel_item.lock().upgrade() else {
// } return true;
// true };
// });
if configured.load(std::sync::atomic::Ordering::SeqCst) && state.has_valid_buffer() {
panel_item
.backend
.add_child(&popup.surface.wl_surface, child_info.clone());
return false;
}
true
});
Ok(()) Ok(())
} }

View File

@@ -18,16 +18,16 @@ use waynest::{
#[derive(Debug)] #[derive(Debug)]
pub struct MappedInner { pub struct MappedInner {
pub panel_item_node: Arc<Node>, pub panel_item_node: Arc<Node>,
pub _panel_item: Arc<PanelItem<XdgBackend>>, pub panel_item: Arc<PanelItem<XdgBackend>>,
} }
impl MappedInner { impl MappedInner {
pub fn create(toplevel: Arc<Toplevel>, pid: Option<i32>) -> Self { pub fn create(toplevel: Arc<Toplevel>, pid: Option<i32>) -> Self {
let (panel_item_node, _panel_item) = let (panel_item_node, panel_item) =
PanelItem::create(Box::new(XdgBackend::new(toplevel)), pid); PanelItem::create(Box::new(XdgBackend::new(toplevel)), pid);
Self { Self {
panel_item_node, panel_item_node,
_panel_item, panel_item,
} }
} }
} }