refactor(wayland): update data in user data map for everything

This commit is contained in:
Nova
2024-08-06 20:42:46 -04:00
parent 08135b03a2
commit 14ebe85493
6 changed files with 230 additions and 204 deletions

View File

@@ -22,6 +22,15 @@ use std::sync::{Arc, Weak};
use tracing::{debug, info};
stardust_xr_server_codegen::codegen_item_panel_protocol!();
impl Default for Geometry {
fn default() -> Self {
Geometry {
origin: [0, 0].into(),
size: [0, 0].into(),
}
}
}
lazy_static! {
pub static ref ITEM_TYPE_INFO_PANEL: TypeInfo = TypeInfo {
type_name: "panel",

View File

@@ -1,7 +1,7 @@
use super::{
state::{ClientState, WaylandState},
utils::WlSurfaceExt,
xdg_shell::{surface_panel_item, ChildInfoExt},
utils::{ChildInfoExt, WlSurfaceExt},
xdg_shell::surface_panel_item,
};
use crate::{
nodes::items::panel::{ChildInfo, Geometry, SurfaceId},

View File

@@ -1,4 +1,4 @@
use super::{state::WaylandState, surface::CoreSurface};
use super::{state::WaylandState, surface::CoreSurface, utils::WlSurfaceExt};
use crate::{
core::task,
nodes::{
@@ -76,8 +76,7 @@ pub struct CursorInfo {
}
impl CursorInfo {
pub fn cursor_data(&self) -> Option<Geometry> {
let cursor_size =
CoreSurface::from_wl_surface(&self.surface.as_ref()?.upgrade().ok()?)?.size()?;
let cursor_size = self.surface.as_ref()?.upgrade().ok()?.get_size()?;
Some(Geometry {
origin: [self.hotspot_x, self.hotspot_y].into(),
size: cursor_size,

View File

@@ -9,7 +9,6 @@ use crate::{
items::camera::TexWrapper,
},
};
use mint::Vector2;
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use send_wrapper::SendWrapper;
@@ -35,7 +34,6 @@ pub static CORE_SURFACES: Registry<CoreSurface> = Registry::new();
pub struct CoreSurfaceData {
wl_tex: Option<SendWrapper<GlesTexture>>,
pub size: Vector2<u32>,
}
impl Drop for CoreSurfaceData {
fn drop(&mut self) {
@@ -156,16 +154,7 @@ impl CoreSurface {
sk_mat.lock().0.queue_offset(*material_offset as i32);
}
let Some(surface_size) = wl_surface
.get_data_raw::<RendererSurfaceStateUserData, _, _>(|surface_states| {
surface_states.lock().unwrap().surface_size()
})
.flatten()
else {
return;
};
let new_mapped_data = CoreSurfaceData {
size: Vector2::from([surface_size.w as u32, surface_size.h as u32]),
wl_tex: Some(SendWrapper::new(smithay_tex)),
};
*mapped_data = Some(new_mapped_data);
@@ -206,10 +195,6 @@ impl CoreSurface {
pub fn wl_surface(&self) -> Option<WlSurface> {
self.weak_surface.upgrade().ok()
}
pub fn size(&self) -> Option<Vector2<u32>> {
self.mapped_data.lock().as_ref().map(|d| d.size)
}
}
impl Drop for CoreSurface {
fn drop(&mut self) {

View File

@@ -1,9 +1,25 @@
use smithay::{reexports::wayland_server::protocol::wl_surface::WlSurface, wayland::compositor};
use mint::Vector2;
use parking_lot::Mutex;
use smithay::{
backend::renderer::utils::RendererSurfaceStateUserData,
reexports::wayland_server::protocol::wl_surface::WlSurface,
wayland::{
compositor,
shell::xdg::{SurfaceCachedState, XdgToplevelSurfaceData},
},
};
use crate::nodes::items::panel::{ChildInfo, Geometry, ToplevelInfo};
use super::xdg_shell::surface_panel_item;
pub trait WlSurfaceExt {
fn insert_data<T: Send + Sync + 'static>(&self, data: T) -> bool;
fn get_data<T: Send + Sync + Clone + 'static>(&self) -> Option<T>;
fn get_data_raw<T: Send + Sync + 'static, O, F: FnOnce(&T) -> O>(&self, f: F) -> Option<O>;
fn get_current_surface_state(&self) -> SurfaceCachedState;
fn get_pending_surface_state(&self) -> SurfaceCachedState;
fn get_size(&self) -> Option<Vector2<u32>>;
fn get_geometry(&self) -> Option<Geometry>;
}
impl WlSurfaceExt for WlSurface {
fn insert_data<T: Send + Sync + 'static>(&self, data: T) -> bool {
@@ -17,4 +33,97 @@ impl WlSurfaceExt for WlSurface {
fn get_data_raw<T: Send + Sync + 'static, O, F: FnOnce(&T) -> O>(&self, f: F) -> Option<O> {
compositor::with_states(self, |d| Some((f)(d.data_map.get::<T>()?)))
}
fn get_current_surface_state(&self) -> SurfaceCachedState {
compositor::with_states(self, |states| {
states
.cached_state
.get::<SurfaceCachedState>()
.current()
.clone()
})
}
fn get_pending_surface_state(&self) -> SurfaceCachedState {
compositor::with_states(self, |states| {
states
.cached_state
.get::<SurfaceCachedState>()
.pending()
.clone()
})
}
fn get_size(&self) -> Option<Vector2<u32>> {
self.get_data_raw::<RendererSurfaceStateUserData, _, _>(|surface_states| {
surface_states.lock().unwrap().surface_size()
})
.flatten()
.map(|size| Vector2::from([size.w as u32, size.h as u32]))
}
fn get_geometry(&self) -> Option<Geometry> {
self.get_current_surface_state().geometry.map(|r| r.into())
}
}
pub trait ToplevelInfoExt {
fn get_toplevel_info(&self) -> Option<ToplevelInfo>;
fn with_toplevel_info<O, F: FnOnce(&mut ToplevelInfo) -> O>(&self, f: F) -> Option<O>;
fn get_parent(&self) -> Option<u64>;
fn get_app_id(&self) -> Option<String>;
fn get_title(&self) -> Option<String>;
fn min_size(&self) -> Option<Vector2<u32>>;
fn max_size(&self) -> Option<Vector2<u32>>;
}
impl ToplevelInfoExt for WlSurface {
fn get_toplevel_info(&self) -> Option<ToplevelInfo> {
self.get_data_raw::<Mutex<ToplevelInfo>, _, _>(|c| c.lock().clone())
}
fn with_toplevel_info<O, F: FnOnce(&mut ToplevelInfo) -> O>(&self, f: F) -> Option<O> {
self.get_data_raw::<Mutex<ToplevelInfo>, _, _>(|r| (f)(&mut r.lock()))
}
fn get_parent(&self) -> Option<u64> {
self.get_data_raw::<XdgToplevelSurfaceData, _, _>(|d| d.lock().unwrap().parent.clone())
.flatten()
.and_then(|p| surface_panel_item(&p))
.and_then(|p| p.node.upgrade())
.map(|p| p.get_id())
}
fn get_app_id(&self) -> Option<String> {
self.get_data_raw::<XdgToplevelSurfaceData, _, _>(|d| d.lock().ok()?.app_id.clone())
.flatten()
}
fn get_title(&self) -> Option<String> {
self.get_data_raw::<XdgToplevelSurfaceData, _, _>(|d| d.lock().ok()?.title.clone())
.flatten()
}
fn min_size(&self) -> Option<Vector2<u32>> {
let state = self.get_pending_surface_state();
let size = state.min_size;
if size.w == 0 && size.h == 0 {
None
} else {
Some(Vector2::from([size.w as u32, size.h as u32]))
}
}
fn max_size(&self) -> Option<Vector2<u32>> {
let state = self.get_pending_surface_state();
let size = state.max_size;
if size.w == 0 && size.h == 0 {
None
} else {
Some(Vector2::from([size.w as u32, size.h as u32]))
}
}
}
pub trait ChildInfoExt {
fn get_child_info(&self) -> Option<ChildInfo>;
fn with_child_info<O, F: FnOnce(&mut ChildInfo) -> O>(&self, f: F) -> Option<O>;
}
impl ChildInfoExt for WlSurface {
fn get_child_info(&self) -> Option<ChildInfo> {
self.get_data_raw::<Mutex<ChildInfo>, _, _>(|c| c.lock().clone())
}
fn with_child_info<O, F: FnOnce(&mut ChildInfo) -> O>(&self, f: F) -> Option<O> {
self.get_data_raw::<Mutex<ChildInfo>, _, _>(|r| (f)(&mut r.lock()))
}
}

View File

@@ -2,7 +2,7 @@ use super::{
seat::{handle_cursor, SeatWrapper},
state::{ClientState, WaylandState},
surface::CoreSurface,
utils::WlSurfaceExt,
utils::*,
};
use crate::nodes::{
drawable::model::ModelPart,
@@ -16,7 +16,6 @@ use parking_lot::Mutex;
use rand::Rng;
use rustc_hash::FxHashMap;
use smithay::{
backend::renderer::utils::RendererSurfaceStateUserData,
delegate_xdg_shell,
reexports::{
wayland_protocols::xdg::{
@@ -30,16 +29,25 @@ use smithay::{
},
utils::{Logical, Rectangle, Serial},
wayland::{
compositor::{self, add_post_commit_hook},
compositor::add_post_commit_hook,
shell::xdg::{
PopupSurface, PositionerState, ShellClient, SurfaceCachedState, ToplevelSurface,
XdgShellHandler, XdgShellState, XdgToplevelSurfaceData,
PopupSurface, PositionerState, ShellClient, ToplevelSurface, XdgShellHandler,
XdgShellState,
},
},
};
use std::sync::{Arc, Weak};
use tracing::warn;
fn get_unconstrained_popup_geometry(positioner: &PositionerState) -> Geometry {
positioner
.get_unconstrained_geometry(Rectangle {
loc: (-100000, -100000).into(),
size: (200000, 200000).into(),
})
.into()
}
impl From<Rectangle<i32, Logical>> for Geometry {
fn from(value: Rectangle<i32, Logical>) -> Self {
Geometry {
@@ -49,49 +57,6 @@ impl From<Rectangle<i32, Logical>> for Geometry {
}
}
// pub trait ToplevelInfoExt {
// fn get_toplevel_info(&self) -> Option<ToplevelInfo>;
// fn with_toplevel_info<O, F: FnOnce(&mut ToplevelInfo) -> O>(&self, f: F) -> Option<O>;
// fn get_toplevel_state(&self) -> Option<ToplevelState>;
// fn get_app_id(&self) -> Option<String>;
// fn get_title(&self) -> Option<String>;
// }
// impl ToplevelInfoExt for WlSurface {
// fn get_toplevel_info(&self) -> Option<ToplevelInfo> {
// self.get_data_raw::<Mutex<ToplevelInfo>, _, _>(|c| c.lock().clone())
// }
// fn with_toplevel_info<O, F: FnOnce(&mut ToplevelInfo) -> O>(&self, f: F) -> Option<O> {
// self.get_data_raw::<Mutex<ToplevelInfo>, _, _>(|r| (f)(&mut r.lock()))
// }
// fn get_toplevel_state(&self) -> Option<ToplevelState> {
// self.get_data_raw::<XdgToplevelSurfaceData, _, _>(|r| r.lock().unwrap().current.clone())
// }
// fn get_app_id(&self) -> Option<String> {
// self.get_data_raw::<XdgToplevelSurfaceData, _, _>(|d| {
// d.lock().unwrap().app_id.clone().unwrap()
// })
// }
// fn get_title(&self) -> Option<String> {
// self.get_data_raw::<XdgToplevelSurfaceData, _, _>(|d| {
// d.lock().unwrap().title.clone().unwrap()
// })
// }
// }
pub trait ChildInfoExt {
fn get_child_info(&self) -> Option<ChildInfo>;
fn with_child_info<O, F: FnOnce(&mut ChildInfo) -> O>(&self, f: F) -> Option<O>;
}
impl ChildInfoExt for WlSurface {
fn get_child_info(&self) -> Option<ChildInfo> {
self.get_data_raw::<Mutex<ChildInfo>, _, _>(|c| c.lock().clone())
}
fn with_child_info<O, F: FnOnce(&mut ChildInfo) -> O>(&self, f: F) -> Option<O> {
self.get_data_raw::<Mutex<ChildInfo>, _, _>(|r| (f)(&mut r.lock()))
}
}
pub fn surface_panel_item(wl_surface: &WlSurface) -> Option<Arc<PanelItem<XdgBackend>>> {
let panel_item = wl_surface
.get_data::<Weak<PanelItem<XdgBackend>>>()
@@ -123,11 +88,76 @@ impl XdgShellHandler for WaylandState {
s.states.unset(State::Fullscreen);
});
toplevel.send_configure();
let initial_size = toplevel
.wl_surface()
.get_size()
.unwrap_or(Vector2::from([0; 2]));
let initial_toplevel_info = ToplevelInfo {
parent: toplevel.wl_surface().get_parent(),
title: toplevel.wl_surface().get_title(),
app_id: toplevel.wl_surface().get_app_id(),
size: initial_size,
min_size: toplevel
.wl_surface()
.min_size()
.map(|s| Vector2::from([s.x as f32, s.y as f32])),
max_size: toplevel
.wl_surface()
.max_size()
.map(|s| Vector2::from([s.x as f32, s.y as f32])),
logical_rectangle: toplevel
.wl_surface()
.get_geometry()
.map(|r| r.into())
.unwrap_or(Geometry {
origin: [0; 2].into(),
size: initial_size,
}),
};
toplevel
.wl_surface()
.insert_data(Mutex::new(Vector2::from([0_u32; 2])));
.insert_data(Mutex::new(initial_toplevel_info));
CoreSurface::add_to(toplevel.wl_surface());
add_post_commit_hook(
toplevel.wl_surface(),
|_state: &mut WaylandState, _dh, surf| {
let parent = surf.get_parent();
let new_size = surf.get_size().unwrap_or(Vector2::from([0; 2]));
let min_size = surf
.min_size()
.map(|s| Vector2::from([s.x as f32, s.y as f32]));
let max_size = surf
.max_size()
.map(|s| Vector2::from([s.x as f32, s.y as f32]));
let logical_rectangle = surf.get_geometry().unwrap_or_default();
let mut size_changed = false;
surf.with_toplevel_info(|info| {
info.parent = parent;
if new_size != info.size {
info.size = new_size;
size_changed = true;
}
info.min_size = min_size;
info.max_size = max_size;
info.logical_rectangle = logical_rectangle;
});
if size_changed {
let Some(panel_item) = surface_panel_item(surf) else {
return;
};
if let Some(toplevel_info) = surf.get_toplevel_info() {
panel_item.toplevel_size_changed(toplevel_info.size);
}
}
},
);
add_post_commit_hook(
toplevel.wl_surface(),
|state: &mut WaylandState, _dh, surf| {
@@ -156,32 +186,6 @@ impl XdgShellHandler for WaylandState {
surf.insert_data(node);
},
);
add_post_commit_hook(
toplevel.wl_surface(),
|_state: &mut WaylandState, _dh, surf| {
let Some(panel_item) = surface_panel_item(surf) else {
return;
};
let Some(size) = surf
.get_data_raw::<RendererSurfaceStateUserData, _, _>(|surface_states| {
surface_states.lock().unwrap().surface_size()
})
.flatten()
else {
return;
};
let size = [size.w as u32, size.h as u32].into();
surf.get_data_raw::<Mutex<Vector2<u32>>, _, _>(|old_size| {
let mut old_size = old_size.lock();
if *old_size != size {
panel_item.toplevel_size_changed(size);
*old_size = size;
}
});
},
);
}
fn toplevel_destroyed(&mut self, toplevel: ToplevelSurface) {
let Some(panel_item) = surface_panel_item(toplevel.wl_surface()) else {
@@ -192,32 +196,35 @@ impl XdgShellHandler for WaylandState {
panel_item.backend.children.lock().clear();
}
fn app_id_changed(&mut self, toplevel: ToplevelSurface) {
let Some(panel_item) = surface_panel_item(toplevel.wl_surface()) else {
let wl_surface = toplevel.wl_surface();
let Some(app_id) = wl_surface.get_app_id() else {
return;
};
panel_item.toplevel_app_id_changed(
&toplevel
.wl_surface()
.get_data_raw::<XdgToplevelSurfaceData, _, _>(|d| {
d.lock().unwrap().app_id.clone().unwrap()
})
.unwrap_or_default(),
)
wl_surface.with_toplevel_info(|info| {
info.app_id = Some(app_id.clone());
});
let Some(panel_item) = surface_panel_item(wl_surface) else {
return;
};
panel_item.toplevel_app_id_changed(&app_id)
}
fn title_changed(&mut self, toplevel: ToplevelSurface) {
let Some(panel_item) = surface_panel_item(toplevel.wl_surface()) else {
let wl_surface = toplevel.wl_surface();
let Some(title) = wl_surface.get_title() else {
return;
};
panel_item.toplevel_title_changed(
&toplevel
.wl_surface()
.get_data_raw::<XdgToplevelSurfaceData, _, _>(|d| {
d.lock().unwrap().title.clone().unwrap()
})
.unwrap_or_default(),
)
wl_surface.with_toplevel_info(|info| {
info.title = Some(title.clone());
});
let Some(panel_item) = surface_panel_item(wl_surface) else {
return;
};
panel_item.toplevel_title_changed(&title)
}
fn new_popup(&mut self, popup: PopupSurface, positioner: PositionerState) {
@@ -232,12 +239,7 @@ impl XdgShellHandler for WaylandState {
popup.wl_surface().insert_data(Mutex::new(ChildInfo {
id,
parent: parent.get_data::<SurfaceId>().unwrap(),
geometry: positioner
.get_unconstrained_geometry(Rectangle {
loc: (-100000, -100000).into(),
size: (200000, 200000).into(),
})
.into(),
geometry: get_unconstrained_popup_geometry(&positioner),
z_order: 1,
receives_input: true,
}));
@@ -271,12 +273,7 @@ impl XdgShellHandler for WaylandState {
};
popup.wl_surface().with_child_info(|ci| {
ci.geometry = positioner
.get_unconstrained_geometry(Rectangle {
loc: (-100000, -100000).into(),
size: (200000, 200000).into(),
})
.into()
ci.geometry = get_unconstrained_popup_geometry(&positioner);
});
panel_item.backend.reposition_child(popup.wl_surface());
@@ -359,7 +356,6 @@ impl XdgBackend {
XdgBackend {
toplevel: Mutex::new(Some(toplevel)),
children: Mutex::new(FxHashMap::default()),
// popups: Mutex::new(FxHashMap::default()),
seat,
}
}
@@ -415,90 +411,18 @@ impl Backend for XdgBackend {
.clone()
.and_then(|s| s.upgrade().ok())
.as_ref()
.and_then(CoreSurface::from_wl_surface)
.and_then(|c| c.size())
.and_then(|c| c.get_size())
.map(|size| Geometry {
origin: [0; 2].into(),
size,
});
let toplevel = self
let toplevel_info = self
.toplevel
.lock()
.clone()
.ok_or(eyre!("Internal: no toplevel"))?;
let (app_id, title) = compositor::with_states(toplevel.wl_surface(), |states| {
let xdg_toplevel_data = states
.data_map
.get::<XdgToplevelSurfaceData>()
.ok_or(eyre!("Internal: XdgToplevelSurfaceData not found"))?;
let locked_data = xdg_toplevel_data
.lock()
.map_err(|_| eyre!("Internal: Failed to lock XdgToplevelSurfaceData"))?;
Ok::<_, color_eyre::eyre::Report>((
locked_data.app_id.clone(),
locked_data.title.clone(),
))
})?;
let toplevel_cached_state = compositor::with_states(toplevel.wl_surface(), |states| {
*states.cached_state.get::<SurfaceCachedState>().current()
});
let toplevel_core_surface = CoreSurface::from_wl_surface(toplevel.wl_surface())
.ok_or(eyre!("Internal: Failed to get CoreSurface from WlSurface"))?;
let size = toplevel
.current_state()
.size
.map(|s| Vector2::from([s.w as u32, s.h as u32]))
.or_else(|| toplevel_core_surface.size())
.unwrap_or(Vector2::from([0; 2]));
let parent = toplevel
.parent()
.as_ref()
.and_then(surface_panel_item)
.and_then(|p| p.node.upgrade())
.map(|p| p.get_id());
let toplevel = ToplevelInfo {
parent,
title,
app_id,
size,
min_size: if toplevel_cached_state.min_size.w != 0
&& toplevel_cached_state.min_size.h != 0
{
Some(
[
toplevel_cached_state.min_size.w as f32,
toplevel_cached_state.min_size.h as f32,
]
.into(),
)
} else {
None
},
max_size: if toplevel_cached_state.max_size.w != 0
&& toplevel_cached_state.max_size.h != 0
{
Some(
[
toplevel_cached_state.max_size.w as f32,
toplevel_cached_state.max_size.h as f32,
]
.into(),
)
} else {
None
},
logical_rectangle: toplevel_cached_state
.geometry
.map(Into::into)
.unwrap_or_else(|| Geometry {
origin: [0; 2].into(),
size,
}),
};
.and_then(|toplevel| toplevel.wl_surface().get_toplevel_info())
.ok_or(eyre!("Internal: no toplevel or ToplevelInfo"))?;
let children = self
.children
@@ -509,7 +433,7 @@ impl Backend for XdgBackend {
Ok(PanelItemInitData {
cursor,
toplevel,
toplevel: toplevel_info,
children,
pointer_grab: None,
keyboard_grab: None,