From c09afba366aabe67c4664ccea18b64f38c577632 Mon Sep 17 00:00:00 2001 From: Nova Date: Sat, 27 Jul 2024 15:58:55 -0400 Subject: [PATCH] feat: subsurface support --- Cargo.lock | 4 +- src/wayland/compositor.rs | 113 ++++++++++++++++++++++-------- src/wayland/xdg_shell.rs | 142 +++++++++++++++++--------------------- 3 files changed, 151 insertions(+), 108 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d879bfa..9778358 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2357,7 +2357,7 @@ checksum = "2f2b15926089e5526bb2dd738a2eb0e59034356e06eb71e1cd912358c0e62c4d" [[package]] name = "stardust-xr" version = "0.45.0" -source = "git+https://github.com/StardustXR/core.git?branch=dev#060e3a91772b4a41178ad73f35a81eb22442641e" +source = "git+https://github.com/StardustXR/core.git?branch=dev#52f75945be534b42006455395d89c91babbb1029" dependencies = [ "cluFlock", "dirs", @@ -2377,7 +2377,7 @@ dependencies = [ [[package]] name = "stardust-xr-schemas" version = "1.5.3" -source = "git+https://github.com/StardustXR/core.git?branch=dev#060e3a91772b4a41178ad73f35a81eb22442641e" +source = "git+https://github.com/StardustXR/core.git?branch=dev#52f75945be534b42006455395d89c91babbb1029" dependencies = [ "flatbuffers", "flexbuffers", diff --git a/src/wayland/compositor.rs b/src/wayland/compositor.rs index 8b8deec..6f94d7b 100644 --- a/src/wayland/compositor.rs +++ b/src/wayland/compositor.rs @@ -1,11 +1,22 @@ -use super::state::{ClientState, WaylandState}; -use crate::wayland::surface::CoreSurface; +use super::{ + state::{ClientState, WaylandState}, + utils::WlSurfaceExt, + xdg_shell::{surface_panel_item, ChildInfoExt}, +}; +use crate::{ + nodes::items::panel::{ChildInfo, Geometry, SurfaceId}, + wayland::surface::CoreSurface, +}; +use parking_lot::Mutex; use portable_atomic::{AtomicU32, Ordering}; +use rand::Rng; use smithay::{ - backend::renderer::utils::on_commit_buffer_handler, + backend::renderer::utils::{on_commit_buffer_handler, RendererSurfaceStateUserData}, delegate_compositor, reexports::wayland_server::{protocol::wl_surface::WlSurface, Client}, - wayland::compositor::{self, CompositorClientState, CompositorHandler, CompositorState}, + wayland::compositor::{ + self, add_post_commit_hook, CompositorClientState, CompositorHandler, CompositorState, + }, }; use std::sync::Arc; use tracing::debug; @@ -38,33 +49,79 @@ impl CompositorHandler for WaylandState { &client.get_data::().unwrap().compositor_state } - // fn new_subsurface(&mut self, surface: &WlSurface, parent: &WlSurface) { - // let Some(panel_item) = surface_panel_item(parent) else { - // return; - // }; - // let uid = surface.insert_data(Arc::downgrade(&panel_item)); - // } + fn new_subsurface(&mut self, surface: &WlSurface, parent: &WlSurface) { + let id = rand::thread_rng().gen_range(0..u64::MAX); + surface.insert_data(SurfaceId::Child(id)); + CoreSurface::add_to(surface); + let Some(parent_surface_id) = parent.get_data::() else { + return; + }; + surface.insert_data(Mutex::new(ChildInfo { + id, + parent: parent_surface_id, + geometry: Geometry { + origin: [0; 2].into(), + size: [256; 2].into(), + }, + z_order: 1, + })); - // fn destroyed(&mut self, surface: &WlSurface) { - // let Some(panel_item) = surface_panel_item(surface) else { - // return; - // }; - // let Some((id, _)) = panel_item - // .backend - // .subsurfaces - // .lock() - // .iter() - // .find(|(_, d)| *d == surface) - // else { - // return; - // }; - // panel_item.backend.drop_subsurface(*id); + let Some(panel_item) = surface_panel_item(parent) else { + return; + }; + let panel_item_weak = Arc::downgrade(&panel_item); + add_post_commit_hook(surface, move |_: &mut WaylandState, _dh, surf| { + if surface_panel_item(surf).is_some() { + return; + } + surf.insert_data(panel_item_weak.clone()); - // // self..lock().insert(id, (popup, positioner)); + let Some(panel_item) = surface_panel_item(surf) else { + return; + }; + panel_item.backend.new_child(surf); + }); - // let child_data = self.child_data(id).unwrap(); - // panel_item.create_child(id, &child_data); - // } + add_post_commit_hook(surface, move |_: &mut WaylandState, _dh, surf| { + let Some(view) = surf + .get_data_raw::(|s| s.lock().ok()?.view()) + .flatten() + else { + return; + }; + let mut changed = false; + surf.get_data_raw::, _, _>(|c| { + let mut info = c.lock(); + if info.geometry.origin.x != view.offset.x + && info.geometry.origin.y != view.offset.y + { + changed = true; + } + if info.geometry.size.x != view.dst.w as u32 + && info.geometry.size.y != view.dst.h as u32 + { + changed = true; + } + info.geometry.size = [view.dst.w as u32, view.dst.h as u32].into(); + }); + + let Some(panel_item) = surface_panel_item(surf) else { + return; + }; + if changed { + panel_item.backend.reposition_child(surf); + } + }); + } + + fn destroyed(&mut self, surface: &WlSurface) { + let Some(panel_item) = surface_panel_item(surface) else { + return; + }; + if surface.get_child_info().is_some() { + panel_item.backend.drop_child(surface); + } + } } delegate_compositor!(WaylandState); diff --git a/src/wayland/xdg_shell.rs b/src/wayland/xdg_shell.rs index b0e1ff2..42b2d8d 100644 --- a/src/wayland/xdg_shell.rs +++ b/src/wayland/xdg_shell.rs @@ -146,7 +146,7 @@ impl XdgShellHandler for WaylandState { }; panel_item.backend.seat.unfocus(toplevel.wl_surface(), self); panel_item.backend.toplevel.lock().take(); - panel_item.backend.popups.lock().clear(); + 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 { @@ -178,21 +178,33 @@ impl XdgShellHandler for WaylandState { } fn new_popup(&mut self, popup: PopupSurface, positioner: PositionerState) { - let uid = rand::thread_rng().gen_range(0..u64::MAX); - popup.wl_surface().insert_data(SurfaceId::Child(uid)); + let id = rand::thread_rng().gen_range(0..u64::MAX); + popup.wl_surface().insert_data(SurfaceId::Child(id)); let Some(parent) = popup.get_parent_surface() else { return; }; let _ = popup.send_configure(); CoreSurface::add_to(popup.wl_surface()); + 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(), + z_order: 1, + })); + let Some(panel_item) = surface_panel_item(&parent) else { return; }; let panel_item_weak = Arc::downgrade(&panel_item); add_post_commit_hook( popup.wl_surface(), - move |state: &mut WaylandState, _dh, surf| { + move |_: &mut WaylandState, _dh, surf| { if surface_panel_item(surf).is_some() { return; } @@ -200,15 +212,7 @@ impl XdgShellHandler for WaylandState { let Some(panel) = surface_panel_item(surf) else { return; }; - let Some(popup) = state - .xdg_shell - .popup_surfaces() - .iter() - .find(|p| p.wl_surface() == surf) - else { - return; - }; - panel.backend.new_popup(uid, popup.clone(), positioner); + panel.backend.new_child(surf); }, ); } @@ -221,21 +225,26 @@ impl XdgShellHandler for WaylandState { let Some(panel_item) = surface_panel_item(popup.wl_surface()) else { return; }; - let Some(SurfaceId::Child(uid)) = popup.wl_surface().get_data::() else { - return; - }; - panel_item.backend.reposition_popup(uid, popup, positioner) + popup + .wl_surface() + .get_data_raw::, _, _>(|ci| { + ci.lock().geometry = positioner + .get_unconstrained_geometry(Rectangle { + loc: (-100000, -100000).into(), + size: (200000, 200000).into(), + }) + .into() + }); + + panel_item.backend.reposition_child(popup.wl_surface()); } fn popup_destroyed(&mut self, popup: PopupSurface) { let Some(panel_item) = surface_panel_item(popup.wl_surface()) else { return; }; - let Some(SurfaceId::Child(uid)) = popup.wl_surface().get_data::() else { - return; - }; panel_item.backend.seat.unfocus(popup.wl_surface(), self); - panel_item.backend.drop_popup(uid); + panel_item.backend.drop_child(popup.wl_surface()); } fn grab(&mut self, _popup: PopupSurface, _seat: WlSeat, _serial: Serial) {} @@ -298,97 +307,74 @@ impl XdgShellHandler for WaylandState { } delegate_xdg_shell!(WaylandState); +pub trait ChildInfoExt { + fn get_child_info(&self) -> Option; +} +impl ChildInfoExt for WlSurface { + fn get_child_info(&self) -> Option { + self.get_data_raw::, _, _>(|c| c.lock().clone()) + } +} + pub struct XdgBackend { toplevel: Mutex>, - pub subsurfaces: Mutex>, - popups: Mutex>, + pub children: Mutex>, + // popups: Mutex>, seat: Arc, } impl XdgBackend { pub fn create(toplevel: ToplevelSurface, seat: Arc) -> Self { XdgBackend { toplevel: Mutex::new(Some(toplevel)), - subsurfaces: Mutex::new(FxHashMap::default()), - popups: Mutex::new(FxHashMap::default()), + children: Mutex::new(FxHashMap::default()), + // popups: Mutex::new(FxHashMap::default()), seat, } } fn wl_surface_from_id(&self, id: &SurfaceId) -> Option { match id { SurfaceId::Toplevel(_) => Some(self.toplevel.lock().clone()?.wl_surface().clone()), - SurfaceId::Child(popup) => { - let popups = self.popups.lock(); - Some(popups.get(popup)?.0.wl_surface().clone()) - } + SurfaceId::Child(id) => self.children.lock().get(id).cloned(), } } fn panel_item(&self) -> Option>> { surface_panel_item(self.toplevel.lock().clone()?.wl_surface()) } - pub fn new_subsurface(&self, id: u64, surface: WlSurface) { + pub fn new_child(&self, surface: &WlSurface) { let Some(panel_item) = self.panel_item() else { return; }; + let Some(child_info) = surface.get_child_info() else { + return; + }; - self.subsurfaces.lock().insert(id, surface); - - let child_data = self.child_data(id).unwrap(); - panel_item.create_child(id, &child_data); + self.children.lock().insert(child_info.id, surface.clone()); + panel_item.create_child(child_info.id, &child_info); } - pub fn drop_subsurface(&self, id: u64) { + pub fn reposition_child(&self, surface: &WlSurface) { let Some(panel_item) = self.panel_item() else { return; }; - panel_item.destroy_child(id); - self.subsurfaces.lock().remove(&id); - } + let Some(child_info) = surface.get_child_info() else { + return; + }; - pub fn new_popup(&self, id: u64, popup: PopupSurface, positioner: PositionerState) { + panel_item.reposition_child(child_info.id, &child_info.geometry); + } + pub fn drop_child(&self, surface: &WlSurface) { let Some(panel_item) = self.panel_item() else { return; }; - - self.popups.lock().insert(id, (popup, positioner)); - - let child_data = self.child_data(id).unwrap(); - panel_item.create_child(id, &child_data); - } - pub fn reposition_popup(&self, id: u64, _popup: PopupSurface, positioner: PositionerState) { - let mut popups = self.popups.lock(); - let Some((_, old_positioner)) = popups.get_mut(&id) else { + let Some(child_info) = surface.get_child_info() else { return; }; - let Some(panel_item) = self.panel_item() else { - return; - }; - let geometry = positioner.get_geometry(); - - *old_positioner = positioner; - panel_item.reposition_child(id, &geometry.into()); - } - pub fn drop_popup(&self, id: u64) { - let Some(panel_item) = self.panel_item() else { - return; - }; - panel_item.destroy_child(id); - self.popups.lock().remove(&id); + panel_item.destroy_child(child_info.id); + self.children.lock().remove(&child_info.id); } - fn child_data(&self, id: u64) -> Option { - let (popup, positioner) = self.popups.lock().get(&id).unwrap().clone(); - let parent = popup.get_parent_surface().unwrap(); - let parent = parent.get_data::().unwrap(); - Some(ChildInfo { - id, - parent, - geometry: positioner - .get_unconstrained_geometry(Rectangle { - loc: (-100000, -100000).into(), - size: (200000, 200000).into(), - }) - .into(), - }) + fn child_info(&self, id: u64) -> Option { + self.children.lock().get(&id).unwrap().get_child_info() } } impl Backend for XdgBackend { @@ -487,10 +473,10 @@ impl Backend for XdgBackend { }; let children = self - .popups + .children .lock() .keys() - .map(|k| self.child_data(*k).unwrap()) + .map(|k| self.child_info(*k).unwrap()) .collect(); Ok(PanelItemInitData {