feat: subsurface support

This commit is contained in:
Nova
2024-07-27 15:58:55 -04:00
parent 48f15e848d
commit c09afba366
3 changed files with 151 additions and 108 deletions

4
Cargo.lock generated
View File

@@ -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",

View File

@@ -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::<ClientState>().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::<SurfaceId>() 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::<RendererSurfaceStateUserData, _, _>(|s| s.lock().ok()?.view())
.flatten()
else {
return;
};
let mut changed = false;
surf.get_data_raw::<Mutex<ChildInfo>, _, _>(|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);

View File

@@ -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::<SurfaceId>().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::<SurfaceId>() else {
return;
};
panel_item.backend.reposition_popup(uid, popup, positioner)
popup
.wl_surface()
.get_data_raw::<Mutex<ChildInfo>, _, _>(|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::<SurfaceId>() 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<ChildInfo>;
}
impl ChildInfoExt for WlSurface {
fn get_child_info(&self) -> Option<ChildInfo> {
self.get_data_raw::<Mutex<ChildInfo>, _, _>(|c| c.lock().clone())
}
}
pub struct XdgBackend {
toplevel: Mutex<Option<ToplevelSurface>>,
pub subsurfaces: Mutex<FxHashMap<u64, WlSurface>>,
popups: Mutex<FxHashMap<u64, (PopupSurface, PositionerState)>>,
pub children: Mutex<FxHashMap<u64, WlSurface>>,
// popups: Mutex<FxHashMap<u64, (PopupSurface, PositionerState)>>,
seat: Arc<SeatWrapper>,
}
impl XdgBackend {
pub fn create(toplevel: ToplevelSurface, seat: Arc<SeatWrapper>) -> 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<WlSurface> {
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<Arc<PanelItem<XdgBackend>>> {
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<ChildInfo> {
let (popup, positioner) = self.popups.lock().get(&id).unwrap().clone();
let parent = popup.get_parent_surface().unwrap();
let parent = parent.get_data::<SurfaceId>().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<ChildInfo> {
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 {