diff --git a/crescent/src/render.rs b/crescent/src/render.rs index ebbe587..7d5b688 100644 --- a/crescent/src/render.rs +++ b/crescent/src/render.rs @@ -261,7 +261,7 @@ impl Renderer { fn render(&mut self, output: wgpu::SurfaceTexture) { use runa_orbiter::{ - shell::surface::roles::subsurface_iter, utils::geometry::coords::Map as _, + shell::surface::roles::subsurface::subsurface_iter, utils::geometry::coords::Map as _, }; let shell = self.shell.borrow(); let output_scale = shell.scale_f32().map(|f| NotNan::try_from(f).unwrap()); diff --git a/crescent/src/shell.rs b/crescent/src/shell.rs index 98ed250..f6112d0 100644 --- a/crescent/src/shell.rs +++ b/crescent/src/shell.rs @@ -12,7 +12,7 @@ use runa_orbiter::{ shell::{ buffers, output::OutputChange, - surface::{self, roles::subsurface_iter}, + surface::{self, roles::subsurface::subsurface_iter}, xdg::{Layout, XdgShell}, Shell, ShellEvent, }, @@ -86,7 +86,7 @@ impl Window { #[derive(Debug)] pub struct DefaultShellSurfaceState { - pub base: surface::SurfaceState>, + pub base: surface::State>, /// Whether this state is the current state of its corresponding surface. pub is_current: bool, /// The index of this state in the window stack, if it's in the stack. @@ -94,7 +94,7 @@ pub struct DefaultShellSurfaceState { } impl DefaultShellSurfaceState { - pub fn new(base: surface::SurfaceState>) -> Self { + pub fn new(base: surface::State>) -> Self { Self { base, is_current: false, @@ -143,7 +143,7 @@ impl DefaultShell { let state = self.get(top_level.surface_state); let surface = state.surface().unwrap(); let role = surface - .role::() + .role::() .unwrap(); if let Some(geometry) = role.geometry() { if !geometry.to().contains(position) { @@ -383,7 +383,7 @@ impl Shell for DefaultShell { type Token = DefaultKey; #[tracing::instrument(skip_all)] - fn allocate(&mut self, state: surface::SurfaceState) -> Self::Token { + fn allocate(&mut self, state: surface::State) -> Self::Token { self.storage.insert(DefaultShellSurfaceState::new(state)) } @@ -392,7 +392,7 @@ impl Shell for DefaultShell { tracing::debug!("Released {:?}, #surfaces left: {}", key, self.storage.len()); } - fn get(&self, key: Self::Token) -> &surface::SurfaceState { + fn get(&self, key: Self::Token) -> &surface::State { // This unwrap cannot fail, unless there is a bug in this implementation to // cause it to return an invalid token. self.storage @@ -404,7 +404,7 @@ impl Shell for DefaultShell { fn get_disjoint_mut( &mut self, keys: [Self::Token; N], - ) -> [&mut surface::SurfaceState; N] { + ) -> [&mut surface::State; N] { self.storage .get_disjoint_mut(keys) .unwrap() diff --git a/runa-orbiter/src/globals/mod.rs b/runa-orbiter/src/globals/mod.rs index 47f7046..b935585 100644 --- a/runa-orbiter/src/globals/mod.rs +++ b/runa-orbiter/src/globals/mod.rs @@ -130,7 +130,7 @@ where continue } self.surfaces.extend( - crate::shell::surface::roles::subsurface_iter( + crate::shell::surface::roles::subsurface::subsurface_iter( surface.inner.current_key(), &*shell, ) diff --git a/runa-orbiter/src/objects/compositor.rs b/runa-orbiter/src/objects/compositor.rs index 7958b65..763f990 100644 --- a/runa-orbiter/src/objects/compositor.rs +++ b/runa-orbiter/src/objects/compositor.rs @@ -655,7 +655,7 @@ where async move { let surface = ctx.objects().get::(object_id).unwrap().0.clone(); let role = surface - .role::::Shell>>() + .role::::Shell>>() .unwrap(); let parent = role.parent().upgrade().unwrap(); let mut parent_stack_pending = parent.pending_mut(); @@ -768,7 +768,7 @@ where if !ctx.objects().contains(id.0) { let shell = ctx.server_context().shell(); let mut shell = shell.borrow_mut(); - if !crate::shell::surface::roles::Subsurface::attach( + if !roles::subsurface::Subsurface::attach( parent, surface.clone(), &mut shell, diff --git a/runa-orbiter/src/objects/shm.rs b/runa-orbiter/src/objects/shm.rs index 7507f69..0a7d5a6 100644 --- a/runa-orbiter/src/objects/shm.rs +++ b/runa-orbiter/src/objects/shm.rs @@ -55,7 +55,7 @@ lazy_static::lazy_static! { } thread_local! { - static SIGBUS_COUNT: Cell = Cell::new(0); + static SIGBUS_COUNT: Cell = const { Cell::new(0) }; } /// The number of times a recoverable SIGBUS has occurred for the current @@ -86,7 +86,7 @@ unsafe fn map_zeroed(addr: *const libc::c_void, len: usize) -> Result<(), libc:: } /// Handle a SIGBUS signal. Tries to recover from SIGBUS caused by a client -/// shrinking its shm pool. You MUST call this function is your SIGBUS handler +/// shrinking its shm pool. You MUST call this function in your SIGBUS handler /// if you want to map shm pools. /// /// Returns `true` if the signal was handled, `false` otherwise. Usually you diff --git a/runa-orbiter/src/objects/xdg_shell.rs b/runa-orbiter/src/objects/xdg_shell.rs index 3a21ff2..f33e5dd 100644 --- a/runa-orbiter/src/objects/xdg_shell.rs +++ b/runa-orbiter/src/objects/xdg_shell.rs @@ -19,7 +19,10 @@ use runa_wayland_protocols::stable::xdg_shell::{ use runa_wayland_types::{NewId, Object as WaylandObject, Str}; use crate::{ - shell::{surface::LayoutEvent, xdg, HasShell, Shell}, + shell::{ + surface::{roles::xdg as xdg_roles, LayoutEvent}, + HasShell, Shell, + }, utils::geometry::{Extent, Point, Rectangle}, }; @@ -28,7 +31,7 @@ use crate::{ pub struct WmBase; #[wayland_object] -impl xdg_wm_base::RequestDispatch for WmBase +impl xdg_wm_base::RequestDispatch for WmBase where Ctx::ServerContext: HasShell, Ctx::Object: From>, @@ -74,7 +77,7 @@ where let mut shell = server_context.shell().borrow_mut(); let inserted = objects .try_insert_with(id.0, || { - let role = crate::shell::xdg::Surface::new(id); + let role = xdg_roles::Surface::new(id); surface.set_role(role, &mut shell); Surface { inner: surface }.into() }) @@ -125,10 +128,7 @@ where message: &'ctx mut Self::Message, ) -> Self::Future<'ctx> { tracing::debug!(?message, "LayoutEventHandler::poll_handle_event"); - use crate::shell::{ - surface::Role, - xdg::{Surface as XdgSurface, TopLevel}, - }; + use crate::shell::surface::roles::Role; let surface = objects .get::::Shell>>( self.surface_object_id, @@ -137,13 +137,17 @@ where let mut connection = Pin::new(connection); async move { if let Some(size) = message.0.extent { - if let Some(role_object_id) = surface.inner.role::().map(|r| { - assert!( - ::Shell>>::is_active(&r), - "TopLevel role no longer active" - ); - r.object_id - }) { + if let Some(role_object_id) = + surface.inner.role::().map(|r| { + assert!( + ::Shell, + >>::is_active(&r), + "TopLevel role no longer active" + ); + r.object_id + }) + { connection .as_mut() .send(role_object_id, xdg_toplevel::events::Configure { @@ -159,7 +163,7 @@ where } // Send xdg_surface.configure event let (serial, role_object_id) = { - let mut role = surface.inner.role_mut::().unwrap(); + let mut role = surface.inner.role_mut::().unwrap(); let serial = role.serial; role.serial = role.serial.checked_add(1).unwrap_or(1.try_into().unwrap()); role.pending_serial.push_back(serial); @@ -303,8 +307,8 @@ where let surface = objects.get::(object_id).unwrap().inner.clone(); let inserted = objects .try_insert_with(id.0, || { - let base_role = surface.role::().unwrap().clone(); - let role = crate::shell::xdg::TopLevel::new(base_role, id.0); + let base_role = surface.role::().unwrap().clone(); + let role = xdg_roles::TopLevel::new(base_role, id.0); surface.set_role(role, &mut server_context.shell().borrow_mut()); // Start listening to layout events @@ -329,7 +333,7 @@ where fn ack_configure(ctx: &mut Ctx, object_id: u32, serial: u32) -> Self::AckConfigureFut<'_> { async move { let this = ctx.objects().get::(object_id).unwrap(); - let mut role = this.inner.role_mut::().unwrap(); + let mut role = this.inner.role_mut::().unwrap(); while let Some(front) = role.pending_serial.front() { if front.get() > serial { break @@ -353,7 +357,7 @@ where ) -> Self::SetWindowGeometryFut<'_> { async move { let this = ctx.objects().get::(object_id).unwrap(); - let mut role = this.inner.role_mut::().unwrap(); + let mut role = this.inner.role_mut::().unwrap(); role.pending_geometry = Some(Rectangle { loc: Point::new(x, y), size: Extent::new(width, height), @@ -439,7 +443,7 @@ where fn set_title<'a>(ctx: &'a mut Ctx, object_id: u32, title: Str<'a>) -> Self::SetTitleFut<'a> { async move { let this = ctx.objects().get::(object_id).unwrap(); - let mut role = this.0.role_mut::().unwrap(); + let mut role = this.0.role_mut::().unwrap(); role.title = Some(String::from_utf8_lossy(title.0).into_owned()); Ok(()) } @@ -455,7 +459,7 @@ where fn set_app_id<'a>(ctx: &'a mut Ctx, object_id: u32, app_id: Str<'a>) -> Self::SetAppIdFut<'a> { async move { let this = ctx.objects().get::(object_id).unwrap(); - let mut role = this.0.role_mut::().unwrap(); + let mut role = this.0.role_mut::().unwrap(); role.app_id = Some(String::from_utf8_lossy(app_id.0).into_owned()); Ok(()) } @@ -469,7 +473,7 @@ where ) -> Self::SetMaxSizeFut<'_> { async move { let this = ctx.objects().get::(object_id).unwrap(); - let mut role = this.0.role_mut::().unwrap(); + let mut role = this.0.role_mut::().unwrap(); role.pending.max_size = Some(Extent::new(width, height)); Ok(()) } @@ -483,7 +487,7 @@ where ) -> Self::SetMinSizeFut<'_> { async move { let this = ctx.objects().get::(object_id).unwrap(); - let mut role = this.0.role_mut::().unwrap(); + let mut role = this.0.role_mut::().unwrap(); role.pending.min_size = Some(Extent::new(width, height)); Ok(()) } diff --git a/runa-orbiter/src/shell/buffers.rs b/runa-orbiter/src/shell/buffers.rs index 16301f2..b628cce 100644 --- a/runa-orbiter/src/shell/buffers.rs +++ b/runa-orbiter/src/shell/buffers.rs @@ -229,6 +229,7 @@ impl BufferLike for Buffer { /// An empty private trait just to make enum_dispatch generate the `From` impls. #[enum_dispatch::enum_dispatch] +#[allow(dead_code)] trait BufferBaseFrom {} /// An enum of all buffer base types defined in this crate. diff --git a/runa-orbiter/src/shell/mod.rs b/runa-orbiter/src/shell/mod.rs index e31d724..4e51bcb 100644 --- a/runa-orbiter/src/shell/mod.rs +++ b/runa-orbiter/src/shell/mod.rs @@ -8,7 +8,6 @@ pub mod buffers; pub mod output; pub mod surface; -pub mod xdg; use std::cell::RefCell; use runa_core::events::EventSource; @@ -53,7 +52,7 @@ pub trait Shell: Sized + EventSource + 'static { type Buffer: buffers::BufferLike; /// Allocate a SurfaceState and returns a handle to it. - fn allocate(&mut self, state: surface::SurfaceState) -> Self::Token; + fn allocate(&mut self, state: surface::State) -> Self::Token; /// Release a token. fn destroy(&mut self, key: Self::Token); @@ -61,10 +60,10 @@ pub trait Shell: Sized + EventSource + 'static { /// Get a reference to a SurfaceState by key. /// /// Returns None if the key is invalid. - fn get(&self, key: Self::Token) -> &surface::SurfaceState; + fn get(&self, key: Self::Token) -> &surface::State; /// Get a mutable reference to a SurfaceState. - fn get_mut(&mut self, key: Self::Token) -> &mut surface::SurfaceState { + fn get_mut(&mut self, key: Self::Token) -> &mut surface::State { self.get_disjoint_mut([key])[0] } @@ -77,7 +76,7 @@ pub trait Shell: Sized + EventSource + 'static { fn get_disjoint_mut( &mut self, keys: [Self::Token; N], - ) -> [&mut surface::SurfaceState; N]; + ) -> [&mut surface::State; N]; /// Callback which is called when a role is added to a surface corresponds /// to the given surface state. A role can be attached using a committed @@ -192,3 +191,31 @@ pub trait Seat: EventSource { /// Get the name of the seat. fn name(&self) -> &str; } + +pub mod xdg { + //! Extensions to [`super::Shell`] to provide xdg shell specific + //! functionalities. + + use crate::utils::geometry::{coords, Extent, Point}; + + /// Surface layout + /// + /// A surface layout is where the surface is positioned on the screen, and + /// its screen space size. + #[derive(Debug, Default, Clone, Copy)] + pub struct Layout { + /// The position of the surface on the screen. + pub position: Option>, + /// The size of the surface on the screen. + pub extent: Option>, + } + + /// Extension of [`super::Shell`] to provide xdg shell specific + /// information. + pub trait XdgShell: super::Shell { + /// Ask the shell to calculate the layout of the given surface. + fn layout(&self, _key: Self::Token) -> Layout { + Layout::default() + } + } +} diff --git a/runa-orbiter/src/shell/surface.rs b/runa-orbiter/src/shell/surface/mod.rs similarity index 61% rename from runa-orbiter/src/shell/surface.rs rename to runa-orbiter/src/shell/surface/mod.rs index b0632ed..c68c74d 100644 --- a/runa-orbiter/src/shell/surface.rs +++ b/runa-orbiter/src/shell/surface/mod.rs @@ -13,12 +13,11 @@ use std::{ use derive_where::derive_where; use dlv_list::{Index, VecList}; -use dyn_clone::DynClone; use hashbrown::HashSet; use ordered_float::NotNan; use runa_core::{ events::{broadcast, single_state, EventSource}, - provide_any::{request_mut, request_ref, Demand, Provider}, + provide_any::{request_mut, request_ref}, }; use runa_wayland_types::NewId; use tinyvecdeq::tinyvecdeq::TinyVecDeq; @@ -35,407 +34,15 @@ use crate::{ }, }; -/// A surface role -pub trait Role: Any { - /// The name of the interface of this role. - fn name(&self) -> &'static str; - /// Returns true if the role is active. - /// - /// As specified by the wayland protocol, a surface can be assigned a role, - /// then have the role object destroyed. This makes the role "inactive", - /// but the surface cannot be assigned a different role. So we keep the - /// role object but "deactivate" it. - fn is_active(&self) -> bool; - /// Deactivate the role. - fn deactivate(&mut self, shell: &mut S); - /// Provides type based access to member variables of this role. - fn provide<'a>(&'a self, _demand: &mut Demand<'a>) {} - /// Provides type based access to member variables of this role. - fn provide_mut<'a>(&'a mut self, _demand: &mut Demand<'a>) {} - /// Called before the pending state becomes the current state, in - /// [`Surface::commit`]. If an error is returned, the commit will be - /// stopped. - fn pre_commit(&mut self, _shell: &mut S, _surfacee: &Surface) -> Result<(), &'static str> { - Ok(()) - } - /// Called after the pending state becomes the current state, in - /// [`Surface::commit`] - fn post_commit(&mut self, _shell: &mut S, _surface: &Surface) {} -} - -/// A double-buffer state associated with a role -pub trait RoleState: Any + DynClone + std::fmt::Debug + 'static {} - -impl Provider for dyn Role { - fn provide<'a>(&'a self, demand: &mut Demand<'a>) { - self.provide(demand); - } - - fn provide_mut<'a>(&'a mut self, demand: &mut Demand<'a>) { - self.provide_mut(demand); - } -} - /// Some roles defined in the wayland protocol -pub mod roles { - use std::{ - cell::Cell, - rc::{Rc, Weak}, - }; - - use derive_where::derive_where; - use dlv_list::Index; - use runa_core::provide_any; - use runa_wayland_protocols::wayland::wl_subsurface; - - use crate::{ - shell::Shell, - utils::geometry::{coords, Point}, - }; - - /// The `wl_subsurface` role. - /// - /// # Note about cache and pending states - /// - /// A surface normally has a pending and a current state. Changes are - /// stored in the pending state first, then applied to the current - /// state when `wl_surface.commit` is called. - /// - /// Subsurfaces has one more state - the cached state. This state exists if - /// the subsurface is in synchronized mode. In sync mode, commit applies - /// pending state to a cached state, and the cached state is applied to - /// current state when the parent calls commit, if the partent is desynced; - /// otherwise the cached state becomes part of the parent's cached - /// state. - /// - /// We can see this as a tree of surface states, rooted at a "top-level" - /// surface, such as a surface with the `xdg_toplevel` role. The root's - /// current state references the children's current states, and the - /// children's current states in turn reference the grand-children's, so - /// on and so forth. When a synced child commits, its current state updates, - /// but it doesn't update its parent's reference to its current state. - /// So the parent still references the previous state, until the parent - /// also commits. - /// - /// A complication is when a child is destroyed, either by destroying the - /// surface or deactivating its role, it's immediately removed, without - /// going through the pending or the cached state. We can detect this by - /// checking if the role object is active, while going through the tree - /// of surfaces. - #[derive(Debug)] - #[derive_where(Clone)] - pub struct Subsurface { - sync: bool, - inherited_sync: bool, - pub(super) is_active: Rc>, - /// Index of this surface in parent's `stack` list. - /// Note this index should be stable across parent updates, including - /// appending to the stack, reordering the stack. a guarantee - /// from VecList. - pub(crate) stack_index: Index>, - pub(super) parent: Weak>, - } - - #[derive(Debug, Clone)] - pub(super) struct SubsurfaceState { - /// Parent surface *state* of this surface *state*. A surface state is - /// only considered a parent after it has been committed. This - /// is different from [`Subsurface::parent`], which is the - /// `Rc` (surface, not surface state) that is the parent of - /// this surface. A surface can have multiple surface states - /// each have different parent surface states. But a surface can - /// have only one parent surface. - /// - /// A surface state can have multiple parents because of the sync - /// mechanism of subsurfaces. i.e. a subsurface can be attached - /// to a parent, then the parent has its own parent. When - /// the parent commits, its old state will still be referenced by - /// the grandparent, and it will have a new cached state. - /// Both the old state and the new state will be "parents" - /// of this surface state. - /// - /// If that's the case, this field will point to the oldest, still valid - /// parent. For states visible from a "root" surface (e.g. a - /// xdg_toplevel), this conveniently forms a path towards the - /// root's current state. - pub(super) parent: Option, - - /// See [`Subsurface::stack_index`] - pub(super) stack_index: Index>, - - /// Whether the corresponding role is active. - pub(super) is_active: Rc>, - } - impl super::RoleState for SubsurfaceState {} - impl Subsurface { - /// Attach a surface to a parent surface, and add the subsurface role to - /// id. - pub fn attach( - parent: Rc>, - surface: Rc>, - shell: &mut S, - ) -> bool { - if surface.role.borrow().is_some() { - // already has a role - tracing::debug!("surface {:p} already has a role", Rc::as_ptr(&surface)); - return false - } - // Preventing cycle creation - if Rc::ptr_eq(&parent.root(), &surface) { - tracing::debug!("cycle detected"); - return false - } - let mut parent_pending = parent.pending_mut(); - let stack_index = - parent_pending - .stack - .push_front(super::SurfaceStackEntry::Subsurface { - token: surface.current_key(), - position: Point::new(0, 0), - }); - let is_active = Rc::new(Cell::new(true)); - let role = Self { - sync: true, - inherited_sync: true, - is_active: is_active.clone(), - stack_index, - parent: Rc::downgrade(&parent), - }; - tracing::debug!( - "attach {:p} to {:p}", - Rc::as_ptr(&surface), - Rc::as_ptr(&parent) - ); - surface.set_role(role, shell); - surface - .pending_mut() - .set_role_state(SubsurfaceState:: { - parent: None, - stack_index, - is_active, - }); - true - } - - /// Returns a weak reference to the parent surface. - pub fn parent(&self) -> &Weak> { - &self.parent - } - } - - impl super::Role for Subsurface { - fn name(&self) -> &'static str { - wl_subsurface::v1::NAME - } - - fn is_active(&self) -> bool { - self.is_active.get() - } - - fn deactivate(&mut self, _shell: &mut S) { - tracing::debug!("deactivate subsurface role {}", self.is_active.get()); - if !self.is_active.get() { - return - } - // Deactivating the subsurface role is immediate, but we don't know - // how many other surface states there are that are referencing this - // subsurface state, as our ancestors can have any number of "cached" - // states. And we aren't keeping track of all of them. Instead we - // mark it inactive, and skip over inactive states when we iterate - // over the subsurface tree. - self.is_active.set(false); - - // Remove ourself from parent's pending stack, so when the parent - // eventually commits, it will drop us. - let parent = self - .parent - .upgrade() - .expect("surface is destroyed but its state is still being used"); - let mut parent_pending_state = parent.pending_mut(); - parent_pending_state.stack.remove(self.stack_index).unwrap(); - self.parent = Weak::new(); - } - - fn provide<'a>(&'a self, demand: &mut provide_any::Demand<'a>) { - demand.provide_ref(self); - } - - fn provide_mut<'a>(&'a mut self, demand: &mut provide_any::Demand<'a>) { - demand.provide_mut(self); - } - - fn post_commit(&mut self, shell: &mut S, surface: &super::Surface) { - // update the state referenced in parent's pending state's stack. - let parent = self - .parent - .upgrade() - .expect("surface is destroyed but its state is still being used"); - - let mut parent_pending_state = parent.pending_mut(); - let parent_pending_stack_entry = parent_pending_state - .stack - .get_mut(self.stack_index) - .unwrap(); - let super::SurfaceStackEntry::Subsurface { token, .. } = parent_pending_stack_entry - else { - panic!("subsurface stack entry has unexpected type") - }; - *token = surface.current_key(); - - // the current state is now referenced by the parent's pending state, - // clear the parent field. (parent could have been set because pending state was - // cloned from a previous current state) - let current = surface.current_mut(shell); - let role_state = current - .role_state_mut::>() - .expect("subsurface role state missing") - .expect("subsurface role state has unexpected type"); - role_state.parent = None; - } - } - - /// Double ended iterator for iterating over a surface and its subsurfaces - /// in the order they are stacked. - /// - /// The forward order is from bottom to top. This iterates over the - /// committed states of the surfaces, as defined by `wl_surface.commit`. - pub fn subsurface_iter( - root: S::Token, - s: &S, - ) -> impl DoubleEndedIterator)> + '_ { - macro_rules! generate_advance { - ($next_in_stack:ident, $next_maybe_deactivated:ident, $next:ident, $id:literal) => { - /// Advance the front pointer to the next surface in the - /// stack. The next surface might be deactivated. - fn $next_maybe_deactivated(&mut self) { - use super::SurfaceState; - if self.head[0].0 == self.head[1].0 { - self.is_empty = true; - } - if self.is_empty { - return - } - - // The head we are advancing - let curr_head = &mut self.head[$id]; - - let ret = self.shell.get(curr_head.0); - if let Some((next, offset)) = SurfaceState::$next_in_stack( - curr_head.0, - ret.stack_index.into(), - self.shell, - ) { - curr_head.1 += offset; - curr_head.0 = next; - } else { - // `ret` is at the bottom/top of its own stack. this includes the case of - // `ret` being the only surface in its stack. So we need return - // upwards to the parent, and find the next surface in the parent's - // stack. We do this repeatedly if we are also at the end of the - // parent's stack. - let mut curr = ret; - let mut offset = curr_head.1; - *curr_head = loop { - let role_state = curr - .role_state::>() - .expect("subsurface role state missing") - .expect("subsurface role state has unexpected type"); - let parent_key = role_state.parent.unwrap_or_else(|| { - panic!( - "surface state {curr:?} (key: {:?}) has no parent, but is in \ - a stack", - curr_head.0 - ) - }); - let parent = self.shell.get(parent_key); - let stack_index = role_state.stack_index; - offset -= parent.stack.get(stack_index).unwrap().position(); - - if let Some((next, next_offset)) = SurfaceState::$next_in_stack( - parent_key, - stack_index.into(), - self.shell, - ) { - offset += next_offset; - break (next, offset) - } - curr = parent; - }; - } - } - - fn $next(&mut self) { - while !self.is_empty { - self.$next_maybe_deactivated(); - let ret = self.shell.get(self.head[0].0); - let role_active = ret - .role_state::>() - // If the role state is not SubsurfaceState, or if the role state - // doesn't exist, then the surface is top-level. - .flatten() - .map_or(true, |role_state| role_state.is_active.get()); - if role_active { - break - } - } - } - }; - } - struct SubsurfaceIter<'a, S: Shell> { - shell: &'a S, - /// Key and offset from the root surface. - head: [(S::Token, Point); 2], - is_empty: bool, - } - - impl SubsurfaceIter<'_, S> { - generate_advance!(next_in_stack, next_maybe_deactivated, next, 0); - - generate_advance!(prev_in_stack, prev_maybe_deactivated, prev, 1); - } - - impl Iterator for SubsurfaceIter<'_, S> { - type Item = (S::Token, Point); - - fn next(&mut self) -> Option { - if self.is_empty { - None - } else { - let ret = self.head[0]; - self.next(); - Some(ret) - } - } - } - impl DoubleEndedIterator for SubsurfaceIter<'_, S> { - fn next_back(&mut self) -> Option { - if self.is_empty { - None - } else { - let ret = self.head[1]; - self.prev(); - Some(ret) - } - } - } - - SubsurfaceIter { - shell: s, - head: [ - super::SurfaceState::top(root, s), - super::SurfaceState::bottom(root, s), - ], - is_empty: false, - } - } -} +pub mod roles; /// A entry in a surface's stack /// /// Each surface has a stack, composed of the surface itself and its /// subsurfaces. #[derive(Debug, Clone)] -pub(crate) enum SurfaceStackEntry { +pub(crate) enum StackEntry { /// The surface itself Self_, /// A subsurface @@ -447,28 +54,28 @@ pub(crate) enum SurfaceStackEntry { /// Index into a surface's stack #[derive_where(Debug, Clone, Copy)] -pub struct SurfaceStackIndex(pub(crate) Index>); +pub struct StackIndex(pub(crate) Index>); -impl From>> for SurfaceStackIndex { - fn from(index: Index>) -> Self { +impl From>> for StackIndex { + fn from(index: Index>) -> Self { Self(index) } } -impl SurfaceStackEntry { +impl StackEntry { /// Position of a surface in a stack, relative to the surface the stack /// belongs to. pub(crate) fn position(&self) -> Point { match self { - SurfaceStackEntry::Self_ => Point::new(0, 0), - SurfaceStackEntry::Subsurface { position, .. } => *position, + StackEntry::Self_ => Point::new(0, 0), + StackEntry::Subsurface { position, .. } => *position, } } pub(crate) fn set_position(&mut self, position: Point) { match self { - SurfaceStackEntry::Self_ => panic!("cannot set position of self"), - SurfaceStackEntry::Subsurface { position: p, .. } => *p = position, + StackEntry::Self_ => panic!("cannot set position of self"), + StackEntry::Subsurface { position: p, .. } => *p = position, } } } @@ -476,31 +83,31 @@ impl SurfaceStackEntry { /// The surface state /// /// This holds the modifiable states of a surface. -pub struct SurfaceState { +pub struct State { /// Weak reference to the surface owning this state surface: Weak>, /// List of of all the unfired frame callbacks pub(crate) frame_callbacks: TinyVecDeq<[u32; 4]>, /// A stack of child surfaces and self. - stack: VecList>, + stack: VecList>, /// The position of this surface state in its own stack. - pub(crate) stack_index: Index>, + pub(crate) stack_index: Index>, buffer: Option>, /// Scale of the buffer, a fraction with a denominator of 120 buffer_scale: u32, - role_state: Option>, + role_state: Option>, } /// Pending changes to a surface state -pub struct PendingSurfaceState { +pub struct PendingState { frame_callbacks: TinyVecDeq<[u32; 4]>, buffer: Option>, buffer_scale: Option, - stack: VecList>, - role_state: Option>, + stack: VecList>, + role_state: Option>, } -impl Debug for PendingSurfaceState { +impl Debug for PendingState { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use super::buffers::BufferLike; f.debug_struct("PendingSurfaceState") @@ -513,8 +120,8 @@ impl Debug for PendingSurfaceState { } } -impl PendingSurfaceState { - fn set_role_state(&mut self, state: T) { +impl PendingState { + fn set_role_state(&mut self, state: T) { self.role_state = Some(Box::new(state)); } @@ -529,7 +136,7 @@ impl PendingSurfaceState { } } - pub(crate) fn stack_mut(&mut self) -> &mut VecList> { + pub(crate) fn stack_mut(&mut self) -> &mut VecList> { &mut self.stack } @@ -548,7 +155,7 @@ impl PendingSurfaceState { } } -impl std::fmt::Debug for SurfaceState { +impl std::fmt::Debug for State { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use crate::shell::buffers::BufferLike; f.debug_struct("SurfaceState") @@ -562,17 +169,17 @@ impl std::fmt::Debug for SurfaceState { } } -impl Default for SurfaceState { +impl Default for State { fn default() -> Self { Self::new() } } -impl SurfaceState { +impl State { /// Create a new surface state fn new() -> Self { let mut stack = VecList::new(); - let stack_index = stack.push_back(SurfaceStackEntry::Self_); + let stack_index = stack.push_back(StackEntry::Self_); Self { frame_callbacks: Default::default(), stack, @@ -597,7 +204,7 @@ impl SurfaceState { } /// Create a new copy of this surface state, with `changes` applied. - fn apply_pending(&self, changes: &mut PendingSurfaceState) -> Self { + fn apply_pending(&self, changes: &mut PendingState) -> Self { if let Some(buffer) = changes.buffer.as_ref() { use crate::shell::buffers::BufferLike; buffer.inner.acquire(); @@ -623,8 +230,8 @@ impl SurfaceState { /// any. None if this surface is not a subsurface. pub fn parent(&self) -> Option { let role_state = self.role_state.as_ref()?; - let role_state = - (&**role_state as &dyn Any).downcast_ref::>()?; + let role_state = (&**role_state as &dyn Any) + .downcast_ref::>()?; role_state.parent } @@ -636,7 +243,7 @@ impl SurfaceState { .as_mut() .and_then(|role_state| { (&mut **role_state as &mut dyn Any) - .downcast_mut::>() + .downcast_mut::>() }) .map(|role_state| { role_state.parent = parent; @@ -657,8 +264,8 @@ impl SurfaceState { // itself can have a stack. So we need to recursively find the top most surface // in `top`'s stack. Unless `top` points to `Self_` in which case we are done. match first { - SurfaceStackEntry::Self_ => break, - &SurfaceStackEntry::Subsurface { token, position } => { + StackEntry::Self_ => break, + &StackEntry::Subsurface { token, position } => { this = token; offset += position; }, @@ -681,9 +288,9 @@ impl SurfaceState { let next = shell.get(this); let last = next.stack.back().unwrap(); match last { - SurfaceStackEntry::Self_ => break, /* `bottom` is the bottom of its own stack, so * + StackEntry::Self_ => break, /* `bottom` is the bottom of its own stack, so * * we don't need to keep descending. */ - &SurfaceStackEntry::Subsurface { token, position } => { + &StackEntry::Subsurface { token, position } => { this = token; offset += position; }, @@ -703,7 +310,7 @@ impl SurfaceState { /// of C in A's stack, and the top-most surface of D's subtree is E. pub fn next_in_stack( this: S::Token, - index: SurfaceStackIndex, + index: StackIndex, shell: &S, ) -> Option<(S::Token, Point)> { let this_surface = shell.get(this); @@ -713,8 +320,8 @@ impl SurfaceState { // get_next_index/get_previous_index let next_child = unsafe { this_surface.stack.get_unchecked(next_index) }; match next_child { - SurfaceStackEntry::Self_ => Some((this, Point::new(0, 0))), - &SurfaceStackEntry::Subsurface { token, position } => { + StackEntry::Self_ => Some((this, Point::new(0, 0))), + &StackEntry::Subsurface { token, position } => { let (top, offset) = Self::top(token, shell); Some((top, offset + position)) }, @@ -736,7 +343,7 @@ impl SurfaceState { /// is G. pub fn prev_in_stack( this: S::Token, - index: SurfaceStackIndex, + index: StackIndex, shell: &S, ) -> Option<(S::Token, Point)> { let this_surface = shell.get(this); @@ -744,8 +351,8 @@ impl SurfaceState { if let Some(prev_index) = prev_index { let prev_child = unsafe { this_surface.stack.get_unchecked(prev_index) }; match prev_child { - SurfaceStackEntry::Self_ => Some((this, Point::new(0, 0))), - &SurfaceStackEntry::Subsurface { token, position } => { + StackEntry::Self_ => Some((this, Point::new(0, 0))), + &StackEntry::Subsurface { token, position } => { let (bottom, offset) = Self::bottom(token, shell); Some((bottom, offset + position)) }, @@ -785,7 +392,7 @@ impl SurfaceState { } /// Set role related state. - pub fn set_role_state(&mut self, state: T) { + pub fn set_role_state(&mut self, state: T) { self.role_state = Some(Box::new(state)); } @@ -793,7 +400,7 @@ impl SurfaceState { /// /// None if there is no role related state assigned to this surface. /// Some(None) if `T` is not the correct type. - pub fn role_state(&self) -> Option> { + pub fn role_state(&self) -> Option> { self.role_state .as_ref() .map(|s| (&**s as &dyn Any).downcast_ref::()) @@ -809,7 +416,7 @@ impl SurfaceState { /// /// None if there is no role related state assigned to this surface. /// Some(None) if `T` is not the correct type. - pub fn role_state_mut(&mut self) -> Option> { + pub fn role_state_mut(&mut self) -> Option> { self.role_state .as_mut() .map(|s| (&mut **s as &mut dyn Any).downcast_mut::()) @@ -833,14 +440,14 @@ impl SurfaceState { let token = queue[head]; let state = shell.get(token); for e in state.stack.iter() { - if let &SurfaceStackEntry::Subsurface { + if let &StackEntry::Subsurface { token: child_token, .. } = e { let child_state = shell.get(child_token); let child_subsurface_state = (&**child_state.role_state.as_ref().unwrap() as &dyn Any) - .downcast_ref::>() + .downcast_ref::>() .unwrap(); let parent = child_subsurface_state.parent; if parent.map(|p| p == token).unwrap_or(true) { @@ -890,8 +497,8 @@ pub struct Surface { current: Cell>, /// The pending state of the surface, this will be applied to /// [`Self::current`] when commit is called - pending_state: RefCell>, - role: RefCell>>>, + pending_state: RefCell>, + role: RefCell>>>, outputs: OutputSet, output_change_events: single_state::Sender, pointer_events: broadcast::Ring, @@ -928,8 +535,8 @@ impl Surface { pointer_events: broadcast::Ring, keyboard_events: broadcast::Ring, ) -> Rc { - let surface_state = SurfaceState::new(); - let pending_state = RefCell::new(PendingSurfaceState { + let surface_state = State::new(); + let pending_state = RefCell::new(PendingState { stack: surface_state.stack.clone(), buffer: None, role_state: None, @@ -957,8 +564,8 @@ impl Surface { impl Surface { /// Get the parent surface if this surface has a subsurface role. pub fn parent(&self) -> Option> { - let role = self.role::>(); - role.map(|r| r.parent.upgrade().unwrap()) + let role = self.role::>(); + role.map(|r| r.parent().upgrade().unwrap()) } /// Follow the parent link of this surface until the root is reached. @@ -987,7 +594,7 @@ impl Surface { // Find potentially free-able surface states and set their parents to // None, so later they can either be resurrected with a new parent, or // be freed. - SurfaceState::scan_for_freeing(current, shell, scratch_buffer); + State::scan_for_freeing(current, shell, scratch_buffer); tracing::debug!("potential freeable surface states: {:?}", scratch_buffer); for &token in &scratch_buffer[..] { // Free-able surface states aren't always subsurfaces, because `self` @@ -1020,7 +627,7 @@ impl Surface { let state = shell.get(token); let child_start = scratch_buffer.len(); for e in state.stack.iter() { - if let &SurfaceStackEntry::Subsurface { + if let &StackEntry::Subsurface { token: child_token, .. } = e { @@ -1118,22 +725,22 @@ impl Surface { } /// Get a unique reference to the pending surface state. - pub fn pending_mut(&self) -> RefMut<'_, PendingSurfaceState> { + pub fn pending_mut(&self) -> RefMut<'_, PendingState> { self.pending_state.borrow_mut() } /// Get a reference to the pending surface state. - pub fn pending(&self) -> Ref<'_, PendingSurfaceState> { + pub fn pending(&self) -> Ref<'_, PendingState> { self.pending_state.borrow() } /// Get a reference to the current surface state. - pub fn current<'a>(&self, shell: &'a S) -> &'a SurfaceState { + pub fn current<'a>(&self, shell: &'a S) -> &'a State { shell.get(self.current_key()) } /// Get a unique reference to the current surface state. - pub fn current_mut<'a>(&self, shell: &'a mut S) -> &'a mut SurfaceState { + pub fn current_mut<'a>(&self, shell: &'a mut S) -> &'a mut State { shell.get_mut(self.current_key()) } @@ -1153,13 +760,13 @@ impl Surface { } /// Borrow the role object of the surface. - pub fn role>(&self) -> Option> { + pub fn role>(&self) -> Option> { let role = self.role.borrow(); Ref::filter_map(role, |r| r.as_ref().and_then(|r| request_ref(&**r))).ok() } /// Mutably borrow the role object of the surface. - pub fn role_mut>(&self) -> Option> { + pub fn role_mut>(&self) -> Option> { let role = self.role.borrow_mut(); RefMut::filter_map(role, |r| r.as_mut().and_then(|r| request_mut(&mut **r))).ok() } @@ -1230,7 +837,7 @@ impl Surface { // orphan all our children let current_key = self.current_key(); for child in stack { - let SurfaceStackEntry::Subsurface { + let StackEntry::Subsurface { token: child_token, .. } = child else { @@ -1238,7 +845,7 @@ impl Surface { }; let child = shell.get_mut(child_token); let role_state = child - .role_state_mut::>() + .role_state_mut::>() .expect("subsurface role state missing") .expect("subsurface role state has unexpected type"); if role_state.parent == Some(current_key) { @@ -1283,7 +890,7 @@ impl Surface { } /// Assign a role to this surface. - pub fn set_role>(&self, role: T, shell: &mut S) { + pub fn set_role>(&self, role: T, shell: &mut S) { let role_name = role.name(); { let mut role_mut = self.role.borrow_mut(); diff --git a/runa-orbiter/src/shell/surface/roles/mod.rs b/runa-orbiter/src/shell/surface/roles/mod.rs new file mode 100644 index 0000000..373726b --- /dev/null +++ b/runa-orbiter/src/shell/surface/roles/mod.rs @@ -0,0 +1,50 @@ +use runa_core::provide_any; + +pub mod subsurface; +pub mod xdg; + +pub use subsurface::Subsurface; +pub use xdg::Surface as XdgSurface; +pub use xdg::TopLevel as XdgTopLevel; +pub use xdg::Popup as XdgPopup; + +/// A surface role +pub trait Role: std::any::Any { + /// The name of the interface of this role. + fn name(&self) -> &'static str; + /// Returns true if the role is active. + /// + /// As specified by the wayland protocol, a surface can be assigned a role, + /// then have the role object destroyed. This makes the role "inactive", + /// but the surface cannot be assigned a different role. So we keep the + /// role object but "deactivate" it. + fn is_active(&self) -> bool; + /// Deactivate the role. + fn deactivate(&mut self, shell: &mut S); + /// Provides type based access to member variables of this role. + fn provide<'a>(&'a self, _demand: &mut provide_any::Demand<'a>) {} + /// Provides type based access to member variables of this role. + fn provide_mut<'a>(&'a mut self, _demand: &mut provide_any::Demand<'a>) {} + /// Called before the pending state becomes the current state, in + /// [`Surface::commit`]. If an error is returned, the commit will be + /// stopped. + fn pre_commit(&mut self, _shell: &mut S, _surfacee: &super::Surface) -> Result<(), &'static str> { + Ok(()) + } + /// Called after the pending state becomes the current state, in + /// [`Surface::commit`] + fn post_commit(&mut self, _shell: &mut S, _surface: &super::Surface) {} +} + +/// A double-buffer state associated with a role +pub trait State: std::any::Any + dyn_clone::DynClone + std::fmt::Debug + 'static {} + +impl provide_any::Provider for dyn Role { + fn provide<'a>(&'a self, demand: &mut provide_any::Demand<'a>) { + self.provide(demand); + } + + fn provide_mut<'a>(&'a mut self, demand: &mut provide_any::Demand<'a>) { + self.provide_mut(demand); + } +} diff --git a/runa-orbiter/src/shell/surface/roles/subsurface.rs b/runa-orbiter/src/shell/surface/roles/subsurface.rs new file mode 100644 index 0000000..eb776b8 --- /dev/null +++ b/runa-orbiter/src/shell/surface/roles/subsurface.rs @@ -0,0 +1,344 @@ +//! Role object for `wl_subsurface`. + +use std::{ + cell::Cell, + rc::{Rc, Weak}, +}; + +use derive_where::derive_where; +use dlv_list::Index; +use runa_core::provide_any; +use runa_wayland_protocols::wayland::wl_subsurface; + +use crate::{ + shell::{ + surface::{Surface, StackEntry, State as SurfaceState}, + Shell, + }, + utils::geometry::{coords, Point}, +}; + +/// The `wl_subsurface` role. +/// +/// # Note about cache and pending states +/// +/// A surface normally has a pending and a current state. Changes are +/// stored in the pending state first, then applied to the current +/// state when `wl_surface.commit` is called. +/// +/// Subsurfaces has one more state - the cached state. This state exists if +/// the subsurface is in synchronized mode. In sync mode, commit applies +/// pending state to a cached state, and the cached state is applied to +/// current state when the parent calls commit, if the partent is desynced; +/// otherwise the cached state becomes part of the parent's cached +/// state. +/// +/// We can see this as a tree of surface states, rooted at a "top-level" +/// surface, such as a surface with the `xdg_toplevel` role. The root's +/// current state references the children's current states, and the +/// children's current states in turn reference the grand-children's, so +/// on and so forth. When a synced child commits, its current state updates, +/// but it doesn't update its parent's reference to its current state. +/// So the parent still references the previous state, until the parent +/// also commits. +/// +/// A complication is when a child is destroyed, either by destroying the +/// surface or deactivating its role, it's immediately removed, without +/// going through the pending or the cached state. We can detect this by +/// checking if the role object is active, while going through the tree +/// of surfaces. +#[derive(Debug)] +#[derive_where(Clone)] +pub struct Subsurface { + sync: bool, + inherited_sync: bool, + pub(super) is_active: Rc>, + /// Index of this surface in parent's `stack` list. + /// Note this index should be stable across parent updates, including + /// appending to the stack, reordering the stack. a guarantee + /// from VecList. + pub(crate) stack_index: Index>, + pub(super) parent: Weak>, +} + +#[derive(Debug, Clone)] +pub(in crate::shell) struct State { + /// Parent surface *state* of this surface *state*. A surface state is + /// only considered a parent after it has been committed. This + /// is different from [`Subsurface::parent`], which is the + /// `Rc` (surface, not surface state) that is the parent of + /// this surface. A surface can have multiple surface states + /// each have different parent surface states. But a surface can + /// have only one parent surface. + /// + /// A surface state can have multiple parents because of the sync + /// mechanism of subsurfaces. i.e. a subsurface can be attached + /// to a parent, then the parent has its own parent. When + /// the parent commits, its old state will still be referenced by + /// the grandparent, and it will have a new cached state. + /// Both the old state and the new state will be "parents" + /// of this surface state. + /// + /// If that's the case, this field will point to the oldest, still valid + /// parent. For states visible from a "root" surface (e.g. a + /// xdg_toplevel), this conveniently forms a path towards the + /// root's current state. + pub(in crate::shell) parent: Option, + + /// See [`Subsurface::stack_index`] + pub(in crate::shell) stack_index: Index>, + + /// Whether the corresponding role is active. + pub(in crate::shell) is_active: Rc>, +} +impl super::State for State {} +impl Subsurface { + /// Attach a surface to a parent surface, and add the subsurface role to + /// id. + pub fn attach(parent: Rc>, surface: Rc>, shell: &mut S) -> bool { + if surface.role.borrow().is_some() { + // already has a role + tracing::debug!("surface {:p} already has a role", Rc::as_ptr(&surface)); + return false + } + // Preventing cycle creation + if Rc::ptr_eq(&parent.root(), &surface) { + tracing::debug!("cycle detected"); + return false + } + let mut parent_pending = parent.pending_mut(); + let stack_index = parent_pending + .stack + .push_front(StackEntry::Subsurface { + token: surface.current_key(), + position: Point::new(0, 0), + }); + let is_active = Rc::new(Cell::new(true)); + let role = Self { + sync: true, + inherited_sync: true, + is_active: is_active.clone(), + stack_index, + parent: Rc::downgrade(&parent), + }; + tracing::debug!( + "attach {:p} to {:p}", + Rc::as_ptr(&surface), + Rc::as_ptr(&parent) + ); + surface.set_role(role, shell); + surface + .pending_mut() + .set_role_state(State:: { + parent: None, + stack_index, + is_active, + }); + true + } + + /// Returns a weak reference to the parent surface. + pub fn parent(&self) -> &Weak> { + &self.parent + } +} + +impl super::Role for Subsurface { + fn name(&self) -> &'static str { + wl_subsurface::v1::NAME + } + + fn is_active(&self) -> bool { + self.is_active.get() + } + + fn deactivate(&mut self, _shell: &mut S) { + tracing::debug!("deactivate subsurface role {}", self.is_active.get()); + if !self.is_active.get() { + return + } + // Deactivating the subsurface role is immediate, but we don't know + // how many other surface states there are that are referencing this + // subsurface state, as our ancestors can have any number of "cached" + // states. And we aren't keeping track of all of them. Instead we + // mark it inactive, and skip over inactive states when we iterate + // over the subsurface tree. + self.is_active.set(false); + + // Remove ourself from parent's pending stack, so when the parent + // eventually commits, it will drop us. + let parent = self + .parent + .upgrade() + .expect("surface is destroyed but its state is still being used"); + let mut parent_pending_state = parent.pending_mut(); + parent_pending_state.stack.remove(self.stack_index).unwrap(); + self.parent = Weak::new(); + } + + fn provide<'a>(&'a self, demand: &mut provide_any::Demand<'a>) { + demand.provide_ref(self); + } + + fn provide_mut<'a>(&'a mut self, demand: &mut provide_any::Demand<'a>) { + demand.provide_mut(self); + } + + fn post_commit(&mut self, shell: &mut S, surface: &Surface) { + // update the state referenced in parent's pending state's stack. + let parent = self + .parent + .upgrade() + .expect("surface is destroyed but its state is still being used"); + + let mut parent_pending_state = parent.pending_mut(); + let parent_pending_stack_entry = parent_pending_state + .stack + .get_mut(self.stack_index) + .unwrap(); + let StackEntry::Subsurface { token, .. } = parent_pending_stack_entry else { + panic!("subsurface stack entry has unexpected type") + }; + *token = surface.current_key(); + + // the current state is now referenced by the parent's pending state, + // clear the parent field. (parent could have been set because pending state was + // cloned from a previous current state) + let current = surface.current_mut(shell); + let role_state = current + .role_state_mut::>() + .expect("subsurface role state missing") + .expect("subsurface role state has unexpected type"); + role_state.parent = None; + } +} + +/// Double ended iterator for iterating over a surface and its subsurfaces +/// in the order they are stacked. +/// +/// The forward order is from bottom to top. This iterates over the +/// committed states of the surfaces, as defined by `wl_surface.commit`. +pub fn subsurface_iter( + root: S::Token, + s: &S, +) -> impl DoubleEndedIterator)> + '_ { + macro_rules! generate_advance { + ($next_in_stack:ident, $next_maybe_deactivated:ident, $next:ident, $id:literal) => { + /// Advance the front pointer to the next surface in the + /// stack. The next surface might be deactivated. + fn $next_maybe_deactivated(&mut self) { + if self.head[0].0 == self.head[1].0 { + self.is_empty = true; + } + if self.is_empty { + return + } + + // The head we are advancing + let curr_head = &mut self.head[$id]; + + let ret = self.shell.get(curr_head.0); + if let Some((next, offset)) = + SurfaceState::$next_in_stack(curr_head.0, ret.stack_index.into(), self.shell) + { + curr_head.1 += offset; + curr_head.0 = next; + } else { + // `ret` is at the bottom/top of its own stack. this includes the case of + // `ret` being the only surface in its stack. So we need return + // upwards to the parent, and find the next surface in the parent's + // stack. We do this repeatedly if we are also at the end of the + // parent's stack. + let mut curr = ret; + let mut offset = curr_head.1; + *curr_head = loop { + let role_state = curr + .role_state::>() + .expect("subsurface role state missing") + .expect("subsurface role state has unexpected type"); + let parent_key = role_state.parent.unwrap_or_else(|| { + panic!( + "surface state {curr:?} (key: {:?}) has no parent, but is in a \ + stack", + curr_head.0 + ) + }); + let parent = self.shell.get(parent_key); + let stack_index = role_state.stack_index; + offset -= parent.stack.get(stack_index).unwrap().position(); + + if let Some((next, next_offset)) = + SurfaceState::$next_in_stack(parent_key, stack_index.into(), self.shell) + { + offset += next_offset; + break (next, offset) + } + curr = parent; + }; + } + } + + fn $next(&mut self) { + while !self.is_empty { + self.$next_maybe_deactivated(); + let ret = self.shell.get(self.head[0].0); + let role_active = ret + .role_state::>() + // If the role state is not SubsurfaceState, or if the role state + // doesn't exist, then the surface is top-level. + .flatten() + .map_or(true, |role_state| role_state.is_active.get()); + if role_active { + break + } + } + } + }; + } + struct SubsurfaceIter<'a, S: Shell> { + shell: &'a S, + /// Key and offset from the root surface. + head: [(S::Token, Point); 2], + is_empty: bool, + } + + impl SubsurfaceIter<'_, S> { + generate_advance!(next_in_stack, next_maybe_deactivated, next, 0); + + generate_advance!(prev_in_stack, prev_maybe_deactivated, prev, 1); + } + + impl Iterator for SubsurfaceIter<'_, S> { + type Item = (S::Token, Point); + + fn next(&mut self) -> Option { + if self.is_empty { + None + } else { + let ret = self.head[0]; + self.next(); + Some(ret) + } + } + } + impl DoubleEndedIterator for SubsurfaceIter<'_, S> { + fn next_back(&mut self) -> Option { + if self.is_empty { + None + } else { + let ret = self.head[1]; + self.prev(); + Some(ret) + } + } + } + + SubsurfaceIter { + shell: s, + head: [ + SurfaceState::top(root, s), + SurfaceState::bottom(root, s), + ], + is_empty: false, + } +} diff --git a/runa-orbiter/src/shell/xdg.rs b/runa-orbiter/src/shell/surface/roles/xdg.rs similarity index 83% rename from runa-orbiter/src/shell/xdg.rs rename to runa-orbiter/src/shell/surface/roles/xdg.rs index 713ed6b..dbec5d5 100644 --- a/runa-orbiter/src/shell/xdg.rs +++ b/runa-orbiter/src/shell/surface/roles/xdg.rs @@ -8,28 +8,10 @@ use runa_wayland_protocols::stable::xdg_shell::{ }; use runa_wayland_types::NewId; -use super::Shell; -use crate::utils::geometry::{coords, Extent, Point, Rectangle}; - -/// Surface layout -/// -/// A surface layout is where the surface is positioned on the screen, and its -/// screen space size. -#[derive(Debug, Default, Clone, Copy)] -pub struct Layout { - /// The position of the surface on the screen. - pub position: Option>, - /// The size of the surface on the screen. - pub extent: Option>, -} - -/// Extension of [`super::Shell`] to provide xdg shell specific informations. -pub trait XdgShell: Shell { - /// Ask the shell to calculate the layout of the given surface. - fn layout(&self, _key: Self::Token) -> Layout { - Layout::default() - } -} +use crate::{ + shell::Shell, + utils::geometry::{coords, Extent, Rectangle}, +}; /// The xdg_surface "role" /// @@ -65,10 +47,10 @@ impl Surface { } } - fn commit( + fn commit( &mut self, shell: &mut S, - surface: &super::surface::Surface, + surface: &crate::shell::surface::Surface, _object_id: u32, ) -> Result<(), &'static str> { tracing::debug!("Committing xdg_surface"); @@ -87,7 +69,7 @@ impl Surface { } } -impl super::surface::Role for Surface { +impl super::Role for Surface { fn name(&self) -> &'static str { xdg_surface::NAME } @@ -149,7 +131,7 @@ impl TopLevel { } } -impl super::surface::Role for TopLevel { +impl super::Role for TopLevel { fn name(&self) -> &'static str { xdg_toplevel::NAME } @@ -180,7 +162,7 @@ impl super::surface::Role for TopLevel { fn pre_commit( &mut self, shell: &mut S, - surface: &super::surface::Surface, + surface: &crate::shell::surface::Surface, ) -> Result<(), &'static str> { tracing::debug!("Committing xdg_toplevel"); let object_id = self.object_id;