From 17583471bf6874a6edf50989c602f520fb67c707 Mon Sep 17 00:00:00 2001 From: Nova Date: Sun, 25 Dec 2022 16:01:23 -0500 Subject: [PATCH] feat(wayland): configure and commit for toplevel] --- src/nodes/items/mod.rs | 4 +- src/wayland/compositor.rs | 19 +- src/wayland/decoration.rs | 118 +++++++++-- src/wayland/mod.rs | 29 +-- src/wayland/panel_item.rs | 325 +++++++++++++++++------------- src/wayland/seat.rs | 94 ++++----- src/wayland/state.rs | 13 +- src/wayland/surface.rs | 201 ++++++++----------- src/wayland/xdg_shell.rs | 405 ++++++++++++++++++++++++++++++++------ 9 files changed, 786 insertions(+), 422 deletions(-) diff --git a/src/nodes/items/mod.rs b/src/nodes/items/mod.rs index 0f6a217..0b99439 100644 --- a/src/nodes/items/mod.rs +++ b/src/nodes/items/mod.rs @@ -175,7 +175,7 @@ pub trait ItemSpecialization { pub enum ItemType { Environment(EnvironmentItem), #[cfg(feature = "wayland")] - Panel(PanelItem), + Panel(Arc), } impl Deref for ItemType { type Target = dyn ItemSpecialization; @@ -184,7 +184,7 @@ impl Deref for ItemType { match self { ItemType::Environment(item) => item, #[cfg(feature = "wayland")] - ItemType::Panel(item) => item, + ItemType::Panel(item) => &**item, } } } diff --git a/src/wayland/compositor.rs b/src/wayland/compositor.rs index 66bc543..c07645e 100644 --- a/src/wayland/compositor.rs +++ b/src/wayland/compositor.rs @@ -1,9 +1,10 @@ -use super::{state::WaylandState, surface::CoreSurface}; +use super::{panel_item::PanelItem, state::WaylandState, surface::CoreSurface}; use smithay::{ delegate_compositor, reexports::wayland_server::protocol::wl_surface::WlSurface, wayland::compositor::{self, CompositorHandler, CompositorState}, }; +use std::sync::Arc; impl CompositorHandler for WaylandState { fn compositor_state(&mut self) -> &mut CompositorState { @@ -11,16 +12,12 @@ impl CompositorHandler for WaylandState { } fn commit(&mut self, surface: &WlSurface) { - compositor::with_states(surface, |data| { - data.data_map.insert_if_missing_threadsafe(|| { - CoreSurface::new( - &self.weak_ref.upgrade().unwrap(), - &self.display, - self.display_handle.clone(), - surface, - ) - }) - }); + CoreSurface::add_to(&self.display, self.display_handle.clone(), surface); + if let Some(panel_item) = compositor::with_states(surface, |data| { + data.data_map.get::>().cloned() + }) { + panel_item.commit_toplevel(); + }; } } diff --git a/src/wayland/decoration.rs b/src/wayland/decoration.rs index 69380b3..1d5959f 100644 --- a/src/wayland/decoration.rs +++ b/src/wayland/decoration.rs @@ -1,30 +1,110 @@ -use super::state::WaylandState; +use super::{state::WaylandState, xdg_shell::XdgSurfaceData}; use smithay::{ - delegate_kde_decoration, delegate_xdg_decoration, - reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode, - wayland::shell::{ - self, kde::decoration::KdeDecorationHandler, xdg::decoration::XdgDecorationHandler, + delegate_kde_decoration, + reexports::{ + wayland_protocols::xdg::{ + decoration::zv1::server::{ + zxdg_decoration_manager_v1::{self, ZxdgDecorationManagerV1}, + zxdg_toplevel_decoration_v1::{self, Mode, ZxdgToplevelDecorationV1}, + }, + shell::server::xdg_toplevel::XdgToplevel, + }, + wayland_server::{ + Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, Weak, + }, }, + wayland::shell::{self, kde::decoration::KdeDecorationHandler}, }; -impl XdgDecorationHandler for WaylandState { - fn new_decoration(&mut self, toplevel: smithay::wayland::shell::xdg::ToplevelSurface) { - toplevel.with_pending_state(|state| { - state.decoration_mode = Some(Mode::ServerSide); - }); - toplevel.send_configure(); - } +// impl XdgDecorationHandler for WaylandState { +// fn new_decoration(&mut self, toplevel: smithay::wayland::shell::xdg::ToplevelSurface) { +// toplevel.with_pending_state(|state| { +// state.decoration_mode = Some(Mode::ServerSide); +// }); +// toplevel.send_configure(); +// } - fn request_mode( - &mut self, - _toplevel: smithay::wayland::shell::xdg::ToplevelSurface, - _mode: smithay::reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode, +// fn request_mode( +// &mut self, +// _toplevel: smithay::wayland::shell::xdg::ToplevelSurface, +// _mode: smithay::reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode, +// ) { +// } + +// fn unset_mode(&mut self, _toplevel: smithay::wayland::shell::xdg::ToplevelSurface) {} +// } +// delegate_xdg_decoration!(WaylandState); + +impl GlobalDispatch for WaylandState { + fn bind( + _state: &mut WaylandState, + _handle: &DisplayHandle, + _client: &Client, + resource: New, + _global_data: &(), + data_init: &mut DataInit<'_, WaylandState>, ) { + data_init.init(resource, ()); + } +} + +impl Dispatch for WaylandState { + fn request( + _state: &mut WaylandState, + _client: &Client, + _resource: &ZxdgDecorationManagerV1, + request: zxdg_decoration_manager_v1::Request, + _data: &(), + _dhandle: &DisplayHandle, + data_init: &mut DataInit<'_, WaylandState>, + ) { + match request { + zxdg_decoration_manager_v1::Request::Destroy => todo!(), + zxdg_decoration_manager_v1::Request::GetToplevelDecoration { id, toplevel } => { + data_init.init(id, toplevel.downgrade()); + } + _ => unreachable!(), + } + } +} +impl Dispatch, WaylandState> for WaylandState { + fn request( + _state: &mut WaylandState, + _client: &Client, + resource: &ZxdgToplevelDecorationV1, + request: zxdg_toplevel_decoration_v1::Request, + data: &Weak, + _dhandle: &DisplayHandle, + _data_init: &mut DataInit<'_, WaylandState>, + ) { + match request { + zxdg_toplevel_decoration_v1::Request::SetMode { mode: _ } => { + resource.configure(Mode::ServerSide); + data.upgrade() + .unwrap() + .data::() + .unwrap() + .xdg_surface + .upgrade() + .unwrap() + .configure(0); + } + zxdg_toplevel_decoration_v1::Request::UnsetMode => { + resource.configure(Mode::ServerSide); + data.upgrade() + .unwrap() + .data::() + .unwrap() + .xdg_surface + .upgrade() + .unwrap() + .configure(0); + } + zxdg_toplevel_decoration_v1::Request::Destroy => (), + _ => unreachable!(), + } } - - fn unset_mode(&mut self, _toplevel: smithay::wayland::shell::xdg::ToplevelSurface) {} } -delegate_xdg_decoration!(WaylandState); impl KdeDecorationHandler for WaylandState { fn kde_decoration_state(&self) -> &shell::kde::decoration::KdeDecorationState { diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index 10d95c0..444d372 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -9,28 +9,28 @@ mod surface; mod xdg_activation; mod xdg_shell; -use self::{panel_item::PanelItem, state::WaylandState, surface::CORE_SURFACES}; +use self::{state::WaylandState, surface::CORE_SURFACES}; use crate::wayland::state::ClientState; use color_eyre::eyre::{ensure, Result}; use once_cell::sync::OnceCell; use parking_lot::Mutex; use slog::Drain; use smithay::{ - backend::{egl::EGLContext, renderer::{gles2::Gles2Renderer}}, - reexports::wayland_server::{backend::GlobalId, Display, ListeningSocket, Resource}, + backend::{egl::EGLContext, renderer::gles2::Gles2Renderer}, + reexports::wayland_server::{backend::GlobalId, Display, ListeningSocket}, }; -use tracing::info; +use std::os::unix::prelude::AsRawFd; use std::{ ffi::c_void, os::unix::{net::UnixListener, prelude::FromRawFd}, sync::Arc, }; -use std::{os::unix::prelude::AsRawFd}; use stereokit as sk; use stereokit::StereoKit; use tokio::{ io::unix::AsyncFd, net::UnixListener as AsyncUnixListener, sync::mpsc, task::JoinHandle, }; +use tracing::info; struct EGLRawHandles { display: *const c_void, @@ -147,26 +147,9 @@ impl Wayland { pub fn frame(&mut self, sk: &StereoKit) { for core_surface in CORE_SURFACES.get_valid_contents() { - let Some(client_id) = - core_surface - .wl_surface() - .and_then(|surf| surf.client()) - .map(|c| c.id()) else { continue }; let state = self.state.lock(); - let Some(seat_data) = state.seats.get(&client_id).cloned() else { continue }; let output = state.output.clone(); - core_surface.process( - sk, - &mut self.renderer, - output, - &self.log, - |data| { - PanelItem::on_mapped(&core_surface, data, seat_data); - }, - |data| { - PanelItem::if_mapped(&core_surface, data); - }, - ); + core_surface.process(sk, &mut self.renderer, output, &self.log); } self.display.lock().flush_clients().unwrap(); diff --git a/src/wayland/panel_item.rs b/src/wayland/panel_item.rs index 6ac4c2a..2bf4bd5 100644 --- a/src/wayland/panel_item.rs +++ b/src/wayland/panel_item.rs @@ -1,6 +1,7 @@ use super::{ - seat::{KeyboardInfo, SeatData}, + seat::{Cursor, KeyboardInfo, SeatData}, surface::CoreSurface, + xdg_shell::{XdgSurfaceData, XdgToplevelData}, }; use crate::{ core::{ @@ -18,14 +19,23 @@ use glam::Mat4; use lazy_static::lazy_static; use mint::Vector2; use nanoid::nanoid; -use serde::Deserialize; +use parking_lot::Mutex; +use serde::{Deserialize, Serialize}; use smithay::{ - reexports::wayland_server::protocol::wl_pointer::{Axis, ButtonState}, - utils::Size, - wayland::{ - compositor::SurfaceData, - shell::xdg::{Configure, XdgToplevelSurfaceData}, + reexports::{ + wayland_protocols::xdg::shell::server::xdg_toplevel::{ + XdgToplevel, EVT_CONFIGURE_BOUNDS_SINCE, + }, + wayland_server::{ + backend::Credentials, + protocol::{ + wl_pointer::{Axis, ButtonState}, + wl_surface::WlSurface, + }, + Resource, Weak as WlWeak, + }, }, + wayland::compositor, }; use stardust_xr::schemas::flex::{deserialize, serialize}; use std::sync::{Arc, Weak}; @@ -48,20 +58,57 @@ lazy_static! { "close", ], aliased_local_methods: vec![], - aliased_remote_signals: vec!["resize", "set_cursor",], + aliased_remote_signals: vec!["commit_toplevel", "set_cursor",], ui: Default::default(), items: Registry::new(), acceptors: Registry::new(), }; } +#[derive(Debug, Clone, Serialize)] +pub struct ToplevelState { + #[serde(skip_serializing)] + pub mapped: bool, + #[serde(skip_serializing)] + pub parent: Option>, + pub title: String, + pub app_id: String, + pub size: Vector2, + pub max_size: Vector2, + pub min_size: Vector2, + pub states: Vec, + #[serde(skip_serializing)] + pub queued_state: Option>, +} +impl Default for ToplevelState { + fn default() -> Self { + Self { + mapped: false, + parent: None, + title: String::default(), + app_id: String::default(), + size: Vector2::from([0; 2]), + max_size: Vector2::from([0; 2]), + min_size: Vector2::from([0; 2]), + states: Vec::new(), + queued_state: None, + } + } +} + pub struct PanelItem { node: Weak, - core_surface: Weak, + client_credentials: Option, + pub toplevel: WlWeak, + pub cursor: Mutex>>, seat_data: SeatData, } impl PanelItem { - pub fn create(core_surface: &Arc, seat_data: SeatData) -> Arc { + pub fn create( + toplevel: XdgToplevel, + client_credentials: Option, + seat_data: SeatData, + ) -> (Arc, Arc) { let node = Arc::new(Node::create( &INTERNAL_CLIENT, "/item/panel/item", @@ -69,17 +116,23 @@ impl PanelItem { true, )); let spatial = Spatial::add_to(&node, None, Mat4::IDENTITY, false).unwrap(); - - let specialization = ItemType::Panel(PanelItem { + let panel_item = Arc::new(PanelItem { node: Arc::downgrade(&node), - core_surface: Arc::downgrade(core_surface), + client_credentials, + toplevel: toplevel.downgrade(), + cursor: Mutex::new(None), seat_data, }); - let item = Item::add_to(&node, &ITEM_TYPE_INFO_PANEL, specialization); - if let ItemType::Panel(panel) = &item.specialization { - let _ = panel.seat_data.panel_item.set(Arc::downgrade(&item)); - } + let _ = panel_item + .seat_data + .panel_item + .set(Arc::downgrade(&panel_item)); + let item = Item::add_to( + &node, + &ITEM_TYPE_INFO_PANEL, + ItemType::Panel(panel_item.clone()), + ); node.add_local_signal( "apply_surface_material", PanelItem::apply_surface_material_flex, @@ -102,11 +155,11 @@ impl PanelItem { ); node.add_local_signal("keyboard_deactivate", PanelItem::keyboard_deactivate_flex); node.add_local_signal("keyboard_key_state", PanelItem::keyboard_key_state_flex); - node.add_local_signal("resize", PanelItem::resize_flex); + node.add_local_signal("configure_toplevel", PanelItem::configure_toplevel_flex); - if let Some(startup_settings) = core_surface - .pid() - .and_then(|pid| get_env(pid).ok()) + if let Some(startup_settings) = panel_item + .client_credentials + .and_then(|cred| get_env(cred.pid).ok()) .and_then(|env| startup_settings(&env)) { spatial.set_local_transform(startup_settings.transform); @@ -119,16 +172,45 @@ impl PanelItem { } } - node + (node, panel_item) } pub fn from_node(node: &Node) -> Option<&PanelItem> { node.item.get().and_then(|item| match &item.specialization { - ItemType::Panel(panel_item) => Some(panel_item), + ItemType::Panel(panel_item) => Some(&**panel_item), _ => None, }) } + fn toplevel_surface_data(&self) -> Option { + Some( + self.toplevel + .upgrade() + .ok()? + .data::()? + .xdg_surface_data + .clone(), + ) + } + pub fn toplevel_state(&self) -> Option>> { + Some( + self.toplevel + .upgrade() + .ok()? + .data::()? + .state + .clone(), + ) + } + fn toplevel_wl_surface(&self) -> Option { + self.toplevel_surface_data()?.wl_surface.upgrade().ok() + } + fn core_surface(&self) -> Option> { + compositor::with_states(&self.toplevel_wl_surface()?, |data| { + data.data_map.get::>().cloned() + }) + } + fn apply_surface_material_flex( node: &Node, calling_client: Arc, @@ -150,7 +232,7 @@ impl PanelItem { .ok_or_else(|| eyre!("Node is not a model"))?; if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization { - if let Some(core_surface) = panel_item.core_surface.upgrade() { + if let Some(core_surface) = panel_item.core_surface() { core_surface.apply_material(model.clone(), info.idx); } } @@ -164,9 +246,8 @@ impl PanelItem { data: &[u8], ) -> Result<()> { let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) }; - let cursor = panel_item.seat_data.cursor.lock(); - let Some(cursor) = &*cursor else { return Ok(())}; - let Some(core_surface) = cursor.lock().core_surface.upgrade() else { return Ok(()) }; + let Some(cursor) = panel_item.seat_data.cursor() else { return Ok(())}; + let Some(core_surface) = CoreSurface::from_wl_surface(&cursor) else { return Ok(()) }; #[derive(Deserialize)] struct SurfaceMaterialInfo<'a> { @@ -188,65 +269,6 @@ impl PanelItem { Ok(()) } - pub fn on_mapped( - core_surface: &Arc, - surface_data: &SurfaceData, - seat_data: SeatData, - ) { - if surface_data - .data_map - .get::() - .is_some() - { - surface_data - .data_map - .insert_if_missing_threadsafe(|| PanelItem::create(core_surface, seat_data)); - } - } - - pub fn if_mapped(_core_surface: &Arc, surface_data: &SurfaceData) { - let Some(panel_node) = surface_data.data_map.get::>() else { return }; - let Some(panel_item) = PanelItem::from_node(panel_node) else { return }; - - panel_item.set_cursor(); - } - - pub fn ack_resize(&self, xdg_config: Configure) { - let Configure::Toplevel(config) = xdg_config else { return }; - let Some(size) = config.state.size else { return }; - let Some(core_surface) = self.core_surface.upgrade() else { return }; - core_surface.with_data(|data| data.size = Vector2::from([size.w as u32, size.h as u32])); - let _ = self - .node - .upgrade() - .unwrap() - .send_remote_signal("resize", &serialize((size.w, size.h)).unwrap()); - } - - pub fn set_cursor(&self) { - let mut cursor_changed = self.seat_data.cursor_changed.lock(); - if !*cursor_changed { - return; - } - let mut data = serialize(()).unwrap(); - - let cursor = self.seat_data.cursor.lock(); - if let Some(cursor) = cursor.as_ref().map(|cursor| cursor.lock()) { - if let Some(core_surface) = cursor.core_surface.upgrade() { - core_surface.with_data(|mapped_data| { - data = serialize((mapped_data.size, cursor.hotspot)).unwrap(); - }); - } - } - - let _ = self - .node - .upgrade() - .unwrap() - .send_remote_signal("set_cursor", &data); - *cursor_changed = false; - } - fn pointer_deactivate_flex( node: &Node, _calling_client: Arc, @@ -256,7 +278,7 @@ impl PanelItem { if !panel_item.seat_data.pointer_active() { return Ok(()); } - let Some(core_surface) = panel_item.core_surface.upgrade() else { return Ok(()) }; + let Some(core_surface) = panel_item.core_surface() else { return Ok(()) }; let Some(wl_surface) = core_surface.wl_surface() else { return Ok(()) }; let Some(pointer) = panel_item.seat_data.pointer() else { return Ok(()) }; @@ -270,7 +292,7 @@ impl PanelItem { fn pointer_motion_flex(node: &Node, _calling_client: Arc, data: &[u8]) -> Result<()> { let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) }; - let Some(core_surface) = panel_item.core_surface.upgrade() else { return Ok(()) }; + let Some(core_surface) = panel_item.core_surface() else { return Ok(()) }; let Some(wl_surface) = core_surface.wl_surface() else { return Ok(()) }; let Some(pointer) = panel_item.seat_data.pointer() else { return Ok(()) }; @@ -297,7 +319,7 @@ impl PanelItem { if !panel_item.seat_data.pointer_active() { return Ok(()); } - let Some(core_surface) = panel_item.core_surface.upgrade() else { return Ok(()) }; + let Some(core_surface) = panel_item.core_surface() else { return Ok(()) }; let Some(pointer) = panel_item.seat_data.pointer() else { return Ok(()) }; let (button, state): (u32, u32) = deserialize(data)?; @@ -324,7 +346,7 @@ impl PanelItem { if !panel_item.seat_data.pointer_active() { return Ok(()); } - let Some(core_surface) = panel_item.core_surface.upgrade() else { return Ok(()) }; + let Some(core_surface) = panel_item.core_surface() else { return Ok(()) }; let Some(pointer) = panel_item.seat_data.pointer() else { return Ok(()) }; #[derive(Deserialize)] @@ -399,7 +421,7 @@ impl PanelItem { fn keyboard_activate_flex(node: &Node, keymap: &Keymap) -> Result<()> { let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) }; - let Some(core_surface) = panel_item.core_surface.upgrade() else { return Ok(()) }; + let Some(core_surface) = panel_item.core_surface() else { return Ok(()) }; let Some(wl_surface) = core_surface.wl_surface() else { return Ok(()) }; let Some(keyboard) = panel_item.seat_data.keyboard() else { return Ok(()) }; @@ -420,7 +442,7 @@ impl PanelItem { _data: &[u8], ) -> Result<()> { let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) }; - let Some(core_surface) = panel_item.core_surface.upgrade() else { return Ok(()) }; + let Some(core_surface) = panel_item.core_surface() else { return Ok(()) }; let Some(wl_surface) = core_surface.wl_surface() else { return Ok(()) }; let Some(keyboard) = panel_item.seat_data.keyboard() else { return Ok(()) }; @@ -450,55 +472,94 @@ impl PanelItem { Ok(()) } - fn resize_flex(node: &Node, _calling_client: Arc, data: &[u8]) -> Result<()> { + fn configure_toplevel_flex( + node: &Node, + _calling_client: Arc, + data: &[u8], + ) -> Result<()> { let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) }; - let Some(core_surface) = panel_item.core_surface.upgrade() else { return Ok(()) }; - let Some(wl_surface) = core_surface.wl_surface() else { return Ok(()) }; - let size: Vector2 = deserialize(data)?; + let Ok(xdg_toplevel) = panel_item.toplevel.upgrade() else { return Ok(()) }; + let Some(xdg_surface) = panel_item.toplevel_surface_data().and_then(|d| d.xdg_surface.upgrade().ok()) else { return Ok(()) }; - let toplevel_surface = core_surface - .wayland_state() - .lock() - .xdg_shell_state - .toplevel_surfaces(|surfaces| { - surfaces - .iter() - .find(|surf| surf.wl_surface().clone() == wl_surface) - .cloned() - }); - - if let Some(toplevel_surface) = toplevel_surface { - let mut size_set = false; - toplevel_surface.with_pending_state(|state| { - state.size = Some(Size::default()); - state.size.as_mut().unwrap().w = size.x as i32; - state.size.as_mut().unwrap().h = size.y as i32; - size_set = true; - }); - if size_set { - toplevel_surface.send_configure(); - } + #[derive(Deserialize)] + struct ConfigureToplevelInfo { + size: Option>, + states: Vec, + bounds: Option>, } + let info: ConfigureToplevelInfo = deserialize(data)?; + if let Some(xdg_state) = panel_item.toplevel_state() { + xdg_state.lock().queued_state.as_mut().unwrap().states = info.states.clone(); + } + if let Some(bounds) = info.bounds { + if xdg_toplevel.version() > EVT_CONFIGURE_BOUNDS_SINCE { + xdg_toplevel.configure_bounds(bounds.x as i32, bounds.y as i32); + } + } + let size = info.size.unwrap_or(Vector2::from([0; 2])); + xdg_toplevel.configure(size.x as i32, size.y as i32, info.states); + xdg_surface.configure(0); + Ok(()) } + + pub fn commit_toplevel(&self) { + let mapped = self.core_surface().map(|c| c.mapped()).unwrap_or(false); + let Some(state) = self.toplevel_state() else { return }; + let Some(surface_data) = self.toplevel_surface_data() else { return }; + let mut state = state.lock(); + { + let queued_state = state.queued_state.as_mut().unwrap(); + queued_state.mapped = mapped; + queued_state.size = *surface_data.size.lock(); + } + + let Some(node) = self.node.upgrade() else { return }; + let queued_state = state.queued_state.take().unwrap(); + *state = (*queued_state).clone(); + state.queued_state = Some(queued_state); + + let _ = node.send_remote_signal("commit_toplevel", &serialize(&*state).unwrap()); + } + + pub fn set_cursor(&self, surface: Option<&WlSurface>, hotspot_x: i32, hotspot_y: i32) { + let Some(node) = self.node.upgrade() else { return }; + let mut data = serialize(()).unwrap(); + + let cursor_size = surface + .and_then(|c| CoreSurface::from_wl_surface(c)) + .and_then(|c| c.with_data(|data| data.size)); + + if let Some(size) = cursor_size { + data = serialize((size, (hotspot_x, hotspot_y))).unwrap(); + } + + let _ = node.send_remote_signal("set_cursor", &data); + } } impl ItemSpecialization for PanelItem { fn serialize_start_data(&self, id: &str) -> Vec { - // Panel size - let panel_size = self - .core_surface - .upgrade() - .unwrap() - .with_data(|data| data.size); + let cursor = self.cursor.lock().as_ref().and_then(|c| c.upgrade().ok()); + let cursor_size = cursor + .as_ref() + .and_then(|c| CoreSurface::from_wl_surface(&c)) + .and_then(|c| c.with_data(|data| data.size)); + let cursor_hotspot = cursor + .and_then(|c| { + compositor::with_states(&c, |data| data.data_map.get::>().cloned()) + }) + .map(|cursor| cursor.hotspot); - let cursor_lock = (*self.seat_data.cursor.lock()).clone(); - let cursor_size = cursor_lock - .clone() - .and_then(|cursor| cursor.lock().core_surface.upgrade()) - .and_then(|surf| surf.with_data(|data| data.size)); - let cursor_hotspot = cursor_lock.map(|cursor| cursor.lock().hotspot); - - serialize((id, (panel_size, cursor_size.zip(cursor_hotspot)))).unwrap() + let toplevel_state = self.toplevel_state(); + let toplevel_state = toplevel_state.as_ref().map(|state| state.lock()); + serialize(( + id, + ( + toplevel_state.and_then(|state| state.mapped.then_some(state.clone())), + cursor_size.zip(cursor_hotspot), + ), + )) + .unwrap() } } diff --git a/src/wayland/seat.rs b/src/wayland/seat.rs index 8fbc5eb..33a9db2 100644 --- a/src/wayland/seat.rs +++ b/src/wayland/seat.rs @@ -1,5 +1,6 @@ -use super::{state::WaylandState, surface::CoreSurface, GLOBAL_DESTROY_QUEUE}; -use crate::nodes::items::Item; +use super::{ + panel_item::PanelItem, state::WaylandState, surface::CoreSurface, GLOBAL_DESTROY_QUEUE, +}; use color_eyre::eyre::Result; use mint::Vector2; use nanoid::nanoid; @@ -9,11 +10,11 @@ use smithay::{ input::keyboard::{KeymapFile, ModifiersState}, reexports::wayland_server::{ backend::{ClientId, GlobalId}, - delegate_dispatch, delegate_global_dispatch, protocol::{ wl_keyboard::{self, KeyState, WlKeyboard}, wl_pointer::{self, WlPointer}, wl_seat::{self, Capability, WlSeat, EVT_NAME_SINCE}, + wl_surface::WlSurface, wl_touch::{self, WlTouch}, }, Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, @@ -25,7 +26,6 @@ use std::{ops::Deref, sync::Weak}; use xkbcommon::xkb::{self, Keymap}; pub struct Cursor { - pub core_surface: Weak, pub hotspot: Vector2, } @@ -70,8 +70,6 @@ impl KeyboardInfo { } unsafe impl Send for KeyboardInfo {} -pub struct SeatDelegate; - #[derive(Clone)] pub struct SeatData(Arc); impl SeatData { @@ -80,8 +78,6 @@ impl SeatData { client, global_id: OnceCell::new(), panel_item: OnceCell::new(), - cursor: Mutex::new(None), - cursor_changed: Mutex::new(false), pointer: OnceCell::new(), pointer_active: Mutex::new(false), keyboard: OnceCell::new(), @@ -107,10 +103,8 @@ impl Deref for SeatData { pub struct SeatDataInner { client: ClientId, - pub global_id: OnceCell, - pub panel_item: OnceCell>, - pub cursor: Mutex>>>, - pub cursor_changed: Mutex, + global_id: OnceCell, + pub panel_item: OnceCell>, pointer: OnceCell, pub pointer_active: Mutex, keyboard: OnceCell, @@ -131,6 +125,16 @@ impl SeatDataInner { pub fn touch(&self) -> Option<&WlTouch> { self.touch.get() } + + pub fn cursor(&self) -> Option { + self.panel_item + .get()? + .upgrade()? + .cursor + .lock() + .as_ref() + .and_then(|c| c.upgrade().ok()) + } } impl Drop for SeatDataInner { fn drop(&mut self) { @@ -139,7 +143,7 @@ impl Drop for SeatDataInner { } } -impl GlobalDispatch for SeatDelegate { +impl GlobalDispatch for WaylandState { fn bind( _state: &mut WaylandState, _handle: &DisplayHandle, @@ -161,9 +165,8 @@ impl GlobalDispatch for SeatDelegate { client.id() == data.0.client } } -delegate_global_dispatch!(WaylandState: [WlSeat: SeatData] => SeatDelegate); -impl Dispatch for SeatDelegate { +impl Dispatch for WaylandState { fn request( _state: &mut WaylandState, _client: &Client, @@ -190,14 +193,13 @@ impl Dispatch for SeatDelegate { } } } -delegate_dispatch!(WaylandState: [WlSeat: SeatData] => SeatDelegate); -impl Dispatch for SeatDelegate { +impl Dispatch for WaylandState { fn request( state: &mut WaylandState, _client: &Client, _resource: &WlPointer, - request: ::Request, + request: wl_pointer::Request, seat_data: &SeatData, dh: &DisplayHandle, _data_init: &mut DataInit<'_, WaylandState>, @@ -209,54 +211,42 @@ impl Dispatch for SeatDelegate { hotspot_x, hotspot_y, } => { - // if !seat_data.pointer_active() { - // return; - // } - *seat_data.0.cursor_changed.lock() = true; if let Some(surface) = surface.as_ref() { + CoreSurface::add_to(&state.display, dh.clone(), surface); compositor::with_states(surface, |data| { data.data_map.insert_if_missing_threadsafe(|| { - CoreSurface::new( - &state.weak_ref.upgrade().unwrap(), - &state.display, - dh.clone(), - surface, - ) - }); - if !data.data_map.insert_if_missing_threadsafe(|| { Arc::new(Mutex::new(Cursor { - core_surface: Arc::downgrade( - data.data_map.get::>().unwrap(), - ), hotspot: Vector2::from([hotspot_x, hotspot_y]), })) - }) { - let mut cursor = - data.data_map.get::>>().unwrap().lock(); - cursor.hotspot = Vector2::from([hotspot_x, hotspot_y]); + }); + let mut cursor = data.data_map.get::>>().unwrap().lock(); + cursor.hotspot = Vector2::from([hotspot_x, hotspot_y]); + + if let Some(core_surface) = data.data_map.get::>() { + core_surface.set_material_offset(1); } }) } - *seat_data.cursor.lock() = surface.and_then(|surf| { - compositor::with_states(&surf, |data| { - let cursor = data.data_map.get::>>(); - if let Some(cursor) = cursor { - if let Some(core_surface) = cursor.lock().core_surface.upgrade() { - core_surface.set_material_offset(1); - } - } - cursor.cloned() - }) - }); + *seat_data + .panel_item + .get() + .unwrap() + .upgrade() + .unwrap() + .cursor + .lock() = surface.as_ref().map(|surf| surf.downgrade()); + + if let Some(panel_item) = seat_data.panel_item.get().and_then(|i| i.upgrade()) { + panel_item.set_cursor(surface.as_ref(), hotspot_x, hotspot_y); + } } wl_pointer::Request::Release => (), _ => unreachable!(), } } } -delegate_dispatch!(WaylandState: [WlPointer: SeatData] => SeatDelegate); -impl Dispatch for SeatDelegate { +impl Dispatch for WaylandState { fn request( _state: &mut WaylandState, _client: &Client, @@ -272,9 +262,8 @@ impl Dispatch for SeatDelegate { } } } -delegate_dispatch!(WaylandState: [WlKeyboard: SeatData] => SeatDelegate); -impl Dispatch for SeatDelegate { +impl Dispatch for WaylandState { fn request( _state: &mut WaylandState, _client: &Client, @@ -290,4 +279,3 @@ impl Dispatch for SeatDelegate { } } } -delegate_dispatch!(WaylandState: [WlTouch: SeatData] => SeatDelegate); diff --git a/src/wayland/state.rs b/src/wayland/state.rs index 9f67adc..0b6233f 100644 --- a/src/wayland/state.rs +++ b/src/wayland/state.rs @@ -10,6 +10,7 @@ use smithay::{ delegate_dmabuf, delegate_output, delegate_shm, output::{Mode, Output, Scale, Subpixel}, reexports::{ + wayland_protocols::xdg::shell::server::xdg_wm_base::XdgWmBase, wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration_manager::Mode as DecorationMode, wayland_server::{ backend::{ClientData, ClientId, DisconnectReason}, @@ -23,10 +24,7 @@ use smithay::{ compositor::CompositorState, dmabuf::{self, DmabufGlobal, DmabufHandler, DmabufState}, output::OutputManagerState, - shell::{ - kde::decoration::KdeDecorationState, - xdg::{decoration::XdgDecorationState, XdgShellState}, - }, + shell::kde::decoration::KdeDecorationState, shm::{ShmHandler, ShmState}, xdg_activation::XdgActivationState, }, @@ -56,9 +54,7 @@ pub struct WaylandState { pub compositor_state: CompositorState, pub xdg_activation_state: XdgActivationState, - pub xdg_decoration_state: XdgDecorationState, pub kde_decoration_state: KdeDecorationState, - pub xdg_shell_state: XdgShellState, pub shm_state: ShmState, pub dmabuf_state: DmabufState, pub dmabuf_global: DmabufGlobal, @@ -77,8 +73,6 @@ impl WaylandState { ) -> Arc> { let compositor_state = CompositorState::new::(&display_handle, log.clone()); let xdg_activation_state = XdgActivationState::new::(&display_handle, log.clone()); - let xdg_shell_state = XdgShellState::new::(&display_handle, log.clone()); - let xdg_decoration_state = XdgDecorationState::new::(&display_handle, log.clone()); let kde_decoration_state = KdeDecorationState::new::( &display_handle, DecorationMode::Server, @@ -113,6 +107,7 @@ impl WaylandState { None, ); display_handle.create_global::(3, ()); + display_handle.create_global::(5, ()); info!("Init Wayland compositor"); @@ -125,9 +120,7 @@ impl WaylandState { compositor_state, xdg_activation_state, - xdg_decoration_state, kde_decoration_state, - xdg_shell_state, shm_state, dmabuf_state, dmabuf_global, diff --git a/src/wayland/surface.rs b/src/wayland/surface.rs index e05ed92..f640843 100644 --- a/src/wayland/surface.rs +++ b/src/wayland/surface.rs @@ -4,6 +4,7 @@ use crate::{ nodes::drawable::model::Model, }; use mint::Vector2; +use once_cell::sync::OnceCell; use parking_lot::Mutex; use send_wrapper::SendWrapper; use slog::Logger; @@ -35,112 +36,75 @@ pub static CORE_SURFACES: Registry = Registry::new(); pub struct CoreSurfaceData { wl_tex: Option>, - sk_tex: Option>, - sk_mat: Option>>, pub size: Vector2, } -impl CoreSurfaceData { - fn new(sk: &StereoKit) -> Self { - let sk_tex = SendWrapper::new( - SKTexture::create(sk, TextureType::ImageNoMips, TextureFormat::RGBA32).unwrap(), - ); - let sk_mat = { - let shader = Shader::from_mem(sk, PANEL_SHADER_BYTES).unwrap(); - let mat = Material::create(sk, &shader).unwrap(); - mat.set_parameter("diffuse", &*sk_tex); - mat.set_transparency(Transparency::Blend); - Arc::new(SendWrapper::new(mat)) - }; - CoreSurfaceData { - wl_tex: None, - sk_tex: Some(sk_tex), - sk_mat: Some(sk_mat), - size: Vector2::from([0, 0]), - } - } - fn update_tex( - &mut self, - surface: &CoreSurface, - data: &RendererSurfaceStateUserData, - renderer_id: usize, - ) { - if let Some(surface_size) = data.borrow().surface_size() { - self.size = Vector2::from([surface_size.w as u32, surface_size.h as u32]); - } - self.wl_tex = data - .borrow() - .texture::(renderer_id) - .cloned() - .map(SendWrapper::new); - if let Some(smithay_tex) = self.wl_tex.as_ref() { - let sk_tex = self.sk_tex.as_ref().unwrap(); - unsafe { - sk_tex.set_native( - smithay_tex.tex_id() as usize, - smithay::backend::renderer::gles2::ffi::RGBA8.into(), - TextureType::ImageNoMips, - smithay_tex.width(), - smithay_tex.height(), - false, - ); - sk_tex.set_sample(TextureSample::Point); - sk_tex.set_address_mode(TextureAddress::Clamp); - } - } - if let Some(sk_mat) = &self.sk_mat { - if let Some(material_offset) = surface.material_offset.lock().delta() { - sk_mat.set_queue_offset(*material_offset as i32); - } - } - } -} impl Drop for CoreSurfaceData { fn drop(&mut self) { destroy_queue::add(self.wl_tex.take()); - destroy_queue::add(self.sk_tex.take()); - destroy_queue::add(self.sk_mat.take()); } } pub struct CoreSurface { display: Weak>>, - pub state: Weak>, pub dh: DisplayHandle, pub weak_surface: wayland_server::Weak, mapped_data: Mutex>, + sk_tex: OnceCell>, + sk_mat: OnceCell>>, material_offset: Mutex>, pub pending_material_applications: Mutex, u32)>>, } impl CoreSurface { - pub fn new( - state: &Arc>, + pub fn add_to( display: &Arc>>, dh: DisplayHandle, surface: &WlSurface, - ) -> Arc { - CORE_SURFACES.add(CoreSurface { - display: Arc::downgrade(display), - state: Arc::downgrade(state), - dh, - weak_surface: surface.downgrade(), - mapped_data: Mutex::new(None), - material_offset: Mutex::new(Delta::new(0)), - pending_material_applications: Mutex::new(Vec::new()), + ) { + compositor::with_states(surface, |data| { + data.data_map.insert_if_missing_threadsafe(|| { + CORE_SURFACES.add(CoreSurface { + display: Arc::downgrade(display), + dh, + weak_surface: surface.downgrade(), + mapped_data: Mutex::new(None), + sk_tex: OnceCell::new(), + sk_mat: OnceCell::new(), + material_offset: Mutex::new(Delta::new(0)), + pending_material_applications: Mutex::new(Vec::new()), + }) + }); + }); + } + + pub fn from_wl_surface(surf: &WlSurface) -> Option> { + compositor::with_states(surf, |data| { + data.data_map.get::>().cloned() }) } - pub fn process( + pub fn process( &self, sk: &StereoKit, renderer: &mut Gles2Renderer, output: Output, log: &Logger, - on_mapped: F, - if_mapped: M, ) { let Some(wl_surface) = self.wl_surface() else { return }; + let sk_tex = self.sk_tex.get_or_init(|| { + SendWrapper::new( + SKTexture::create(sk, TextureType::ImageNoMips, TextureFormat::RGBA32).unwrap(), + ) + }); + self.sk_mat.get_or_init(|| { + let shader = Shader::from_mem(sk, PANEL_SHADER_BYTES).unwrap(); + let mat = Material::create(sk, &shader).unwrap(); + mat.set_parameter("diffuse", &**sk_tex); + mat.set_transparency(Transparency::Blend); + Arc::new(SendWrapper::new(mat)) + }); + // Let smithay handle buffer management (has to be done here as RendererSurfaceStates is not thread safe) on_commit_buffer_handler(&wl_surface); // Import all surface buffers into textures @@ -160,26 +124,44 @@ impl CoreSurface { } let mut mapped_data = self.mapped_data.lock(); - let just_mapped = mapped_data.is_none(); - if just_mapped { - *mapped_data = Some(CoreSurfaceData::new(sk)); - } - drop(mapped_data); self.with_states(|data| { - self.with_data(|mapped_data| { - mapped_data.update_tex( - self, - data.data_map.get::().unwrap(), - renderer.id(), - ); - }); - self.apply_surface_materials(); - + let just_mapped = mapped_data.is_none(); if just_mapped { - on_mapped(data); + let smithay_tex = data + .data_map + .get::() + .unwrap() + .borrow() + .texture::(renderer.id()) + .unwrap() + .clone(); + + let sk_tex = self.sk_tex.get().unwrap(); + let sk_mat = self.sk_mat.get().unwrap(); + unsafe { + sk_tex.set_native( + smithay_tex.tex_id() as usize, + smithay::backend::renderer::gles2::ffi::RGBA8.into(), + TextureType::ImageNoMips, + smithay_tex.width(), + smithay_tex.height(), + false, + ); + sk_tex.set_sample(TextureSample::Point); + sk_tex.set_address_mode(TextureAddress::Clamp); + } + if let Some(material_offset) = self.material_offset.lock().delta() { + sk_mat.set_queue_offset(*material_offset as i32); + } + + let new_mapped_data = CoreSurfaceData { + size: Vector2::from([smithay_tex.width(), smithay_tex.height()]), + wl_tex: Some(SendWrapper::new(smithay_tex)), + }; + *mapped_data = Some(new_mapped_data); } - if_mapped(data); }); + self.apply_surface_materials(); send_frames_surface_tree( &wl_surface, @@ -190,6 +172,10 @@ impl CoreSurface { ); } + pub fn mapped(&self) -> bool { + self.mapped_data.lock().is_some() + } + pub fn set_material_offset(&self, material_offset: u32) { *self.material_offset.lock().value_mut() = material_offset; } @@ -201,32 +187,12 @@ impl CoreSurface { } fn apply_surface_materials(&self) { - self.with_data(|mapped_data| { - let mut pending_material_applications = self.pending_material_applications.lock(); - for (model, material_idx) in &*pending_material_applications { - model - .pending_material_replacements - .lock() - .insert(*material_idx, mapped_data.sk_mat.clone().unwrap()); - } - pending_material_applications.clear(); - }); - } - - pub fn pid(&self) -> Option { - Some( - self.weak_surface - .upgrade() - .ok()? - .client()? - .get_credentials(&self.dh) - .ok()? - .pid, - ) - } - - pub fn wayland_state(&self) -> Arc> { - self.state.upgrade().unwrap() + for (model, material_idx) in self.pending_material_applications.lock().drain(0..) { + model + .pending_material_replacements + .lock() + .insert(material_idx, self.sk_mat.get().unwrap().clone()); + } } pub fn wl_surface(&self) -> Option { @@ -260,5 +226,8 @@ impl CoreSurface { impl Drop for CoreSurface { fn drop(&mut self) { CORE_SURFACES.remove(self); + + destroy_queue::add(self.sk_tex.take()); + destroy_queue::add(self.sk_mat.take()); } } diff --git a/src/wayland/xdg_shell.rs b/src/wayland/xdg_shell.rs index 858e983..4d02d5b 100644 --- a/src/wayland/xdg_shell.rs +++ b/src/wayland/xdg_shell.rs @@ -1,69 +1,362 @@ use std::sync::Arc; -use crate::nodes::Node; - -use super::{panel_item::PanelItem, state::WaylandState}; +use super::{ + panel_item::{PanelItem, ToplevelState}, + state::WaylandState, +}; +use mint::Vector2; +use parking_lot::Mutex; +use serde::Serialize; use smithay::{ - delegate_xdg_shell, reexports::{ - wayland_protocols::xdg::{ - decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode, - shell::server::xdg_toplevel::State, + wayland_protocols::xdg::shell::server::{ + xdg_popup::{self, XdgPopup}, + xdg_positioner::{self, Anchor, ConstraintAdjustment, Gravity, XdgPositioner}, + xdg_surface::{self, XdgSurface}, + xdg_toplevel::{self, XdgToplevel}, + xdg_wm_base::{self, XdgWmBase}, }, - wayland_server::protocol::{wl_seat::WlSeat, wl_surface::WlSurface}, - }, - utils::Serial, - wayland::{ - compositor, - shell::xdg::{ - Configure, PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, - XdgShellState, + wayland_server::{ + protocol::wl_surface::WlSurface, Client, DataInit, Dispatch, DisplayHandle, + GlobalDispatch, New, Resource, WEnum, Weak, }, }, + wayland::compositor, }; -impl XdgShellHandler for WaylandState { - fn xdg_shell_state(&mut self) -> &mut XdgShellState { - &mut self.xdg_shell_state - } +// impl XdgShellHandler for WaylandState { +// fn xdg_shell_state(&mut self) -> &mut WaylandState { +// &mut self.xdg_shell_state +// } - fn new_toplevel(&mut self, surface: ToplevelSurface) { - self.output.enter(surface.wl_surface()); - surface.with_pending_state(|state| { - state.states.set(State::Maximized); - state.states.set(State::Activated); - state.decoration_mode = Some(Mode::ServerSide); - }); - surface.send_configure(); - } - fn ack_configure(&mut self, surface: WlSurface, configure: Configure) { - // let size = match configure { - // Configure::Toplevel(config) => config.state.size, - // Configure::Popup(_) => return, - // }; - // let core_surface = match configure { - // Configure::Toplevel(config) => { - // .and_then(|panel| panel.core_surface()) - // } - // Configure::Popup(_) => return, - // }; - let Some(panel_item_node) = compositor::with_states(&surface, |data| { - data.data_map.get::>().cloned() - }) else { return }; - let Some(panel_item) = PanelItem::from_node(&panel_item_node) else { return }; - panel_item.ack_resize(configure); +// fn new_toplevel(&mut self, surface: ToplevelSurface) { +// self.output.enter(surface.wl_surface()); +// surface.with_pending_state(|state| { +// state.states.set(State::Maximized); +// state.states.set(State::Activated); +// state.decoration_mode = Some(Mode::ServerSide); +// }); +// surface.send_configure(); - // let has_data = core_surface - // .with_data(|data| { - // data.size.x = size.w as u32; - // data.size.y = size.h as u32; - // }) - // .is_some(); - // if has_data { - // } - } +// let client = surface.wl_surface().client().unwrap(); +// let (node, item) = PanelItem::create( +// &surface, +// client.get_credentials(&self.display_handle).ok(), +// self.seats.get(&client.id()).unwrap().clone(), +// ); +// compositor::with_states(surface.wl_surface(), |surface_data| { +// surface_data.data_map.insert_if_missing_threadsafe(|| node); +// surface_data.data_map.insert_if_missing_threadsafe(|| item); +// }); +// } +// fn new_popup(&mut self, surface: PopupSurface, _positioner: PositionerState) { +// self.output.enter(surface.wl_surface()); +// let _ = surface.send_configure(); +// // let panel_item = compositor::with_states(&surface.get_parent_surface().unwrap(), |data| { +// // data.data_map.get::>().cloned() +// // }); +// } +// fn ack_configure(&mut self, surface: WlSurface, configure: Configure) { +// compositor::with_states(&surface, |data| { +// if let Some(panel_item) = data.data_map.get::>() { +// panel_item.ack_resize(configure); +// } +// }); +// } - fn new_popup(&mut self, _surface: PopupSurface, _positioner: PositionerState) {} - fn grab(&mut self, _surface: PopupSurface, _seat: WlSeat, _serial: Serial) {} +// fn grab(&mut self, _surface: PopupSurface, _seat: WlSeat, _serial: Serial) {} +// } +// delegate_xdg_shell!(WaylandState); + +impl GlobalDispatch for WaylandState { + fn bind( + _state: &mut WaylandState, + _handle: &DisplayHandle, + _client: &Client, + resource: New, + _global_data: &(), + data_init: &mut DataInit<'_, WaylandState>, + ) { + data_init.init(resource, ()); + } +} +#[derive(Debug)] +pub struct WaylandSurface { + wl_surface: Weak, + size: Arc>>, +} + +impl Dispatch for WaylandState { + fn request( + _state: &mut WaylandState, + _client: &Client, + _resource: &XdgWmBase, + request: xdg_wm_base::Request, + _data: &(), + _dhandle: &DisplayHandle, + data_init: &mut DataInit<'_, WaylandState>, + ) { + match request { + xdg_wm_base::Request::CreatePositioner { id } => { + data_init.init(id, Arc::new(Mutex::new(PositionerData::default()))); + } + xdg_wm_base::Request::GetXdgSurface { id, surface } => { + data_init.init( + id, + WaylandSurface { + wl_surface: surface.downgrade(), + size: Arc::new(Mutex::new(Vector2::from([0; 2]))), + }, + ); + } + xdg_wm_base::Request::Pong { serial: _ } => (), + xdg_wm_base::Request::Destroy => (), + _ => unreachable!(), + } + } +} + +#[derive(Debug, Serialize)] +pub struct PositionerData { + size: Vector2, + anchor_rect_pos: Vector2, + anchor_rect_size: Vector2, + anchor: u32, + gravity: u32, + constraint_adjustment: u32, + offset: Vector2, + reactive: bool, +} +impl Default for PositionerData { + fn default() -> Self { + Self { + size: Vector2::from([0; 2]), + anchor_rect_pos: Vector2::from([0; 2]), + anchor_rect_size: Vector2::from([0; 2]), + anchor: Anchor::None as u32, + gravity: Gravity::None as u32, + constraint_adjustment: ConstraintAdjustment::None.bits(), + offset: Vector2::from([0; 2]), + reactive: false, + } + } +} + +impl Dispatch>, WaylandState> for WaylandState { + fn request( + _state: &mut WaylandState, + _client: &Client, + resource: &XdgPositioner, + request: xdg_positioner::Request, + data: &Arc>, + _dhandle: &DisplayHandle, + _data_init: &mut DataInit<'_, WaylandState>, + ) { + match request { + xdg_positioner::Request::SetSize { width, height } => { + data.lock().size = Vector2::from([width as u32, height as u32]); + } + xdg_positioner::Request::SetAnchorRect { + x, + y, + width, + height, + } => { + if width < 1 || height < 1 { + resource.post_error( + xdg_positioner::Error::InvalidInput, + "Invalid size for positioner's anchor rectangle.", + ); + return; + } + + let mut data = data.lock(); + data.anchor_rect_pos = [x, y].into(); + data.anchor_rect_size = [width as u32, height as u32].into(); + } + xdg_positioner::Request::SetAnchor { anchor } => { + if let WEnum::Value(anchor) = anchor { + data.lock().anchor = anchor as u32; + } + } + xdg_positioner::Request::SetGravity { gravity } => { + if let WEnum::Value(gravity) = gravity { + data.lock().gravity = gravity as u32; + } + } + xdg_positioner::Request::SetConstraintAdjustment { + constraint_adjustment, + } => { + data.lock().constraint_adjustment = constraint_adjustment; + } + xdg_positioner::Request::SetOffset { x, y } => { + data.lock().offset = [x, y].into(); + } + xdg_positioner::Request::SetReactive => { + data.lock().reactive = true; + } + xdg_positioner::Request::SetParentSize { + parent_width: _, + parent_height: _, + } => (), + xdg_positioner::Request::SetParentConfigure { serial: _ } => (), + xdg_positioner::Request::Destroy => (), + _ => unreachable!(), + } + } +} + +#[derive(Debug, Clone)] +pub struct XdgSurfaceData { + pub wl_surface: Weak, + pub xdg_surface: Weak, + pub size: Arc>>, +} +impl Dispatch for WaylandState { + fn request( + state: &mut WaylandState, + client: &Client, + xdg_surface: &XdgSurface, + request: xdg_surface::Request, + data: &WaylandSurface, + _dhandle: &DisplayHandle, + data_init: &mut DataInit<'_, WaylandState>, + ) { + match request { + xdg_surface::Request::GetToplevel { id } => { + let toplevel_state = Arc::new(Mutex::new(ToplevelState { + queued_state: Some(Box::new(ToplevelState::default())), + ..Default::default() + })); + let toplevel = data_init.init( + id, + XdgToplevelData { + state: toplevel_state, + xdg_surface_data: XdgSurfaceData { + wl_surface: data.wl_surface.clone(), + xdg_surface: xdg_surface.downgrade(), + size: data.size.clone(), + }, + }, + ); + + toplevel.configure(0, 0, vec![]); + xdg_surface.configure(0); + + let (node, item) = PanelItem::create( + toplevel, + client.get_credentials(&state.display_handle).ok(), + state.seats.get(&client.id()).unwrap().clone(), + ); + compositor::with_states(&data.wl_surface.upgrade().unwrap(), |surface_data| { + surface_data.data_map.insert_if_missing_threadsafe(|| node); + surface_data.data_map.insert_if_missing_threadsafe(|| item); + }); + } + xdg_surface::Request::GetPopup { + id, + parent: _, + positioner: _, + } => { + data_init.init(id, ()); + } + xdg_surface::Request::SetWindowGeometry { + x: _, + y: _, + width, + height, + } => { + *data.size.lock() = Vector2::from([width as u32, height as u32]); + } + xdg_surface::Request::AckConfigure { serial: _ } => (), + xdg_surface::Request::Destroy => (), + _ => unreachable!(), + } + } +} + +#[derive(Debug)] +pub struct XdgToplevelData { + pub state: Arc>, + pub xdg_surface_data: XdgSurfaceData, +} +impl Dispatch for WaylandState { + fn request( + _state: &mut WaylandState, + _client: &Client, + _resource: &XdgToplevel, + request: xdg_toplevel::Request, + data: &XdgToplevelData, + _dhandle: &DisplayHandle, + _data_init: &mut DataInit<'_, WaylandState>, + ) { + match request { + xdg_toplevel::Request::SetParent { parent } => { + let mut state = data.state.lock(); + let queued_state = state.queued_state.as_mut().unwrap(); + queued_state.parent = parent.map(|toplevel| toplevel.downgrade()); + } + xdg_toplevel::Request::SetTitle { title } => { + let mut state = data.state.lock(); + let queued_state = state.queued_state.as_mut().unwrap(); + queued_state.title = title; + } + xdg_toplevel::Request::SetAppId { app_id } => { + let mut state = data.state.lock(); + let queued_state = state.queued_state.as_mut().unwrap(); + queued_state.app_id = app_id; + } + xdg_toplevel::Request::ShowWindowMenu { + seat: _, + serial: _, + x: _, + y: _, + } => (), + xdg_toplevel::Request::Move { seat: _, serial: _ } => (), + xdg_toplevel::Request::Resize { + seat: _, + serial: _, + edges: _, + } => (), + xdg_toplevel::Request::SetMaxSize { width, height } => { + let mut state = data.state.lock(); + let queued_state = state.queued_state.as_mut().unwrap(); + queued_state.max_size = Vector2::from([width as u32, height as u32]); + } + xdg_toplevel::Request::SetMinSize { width, height } => { + let mut state = data.state.lock(); + let queued_state = state.queued_state.as_mut().unwrap(); + queued_state.min_size = Vector2::from([width as u32, height as u32]); + } + xdg_toplevel::Request::SetMaximized => (), + xdg_toplevel::Request::UnsetMaximized => (), + xdg_toplevel::Request::SetFullscreen { output: _ } => (), + xdg_toplevel::Request::UnsetFullscreen => (), + xdg_toplevel::Request::SetMinimized => (), + xdg_toplevel::Request::Destroy => (), + _ => unreachable!(), + } + } +} + +impl Dispatch for WaylandState { + fn request( + _state: &mut WaylandState, + _client: &Client, + _resource: &XdgPopup, + request: xdg_popup::Request, + _data: &(), + _dhandle: &DisplayHandle, + _data_init: &mut DataInit<'_, WaylandState>, + ) { + match request { + xdg_popup::Request::Grab { seat: _, serial: _ } => (), + xdg_popup::Request::Reposition { + positioner: _, + token: _, + } => (), + xdg_popup::Request::Destroy => (), + _ => unreachable!(), + } + } } -delegate_xdg_shell!(WaylandState);