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
pub type OnCommitCallback = Box<dyn Fn(&Surface, &SurfaceState) -> bool + Send + Sync>;

View File

@@ -3,10 +3,16 @@ use crate::{
core::error::Result,
nodes::{
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 std::sync::Arc;
use std::sync::Weak;
@@ -15,12 +21,14 @@ use tracing;
#[derive(Debug)]
pub struct XdgBackend {
toplevel: Weak<Toplevel>,
children: DashMap<u64, (Weak<Surface>, ChildInfo)>,
}
impl XdgBackend {
pub fn new(toplevel: Arc<Toplevel>) -> Self {
Self {
toplevel: Arc::downgrade(&toplevel),
children: DashMap::new(),
}
}
@@ -32,14 +40,59 @@ impl XdgBackend {
.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 {
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 {
fn start_data(&self) -> Result<PanelItemInitData> {
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_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);
}
}
@@ -123,30 +176,29 @@ impl Backend for XdgBackend {
}
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
.toplevel()
.wl_surface()
.message_sink
.send(Message::Seat(
crate::wayland::core::seat::SeatMessage::PointerMotion { surface, position },
));
.send(Message::Seat(SeatMessage::PointerMotion {
surface,
position,
}));
}
}
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
.toplevel()
.wl_surface()
.message_sink
.send(Message::Seat(
crate::wayland::core::seat::SeatMessage::PointerButton {
surface,
button,
pressed,
},
));
.send(Message::Seat(SeatMessage::PointerButton {
surface,
button,
pressed,
}));
}
}
@@ -156,18 +208,16 @@ impl Backend for XdgBackend {
scroll_distance: 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
.toplevel()
.wl_surface()
.message_sink
.send(Message::Seat(
crate::wayland::core::seat::SeatMessage::PointerScroll {
surface,
scroll_distance,
scroll_steps,
},
));
.send(Message::Seat(SeatMessage::PointerScroll {
surface,
scroll_distance,
scroll_steps,
}));
}
}
@@ -177,19 +227,17 @@ impl Backend for XdgBackend {
key,
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
.toplevel()
.wl_surface()
.message_sink
.send(Message::Seat(
crate::wayland::core::seat::SeatMessage::KeyboardKey {
surface,
keymap_id,
key,
pressed,
},
));
.send(Message::Seat(SeatMessage::KeyboardKey {
surface,
keymap_id,
key,
pressed,
}));
}
}
@@ -200,18 +248,16 @@ impl Backend for XdgBackend {
position.x,
position.y
);
if let Some(surface) = self.surface_from_id(surface.clone()) {
if let Some(surface) = self.surface_from_id(surface) {
let _ = self
.toplevel()
.wl_surface()
.message_sink
.send(Message::Seat(
crate::wayland::core::seat::SeatMessage::TouchDown {
surface,
id,
position,
},
));
.send(Message::Seat(SeatMessage::TouchDown {
surface,
id,
position,
}));
}
}
@@ -223,24 +269,27 @@ impl Backend for XdgBackend {
position.y
);
let toplevel = self.toplevel();
let _ = toplevel.wl_surface().message_sink.send(Message::Seat(
crate::wayland::core::seat::SeatMessage::TouchMove { id, position },
));
let _ = toplevel
.wl_surface()
.message_sink
.send(Message::Seat(SeatMessage::TouchMove { id, position }));
}
fn touch_up(&self, id: u32) {
tracing::debug!("Backend: Touch up {}", id);
let toplevel = self.toplevel();
let _ = toplevel.wl_surface().message_sink.send(Message::Seat(
crate::wayland::core::seat::SeatMessage::TouchUp { id },
));
let _ = toplevel
.wl_surface()
.message_sink
.send(Message::Seat(SeatMessage::TouchUp { id }));
}
fn reset_input(&self) {
tracing::debug!("Backend: Reset input");
let toplevel = self.toplevel();
let _ = toplevel.wl_surface().message_sink.send(Message::Seat(
crate::wayland::core::seat::SeatMessage::Reset,
));
let _ = toplevel
.wl_surface()
.message_sink
.send(Message::Seat(SeatMessage::Reset));
}
}

View File

@@ -1,15 +1,17 @@
use super::{
backend::XdgBackend,
positioner::{Positioner, PositionerData},
surface::Surface,
};
use crate::{
nodes::items::panel::{Geometry, PanelItem, SurfaceId},
nodes::items::panel::{Geometry, SurfaceId},
wayland::util::DoubleBuffer,
};
use parking_lot::Mutex;
use rand::Rng;
use std::sync::{Arc, Weak, atomic::AtomicBool};
use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
};
use waynest::{
server::{Client, Dispatcher, Result, protocol::stable::xdg_shell::xdg_popup::XdgPopup},
wire::ObjectId,
@@ -20,8 +22,7 @@ pub struct Popup {
id: ObjectId,
version: u32,
parent: Arc<Surface>,
surface: Arc<Surface>,
pub panel_item: Weak<PanelItem<XdgBackend>>,
pub surface: Arc<Surface>,
positioner_data: Mutex<PositionerData>,
geometry: DoubleBuffer<Geometry>,
mapped: AtomicBool,
@@ -31,7 +32,6 @@ impl Popup {
id: ObjectId,
version: u32,
parent: Arc<Surface>,
panel_item: &Arc<PanelItem<XdgBackend>>,
surface: Arc<Surface>,
positioner: &Positioner,
) -> Self {
@@ -46,7 +46,6 @@ impl Popup {
version,
parent,
surface,
panel_item: Arc::downgrade(panel_item),
positioner_data: Mutex::new(positioner_data),
geometry: DoubleBuffer::new(positioner_data.infinite_geometry()),
mapped: AtomicBool::new(false),
@@ -90,6 +89,13 @@ impl XdgPopup for Popup {
)
.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(())
}
@@ -98,3 +104,14 @@ impl XdgPopup for Popup {
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 crate::nodes::items::panel::{ChildInfo, SurfaceId};
use crate::wayland::util::ClientExt;
use crate::wayland::{core::surface::SurfaceRole, display::Display, xdg::toplevel::Toplevel};
use std::sync::Arc;
use waynest::server;
pub use waynest::server::protocol::stable::xdg_shell::xdg_surface::*;
use waynest::{
server::{Client, Dispatcher, Result},
@@ -81,23 +81,19 @@ impl XdgSurface for Surface {
let toplevel_weak = Arc::downgrade(&toplevel);
let pid = client.get::<Display>(ObjectId::DISPLAY).unwrap().pid;
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 {
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();
if mapped_lock.is_none()
&& 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;
}
true
@@ -152,53 +148,52 @@ impl XdgSurface for Surface {
)
.await;
};
let Some(panel_item) = parent.wl_surface.panel_item.lock().upgrade() else {
return Err(server::Error::Custom(
"Parent surface does not have a panel item".to_string(),
));
};
*self.wl_surface.panel_item.lock() = parent.wl_surface.panel_item.lock().clone();
let positioner = client.get::<Positioner>(positioner).unwrap();
let surface = client.get::<Surface>(self.id).unwrap();
let popup = client.insert(
popup_id,
Popup::new(
popup_id,
self.version,
parent,
&panel_item,
surface,
&positioner,
),
Popup::new(popup_id, self.version, parent.clone(), surface, &positioner),
);
let serial = client.next_event_serial();
self.configure(client, sender_id, serial).await?;
// let pid = client.get::<Display>(ObjectId::DISPLAY).unwrap().pid;
// let configured = self.configured.clone();
// surface.add_commit_handler(move |surface, state| {
// let Some(SurfaceRole::XDGPopup(popup)) = &mut *surface.role.lock() else {
// return true;
// };
let Some(SurfaceId::Child(id)) = self.wl_surface.surface_id.get() else {
return Ok(());
};
let Some(parent_id) = parent.wl_surface.surface_id.get() else {
return Ok(());
};
// // 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 child_info = ChildInfo {
id: *id,
parent: parent_id.clone(),
geometry: positioner.data().infinite_geometry(),
z_order: 1,
receives_input: true,
};
// let mut mapped_lock = popup.mapped.lock();
// if mapped_lock.is_none()
// && configured.load(std::sync::atomic::Ordering::SeqCst)
// && has_valid_buffer
// {
// mapped_lock.replace(Mapped::create(popup.clone(), pid));
// return false;
// }
// true
// });
let popup_weak = Arc::downgrade(&popup);
let configured = self.configured.clone();
self.wl_surface.add_commit_handler(move |surface, state| {
let Some(popup) = popup_weak.upgrade() else {
return true;
};
let Some(panel_item) = surface.panel_item.lock().upgrade() else {
return 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(())
}

View File

@@ -18,16 +18,16 @@ use waynest::{
#[derive(Debug)]
pub struct MappedInner {
pub panel_item_node: Arc<Node>,
pub _panel_item: Arc<PanelItem<XdgBackend>>,
pub panel_item: Arc<PanelItem<XdgBackend>>,
}
impl MappedInner {
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);
Self {
panel_item_node,
_panel_item,
panel_item,
}
}
}