From 14ebe85493744105bd48d6f99a16dc67306f0e61 Mon Sep 17 00:00:00 2001 From: Nova Date: Tue, 6 Aug 2024 20:42:46 -0400 Subject: [PATCH] refactor(wayland): update data in user data map for everything --- src/nodes/items/panel.rs | 9 ++ src/wayland/compositor.rs | 4 +- src/wayland/seat.rs | 5 +- src/wayland/surface.rs | 15 -- src/wayland/utils.rs | 111 ++++++++++++++- src/wayland/xdg_shell.rs | 290 ++++++++++++++------------------------ 6 files changed, 230 insertions(+), 204 deletions(-) diff --git a/src/nodes/items/panel.rs b/src/nodes/items/panel.rs index 5b2ebbb..32827c0 100644 --- a/src/nodes/items/panel.rs +++ b/src/nodes/items/panel.rs @@ -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", diff --git a/src/wayland/compositor.rs b/src/wayland/compositor.rs index f9f9360..1527bbc 100644 --- a/src/wayland/compositor.rs +++ b/src/wayland/compositor.rs @@ -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}, diff --git a/src/wayland/seat.rs b/src/wayland/seat.rs index 5049c0e..ddc5baf 100644 --- a/src/wayland/seat.rs +++ b/src/wayland/seat.rs @@ -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 { - 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, diff --git a/src/wayland/surface.rs b/src/wayland/surface.rs index 250538b..5044dc8 100644 --- a/src/wayland/surface.rs +++ b/src/wayland/surface.rs @@ -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 = Registry::new(); pub struct CoreSurfaceData { wl_tex: Option>, - pub size: Vector2, } 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::(|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 { self.weak_surface.upgrade().ok() } - - pub fn size(&self) -> Option> { - self.mapped_data.lock().as_ref().map(|d| d.size) - } } impl Drop for CoreSurface { fn drop(&mut self) { diff --git a/src/wayland/utils.rs b/src/wayland/utils.rs index 70711ce..b6dc842 100644 --- a/src/wayland/utils.rs +++ b/src/wayland/utils.rs @@ -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(&self, data: T) -> bool; fn get_data(&self) -> Option; fn get_data_raw O>(&self, f: F) -> Option; + fn get_current_surface_state(&self) -> SurfaceCachedState; + fn get_pending_surface_state(&self) -> SurfaceCachedState; + fn get_size(&self) -> Option>; + fn get_geometry(&self) -> Option; } impl WlSurfaceExt for WlSurface { fn insert_data(&self, data: T) -> bool { @@ -17,4 +33,97 @@ impl WlSurfaceExt for WlSurface { fn get_data_raw O>(&self, f: F) -> Option { compositor::with_states(self, |d| Some((f)(d.data_map.get::()?))) } + fn get_current_surface_state(&self) -> SurfaceCachedState { + compositor::with_states(self, |states| { + states + .cached_state + .get::() + .current() + .clone() + }) + } + fn get_pending_surface_state(&self) -> SurfaceCachedState { + compositor::with_states(self, |states| { + states + .cached_state + .get::() + .pending() + .clone() + }) + } + fn get_size(&self) -> Option> { + self.get_data_raw::(|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 { + self.get_current_surface_state().geometry.map(|r| r.into()) + } +} + +pub trait ToplevelInfoExt { + fn get_toplevel_info(&self) -> Option; + fn with_toplevel_info O>(&self, f: F) -> Option; + + fn get_parent(&self) -> Option; + fn get_app_id(&self) -> Option; + fn get_title(&self) -> Option; + fn min_size(&self) -> Option>; + fn max_size(&self) -> Option>; +} +impl ToplevelInfoExt for WlSurface { + fn get_toplevel_info(&self) -> Option { + self.get_data_raw::, _, _>(|c| c.lock().clone()) + } + fn with_toplevel_info O>(&self, f: F) -> Option { + self.get_data_raw::, _, _>(|r| (f)(&mut r.lock())) + } + + fn get_parent(&self) -> Option { + self.get_data_raw::(|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 { + self.get_data_raw::(|d| d.lock().ok()?.app_id.clone()) + .flatten() + } + fn get_title(&self) -> Option { + self.get_data_raw::(|d| d.lock().ok()?.title.clone()) + .flatten() + } + fn min_size(&self) -> Option> { + 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> { + 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; + fn with_child_info O>(&self, f: F) -> Option; +} +impl ChildInfoExt for WlSurface { + fn get_child_info(&self) -> Option { + self.get_data_raw::, _, _>(|c| c.lock().clone()) + } + fn with_child_info O>(&self, f: F) -> Option { + self.get_data_raw::, _, _>(|r| (f)(&mut r.lock())) + } } diff --git a/src/wayland/xdg_shell.rs b/src/wayland/xdg_shell.rs index 63dc524..50db4a0 100644 --- a/src/wayland/xdg_shell.rs +++ b/src/wayland/xdg_shell.rs @@ -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> for Geometry { fn from(value: Rectangle) -> Self { Geometry { @@ -49,49 +57,6 @@ impl From> for Geometry { } } -// pub trait ToplevelInfoExt { -// fn get_toplevel_info(&self) -> Option; -// fn with_toplevel_info O>(&self, f: F) -> Option; -// fn get_toplevel_state(&self) -> Option; - -// fn get_app_id(&self) -> Option; -// fn get_title(&self) -> Option; -// } -// impl ToplevelInfoExt for WlSurface { -// fn get_toplevel_info(&self) -> Option { -// self.get_data_raw::, _, _>(|c| c.lock().clone()) -// } -// fn with_toplevel_info O>(&self, f: F) -> Option { -// self.get_data_raw::, _, _>(|r| (f)(&mut r.lock())) -// } -// fn get_toplevel_state(&self) -> Option { -// self.get_data_raw::(|r| r.lock().unwrap().current.clone()) -// } - -// fn get_app_id(&self) -> Option { -// self.get_data_raw::(|d| { -// d.lock().unwrap().app_id.clone().unwrap() -// }) -// } -// fn get_title(&self) -> Option { -// self.get_data_raw::(|d| { -// d.lock().unwrap().title.clone().unwrap() -// }) -// } -// } -pub trait ChildInfoExt { - fn get_child_info(&self) -> Option; - fn with_child_info O>(&self, f: F) -> Option; -} -impl ChildInfoExt for WlSurface { - fn get_child_info(&self) -> Option { - self.get_data_raw::, _, _>(|c| c.lock().clone()) - } - fn with_child_info O>(&self, f: F) -> Option { - self.get_data_raw::, _, _>(|r| (f)(&mut r.lock())) - } -} - pub fn surface_panel_item(wl_surface: &WlSurface) -> Option>> { let panel_item = wl_surface .get_data::>>() @@ -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::(|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::>, _, _>(|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::(|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::(|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::().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::() - .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::().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,