From f577f5feef4da8284574f887c2629a856827c565 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 29 Jan 2022 23:08:25 +0100 Subject: [PATCH] autocommit 2022-01-29 23:08:25 CET --- src/client/mod.rs | 16 +- src/client/objects.rs | 3 + src/ifs/wl_seat/mod.rs | 14 +- src/ifs/wl_surface/mod.rs | 39 ++-- src/ifs/wl_surface/types.rs | 4 + src/ifs/wl_surface/wl_subsurface/mod.rs | 10 +- src/ifs/wl_surface/xdg_surface/mod.rs | 64 +++++-- src/ifs/wl_surface/xdg_surface/types.rs | 9 +- .../wl_surface/xdg_surface/xdg_popup/mod.rs | 169 +++++++++++++++++- .../wl_surface/xdg_surface/xdg_popup/types.rs | 7 + .../xdg_surface/xdg_toplevel/mod.rs | 52 ++---- src/ifs/xdg_positioner/mod.rs | 145 +++++++++------ src/rect.rs | 4 + src/render/renderer/renderer.rs | 25 ++- src/tasks/output.rs | 5 +- src/tree/container.rs | 28 ++- src/tree/mod.rs | 39 ++-- src/tree/workspace.rs | 24 ++- 18 files changed, 484 insertions(+), 173 deletions(-) diff --git a/src/client/mod.rs b/src/client/mod.rs index f8b2e18d..8627df4f 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -30,7 +30,7 @@ use crate::ifs::wl_surface::xdg_surface::xdg_popup::{XdgPopup, XdgPopupError}; use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::{XdgToplevel, XdgToplevelError}; use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceId}; use crate::ifs::wl_surface::{WlSurface, WlSurfaceError, WlSurfaceId}; -use crate::ifs::xdg_positioner::{XdgPositioner, XdgPositionerError}; +use crate::ifs::xdg_positioner::{XdgPositioner, XdgPositionerError, XdgPositionerId}; use crate::ifs::xdg_wm_base::{XdgWmBaseError, XdgWmBaseObj}; use crate::ifs::zwp_linux_buffer_params_v1::{ZwpLinuxBufferParamsV1, ZwpLinuxBufferParamsV1Error}; use crate::ifs::zwp_linux_dmabuf_v1::{ZwpLinuxDmabufV1Error, ZwpLinuxDmabufV1Obj}; @@ -78,6 +78,8 @@ pub enum ClientError { SurfaceDoesNotExist(WlSurfaceId), #[error("There is no xdg_surface with id {0}")] XdgSurfaceDoesNotExist(XdgSurfaceId), + #[error("There is no xdg_positioner with id {0}")] + XdgPositionerDoesNotExist(XdgPositionerId), #[error("There is no wl_seat with id {0}")] WlSeatDoesNotExist(WlSeatId), #[error("Cannot parse the message")] @@ -498,6 +500,16 @@ impl Client { } } + pub fn get_xdg_positioner( + &self, + id: XdgPositionerId, + ) -> Result, ClientError> { + match self.objects.xdg_positioners.get(&id) { + Some(r) => Ok(r), + _ => Err(ClientError::XdgPositionerDoesNotExist(id)), + } + } + pub fn get_wl_seat(&self, id: WlSeatId) -> Result, ClientError> { match self.objects.seats.get(&id) { Some(r) => Ok(r), @@ -567,7 +579,6 @@ simple_add_obj!(WlShmObj); simple_add_obj!(WlShmPool); simple_add_obj!(WlSubcompositorObj); simple_add_obj!(WlSubsurface); -simple_add_obj!(XdgPositioner); simple_add_obj!(XdgToplevel); simple_add_obj!(XdgPopup); simple_add_obj!(WlOutputObj); @@ -603,3 +614,4 @@ dedicated_add_obj!(XdgWmBaseObj, xdg_wm_bases); dedicated_add_obj!(XdgSurface, xdg_surfaces); dedicated_add_obj!(WlBuffer, buffers); dedicated_add_obj!(WlSeatObj, seats); +dedicated_add_obj!(XdgPositioner, xdg_positioners); diff --git a/src/client/objects.rs b/src/client/objects.rs index 940ff0f2..438eae2e 100644 --- a/src/client/objects.rs +++ b/src/client/objects.rs @@ -6,6 +6,7 @@ use crate::ifs::wl_registry::{WlRegistry, WlRegistryId}; use crate::ifs::wl_seat::{WlSeatId, WlSeatObj}; use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceId}; use crate::ifs::wl_surface::{WlSurface, WlSurfaceId}; +use crate::ifs::xdg_positioner::{XdgPositioner, XdgPositionerId}; use crate::ifs::xdg_wm_base::{XdgWmBaseId, XdgWmBaseObj}; use crate::object::{Object, ObjectId}; use crate::utils::clonecell::CloneCell; @@ -21,6 +22,7 @@ pub struct Objects { registries: CopyHashMap>, pub surfaces: CopyHashMap>, pub xdg_surfaces: CopyHashMap>, + pub xdg_positioners: CopyHashMap>, pub regions: CopyHashMap>, pub buffers: CopyHashMap>, pub xdg_wm_bases: CopyHashMap>, @@ -39,6 +41,7 @@ impl Objects { registries: Default::default(), surfaces: Default::default(), xdg_surfaces: Default::default(), + xdg_positioners: Default::default(), regions: Default::default(), buffers: Default::default(), xdg_wm_bases: Default::default(), diff --git a/src/ifs/wl_seat/mod.rs b/src/ifs/wl_seat/mod.rs index 0f089345..f0f57514 100644 --- a/src/ifs/wl_seat/mod.rs +++ b/src/ifs/wl_seat/mod.rs @@ -28,6 +28,8 @@ use std::ops::Deref; use std::rc::Rc; pub use types::*; use uapi::{c, OwnedFd}; +use crate::ifs::wl_surface::xdg_surface::xdg_popup::XdgPopup; +use crate::ifs::wl_surface::xdg_surface::XdgSurface; id!(WlSeatId); @@ -167,13 +169,17 @@ impl WlSeatGlobal { self.toplevel_focus_stash .borrow_mut() .insert(toplevel.id, node); + self.focus_xdg_surface(&toplevel.xdg); + } + + fn focus_xdg_surface(&self, xdg: &Rc) { self.keyboard_node.get().unfocus(self); let focus_surface; - if let Some(ss) = toplevel.focus_subsurface.get() { + if let Some(ss) = xdg.focus_subsurface.get() { focus_surface = ss.surface.clone(); self.keyboard_node.set(ss); } else { - focus_surface = toplevel.xdg.surface.clone(); + focus_surface = xdg.surface.clone(); self.keyboard_node.set(focus_surface.clone()); } self.focus_surface(&focus_surface); @@ -328,6 +334,10 @@ impl WlSeatGlobal { self.focus_toplevel(n); } + pub fn enter_popup(&self, n: &Rc) { + self.focus_xdg_surface(&n.xdg); + } + pub fn enter_surface(&self, n: &WlSurface, x: Fixed, y: Fixed) { self.surface_pointer_event(0, n, |p| p.enter(0, n.id, x, y)); } diff --git a/src/ifs/wl_surface/mod.rs b/src/ifs/wl_surface/mod.rs index efc6c030..2e2f777b 100644 --- a/src/ifs/wl_surface/mod.rs +++ b/src/ifs/wl_surface/mod.rs @@ -102,9 +102,9 @@ enum CommitAction { } trait SurfaceExt { - fn pre_commit(self: Rc, ctx: CommitContext) -> CommitAction { + fn pre_commit(self: Rc, ctx: CommitContext) -> Result { let _ = ctx; - CommitAction::ContinueCommit + Ok(CommitAction::ContinueCommit) } fn post_commit(&self) { @@ -147,8 +147,8 @@ impl SurfaceExt for NoneSurfaceExt { #[derive(Default)] struct PendingState { buffer: Cell)>>>, - opaque_region: Cell>, - input_region: Cell>, + opaque_region: Cell>>, + input_region: Cell>>, frame_request: RefCell>>, } @@ -306,28 +306,36 @@ impl WlSurface { fn set_opaque_region(&self, parser: MsgParser<'_, '_>) -> Result<(), SetOpaqueRegionError> { let region: SetOpaqueRegion = self.parse(parser)?; - let region = self.client.get_region(region.region)?; - self.pending.opaque_region.set(Some(region.region())); + let region = if region.region.is_some() { + Some(self.client.get_region(region.region)?.region()) + } else { + None + }; + self.pending.opaque_region.set(Some(region)); Ok(()) } fn set_input_region(&self, parser: MsgParser<'_, '_>) -> Result<(), SetInputRegionError> { let req: SetInputRegion = self.parse(parser)?; - let region = self.client.get_region(req.region)?; - self.pending.input_region.set(Some(region.region())); + let region = if req.region.is_some() { + Some(self.client.get_region(req.region)?.region()) + } else { + None + }; + self.pending.input_region.set(Some(region)); Ok(()) } - fn do_commit(&self, ctx: CommitContext) { + fn do_commit(&self, ctx: CommitContext) -> Result<(), WlSurfaceError> { let ext = self.ext.get(); - if ext.clone().pre_commit(ctx) == CommitAction::AbortCommit { - return; + if ext.clone().pre_commit(ctx)? == CommitAction::AbortCommit { + return Ok(()); } { let children = self.children.borrow(); if let Some(children) = children.deref() { for child in children.subsurfaces.values() { - child.surface.do_commit(CommitContext::ChildCommit); + child.surface.do_commit(CommitContext::ChildCommit)?; } } } @@ -362,21 +370,22 @@ impl WlSurface { } { if let Some(region) = self.pending.input_region.take() { - self.input_region.set(Some(region)); + self.input_region.set(region); } if let Some(region) = self.pending.opaque_region.take() { - self.opaque_region.set(Some(region)); + self.opaque_region.set(region); } } if self.need_extents_update.get() { self.calculate_extents(); } ext.post_commit(); + Ok(()) } fn commit(&self, parser: MsgParser<'_, '_>) -> Result<(), CommitError> { let _req: Commit = self.parse(parser)?; - self.do_commit(CommitContext::RootCommit); + self.do_commit(CommitContext::RootCommit)?; Ok(()) } diff --git a/src/ifs/wl_surface/types.rs b/src/ifs/wl_surface/types.rs index 669641f0..bd0880b6 100644 --- a/src/ifs/wl_surface/types.rs +++ b/src/ifs/wl_surface/types.rs @@ -5,11 +5,14 @@ use crate::ifs::wl_surface::{SurfaceRole, WlSurfaceId}; use crate::utils::buffd::{MsgParser, MsgParserError}; use std::fmt::{Debug, Formatter}; use thiserror::Error; +use crate::ifs::wl_surface::xdg_surface::XdgSurfaceError; #[derive(Debug, Error)] pub enum WlSurfaceError { #[error(transparent)] ClientError(Box), + #[error(transparent)] + XdgSurfaceError(Box), #[error("Could not process `destroy` request")] DestroyError(#[source] Box), #[error("Could not process `attach` request")] @@ -38,6 +41,7 @@ pub enum WlSurfaceError { }, } efrom!(WlSurfaceError, ClientError); +efrom!(WlSurfaceError, XdgSurfaceError); efrom!(WlSurfaceError, DestroyError); efrom!(WlSurfaceError, AttachError); efrom!(WlSurfaceError, DamageError); diff --git a/src/ifs/wl_surface/wl_subsurface/mod.rs b/src/ifs/wl_surface/wl_subsurface/mod.rs index 68102c67..2d299ac2 100644 --- a/src/ifs/wl_surface/wl_subsurface/mod.rs +++ b/src/ifs/wl_surface/wl_subsurface/mod.rs @@ -3,9 +3,7 @@ mod types; use crate::backend::{KeyState, ScrollAxis}; use crate::fixed::Fixed; use crate::ifs::wl_seat::WlSeatGlobal; -use crate::ifs::wl_surface::{ - CommitAction, CommitContext, StackElement, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceId, -}; +use crate::ifs::wl_surface::{CommitAction, CommitContext, StackElement, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError, WlSurfaceId}; use crate::object::{Interface, Object, ObjectId}; use crate::rect::Rect; use crate::tree::{Node, NodeId}; @@ -279,12 +277,12 @@ impl Object for WlSubsurface { } impl SurfaceExt for WlSubsurface { - fn pre_commit(self: Rc, ctx: CommitContext) -> CommitAction { + fn pre_commit(self: Rc, ctx: CommitContext) -> Result { if ctx == CommitContext::RootCommit && self.sync() { log::info!("Aborting commit due to sync"); - return CommitAction::AbortCommit; + return Ok(CommitAction::AbortCommit); } - CommitAction::ContinueCommit + Ok(CommitAction::ContinueCommit) } fn post_commit(&self) { diff --git a/src/ifs/wl_surface/xdg_surface/mod.rs b/src/ifs/wl_surface/xdg_surface/mod.rs index d525a4b2..e671e702 100644 --- a/src/ifs/wl_surface/xdg_surface/mod.rs +++ b/src/ifs/wl_surface/xdg_surface/mod.rs @@ -5,18 +5,20 @@ pub mod xdg_toplevel; use crate::client::DynEventFormatter; use crate::ifs::wl_surface::xdg_surface::xdg_popup::{XdgPopup, XdgPopupId}; use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel; -use crate::ifs::wl_surface::{CommitAction, CommitContext, SurfaceExt, SurfaceRole, WlSurface}; +use crate::ifs::wl_surface::{CommitAction, CommitContext, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError}; use crate::ifs::xdg_wm_base::XdgWmBaseObj; use crate::object::{Interface, Object, ObjectId}; use crate::rect::Rect; -use crate::tree::Node; +use crate::tree::{FoundNode, Node}; use crate::utils::buffd::MsgParser; use crate::utils::clonecell::CloneCell; use crate::utils::copyhashmap::CopyHashMap; use crate::NumCell; use std::cell::Cell; +use std::ops::Deref; use std::rc::Rc; pub use types::*; +use crate::ifs::wl_surface::wl_subsurface::WlSubsurface; const DESTROY: u32 = 0; const GET_TOPLEVEL: u32 = 1; @@ -42,9 +44,11 @@ pub struct XdgSurface { acked_serial: Cell>, geometry: Cell>, extents: Cell, + pub absolute_desired_extents: Cell, ext: CloneCell>>, popups: CopyHashMap>, pending: PendingXdgSurfaceData, + pub focus_subsurface: CloneCell>>, } #[derive(Default)] @@ -53,12 +57,8 @@ struct PendingXdgSurfaceData { } trait XdgSurfaceExt { - fn initial_configure(self: Rc) { - // nothing - } - - fn pre_commit(self: Rc) { - // nothing + fn initial_configure(self: Rc) -> Result<(), XdgSurfaceError> { + Ok(()) } fn post_commit(self: Rc) { @@ -84,9 +84,11 @@ impl XdgSurface { acked_serial: Cell::new(None), geometry: Cell::new(None), extents: Cell::new(Default::default()), + absolute_desired_extents: Cell::new(Default::default()), ext: Default::default(), popups: Default::default(), pending: Default::default(), + focus_subsurface: Default::default() } } @@ -122,8 +124,8 @@ impl XdgSurface { } { let children = self.popups.lock(); - for child in children.values() { - child.parent.set(None); + if !children.is_empty() { + return Err(DestroyError::PopupsNotYetDestroyed); } } self.surface.unset_ext(); @@ -159,6 +161,7 @@ impl XdgSurface { if req.parent.is_some() { parent = Some(self.surface.client.get_xdg_surface(req.parent)?); } + let positioner = self.surface.client.get_xdg_positioner(req.positioner)?; if self.ext.get().is_some() { self.surface.client.protocol_error( &**self, @@ -170,7 +173,7 @@ impl XdgSurface { ); return Err(GetPopupError::AlreadyConstructed); } - let popup = Rc::new(XdgPopup::new(req.id, self, parent.as_ref())); + let popup = Rc::new(XdgPopup::new(req.id, self, parent.as_ref(), &positioner)?); self.surface.client.add_client_obj(&popup)?; if let Some(parent) = &parent { parent.popups.set(req.id, popup.clone()); @@ -226,6 +229,35 @@ impl XdgSurface { } } } + + fn find_child_at(&self, mut x: i32, mut y: i32) -> Option { + if let Some(geo) = self.geometry.get() { + let (xt, yt) = geo.translate_inv(x, y); + x = xt; + y = yt; + } + match self.surface.find_surface_at(x, y) { + Some((node, x, y)) => Some(FoundNode { + node: if std::ptr::eq(node.deref(), self.surface.deref()) { + node + } else { + node.ext.get().into_node().unwrap() + }, + x, + y, + contained: true, + }), + _ => None, + } + } + + fn update_popup_positions(&self) { + let popups = self.popups.lock(); + for popup in popups.values() { + popup.update_absolute_position(); + popup.xdg.update_popup_positions(); + } + } } handle_request!(XdgSurface); @@ -242,17 +274,21 @@ impl Object for XdgSurface { fn num_requests(&self) -> u32 { ACK_CONFIGURE + 1 } + + fn break_loops(&self) { + self.focus_subsurface.set(None); + } } impl SurfaceExt for XdgSurface { - fn pre_commit(self: Rc, _ctx: CommitContext) -> CommitAction { + fn pre_commit(self: Rc, _ctx: CommitContext) -> Result { { let ase = self.acked_serial.get(); let rse = self.requested_serial.get(); if ase != Some(rse) { if ase.is_none() { if let Some(ext) = self.ext.get() { - ext.initial_configure(); + ext.initial_configure()?; } self.surface.client.event(self.configure(rse)); } @@ -263,7 +299,7 @@ impl SurfaceExt for XdgSurface { self.geometry.set(Some(geometry)); self.update_extents(); } - CommitAction::ContinueCommit + Ok(CommitAction::ContinueCommit) } fn post_commit(&self) { diff --git a/src/ifs/wl_surface/xdg_surface/types.rs b/src/ifs/wl_surface/xdg_surface/types.rs index bce2ba85..d493203d 100644 --- a/src/ifs/wl_surface/xdg_surface/types.rs +++ b/src/ifs/wl_surface/xdg_surface/types.rs @@ -1,5 +1,5 @@ use crate::client::{ClientError, EventFormatter, RequestParser}; -use crate::ifs::wl_surface::xdg_surface::xdg_popup::XdgPopupId; +use crate::ifs::wl_surface::xdg_surface::xdg_popup::{XdgPopupError, XdgPopupId}; use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevelId; use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceId, CONFIGURE}; use crate::ifs::wl_surface::{WlSurfaceError, WlSurfaceId}; @@ -26,6 +26,8 @@ pub enum XdgSurfaceError { AlreadyAttached(WlSurfaceId), #[error(transparent)] WlSurfaceError(Box), + #[error(transparent)] + XdgPopupError(#[from] XdgPopupError), } efrom!(XdgSurfaceError, WlSurfaceError); @@ -37,6 +39,8 @@ pub enum DestroyError { ClientError(Box), #[error("Cannot destroy xdg_surface {0} because it's associated xdg_toplevel/popup is not yet destroyed")] RoleNotYetDestroyed(XdgSurfaceId), + #[error("The surface still has popups attached")] + PopupsNotYetDestroyed, } efrom!(DestroyError, ParseFailed, MsgParserError); efrom!(DestroyError, ClientError); @@ -66,9 +70,12 @@ pub enum GetPopupError { AlreadyConstructed, #[error(transparent)] WlSurfaceError(Box), + #[error(transparent)] + XdgPopupError(Box), } efrom!(GetPopupError, ParseFailed, MsgParserError); efrom!(GetPopupError, ClientError); +efrom!(GetPopupError, XdgPopupError); efrom!(GetPopupError, WlSurfaceError); #[derive(Debug, Error)] diff --git a/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs b/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs index 4827d20f..bebdb673 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs @@ -1,12 +1,21 @@ mod types; -use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceExt}; +use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceExt}; +use crate::ifs::xdg_positioner::{XdgPositioned, XdgPositioner}; use crate::object::{Interface, Object, ObjectId}; -use crate::tree::{Node, NodeId}; +use crate::rect::Rect; +use crate::tree::{FoundNode, Node, NodeId, StackedNode, WorkspaceNode}; use crate::utils::buffd::MsgParser; use crate::utils::clonecell::CloneCell; +use std::cell::{Cell, RefCell}; use std::rc::Rc; pub use types::*; +use crate::client::DynEventFormatter; +use crate::fixed::Fixed; +use crate::ifs::wl_seat::WlSeatGlobal; +use crate::ifs::wl_surface::SurfaceExt; +use crate::render::Renderer; +use crate::utils::linkedlist::LinkedNode; const DESTROY: u32 = 0; const GRAB: u32 = 1; @@ -25,17 +34,75 @@ id!(XdgPopupId); pub struct XdgPopup { id: XdgPopupId, node_id: PopupId, - pub(in super::super) xdg: Rc, + pub xdg: Rc, pub(super) parent: CloneCell>>, + relative_position: Cell, + display_link: RefCell>>, + workspace_link: RefCell>>, + pos: RefCell, } impl XdgPopup { - pub fn new(id: XdgPopupId, xdg: &Rc, parent: Option<&Rc>) -> Self { - Self { + pub fn new( + id: XdgPopupId, + xdg: &Rc, + parent: Option<&Rc>, + pos: &Rc, + ) -> Result { + let pos = pos.value(); + if !pos.is_complete() { + return Err(XdgPopupError::Incomplete); + } + Ok(Self { id, node_id: xdg.surface.client.state.node_ids.next(), xdg: xdg.clone(), parent: CloneCell::new(parent.cloned()), + relative_position: Cell::new(Default::default()), + display_link: RefCell::new(None), + workspace_link: RefCell::new(None), + pos: RefCell::new(pos), + }) + } + + fn configure(self: &Rc, x: i32, y: i32, width: i32, height: i32) -> DynEventFormatter { + Box::new(Configure { + obj: self.clone(), + x, + y, + width, + height, + }) + } + + fn repositioned(self: &Rc, token: u32) -> DynEventFormatter { + Box::new(Repositioned { + obj: self.clone(), + token, + }) + } + + fn popup_done(self: &Rc) -> DynEventFormatter { + Box::new(PopupDone { + obj: self.clone(), + }) + } + + fn update_relative_position(&self, parent: &XdgSurface) -> Result<(), XdgPopupError> { + let parent = parent.extents.get(); + let positioner = self.pos.borrow(); + if !parent.contains_rect(&positioner.ar) { + // return Err(XdgPopupError::AnchorRectOutside); + } + self.relative_position.set(positioner.get_position()); + Ok(()) + } + + pub fn update_absolute_position(&self) { + if let Some(parent) = self.parent.get() { + let rel = self.relative_position.get(); + let parent = parent.absolute_desired_extents.get(); + self.xdg.absolute_desired_extents.set(rel.move_(parent.x1(), parent.y1())); } } @@ -48,6 +115,9 @@ impl XdgPopup { } self.xdg.ext.set(None); self.xdg.surface.client.remove_obj(self)?; + self.clear(); + *self.display_link.borrow_mut() = None; + *self.workspace_link.borrow_mut() = None; Ok(()) } @@ -56,13 +126,23 @@ impl XdgPopup { Ok(()) } - fn reposition(&self, parser: MsgParser<'_, '_>) -> Result<(), RepositionError> { - let _req: Reposition = self.xdg.surface.client.parse(self, parser)?; + fn reposition(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), RepositionError> { + let req: Reposition = self.xdg.surface.client.parse(&**self, parser)?; + *self.pos.borrow_mut() = self.xdg.surface.client.get_xdg_positioner(req.positioner)?.value(); + if let Some(parent) = self.parent.get() { + self.update_relative_position(&parent)?; + let rel = self.relative_position.get(); + self.xdg.surface.client.event(self.repositioned(req.token)); + self.xdg.surface.client.event(self.configure(rel.x1(), rel.y1(), rel.width(), rel.height())); + self.xdg.send_configure(); + let parent = parent.absolute_desired_extents.get(); + self.xdg.absolute_desired_extents.set(rel.move_(parent.x1(), parent.y1())); + } Ok(()) } fn handle_request_( - &self, + self: &Rc, request: u32, parser: MsgParser<'_, '_>, ) -> Result<(), XdgPopupError> { @@ -90,12 +170,83 @@ impl Object for XdgPopup { fn num_requests(&self) -> u32 { REPOSITION + 1 } + + fn break_loops(&self) { + self.parent.set(None); + self.clear(); + *self.display_link.borrow_mut() = None; + *self.workspace_link.borrow_mut() = None; + } } impl Node for XdgPopup { fn id(&self) -> NodeId { self.node_id.into() } + + fn clear(&self) { + let _v = self.display_link.borrow_mut().take(); + let _v = self.workspace_link.borrow_mut().take(); + } + + fn find_child_at(&self, x: i32, y: i32) -> Option { + self.xdg.find_child_at(x, y) + } + + fn enter(self: Rc, seat: &WlSeatGlobal, _x: Fixed, _y: Fixed) { + seat.enter_popup(&self); + } + + fn render(&self, renderer: &mut Renderer, x: i32, y: i32) { + renderer.render_xdg_surface(&self.xdg, x, y) + } + + fn get_workspace(self: Rc) -> Option> { + self.parent.get()?.into_node()?.get_workspace() + } } -impl XdgSurfaceExt for XdgPopup {} +impl XdgSurfaceExt for XdgPopup { + fn initial_configure(self: Rc) -> Result<(), XdgSurfaceError> { + if let Some(parent) = self.parent.get() { + self.update_relative_position(&parent)?; + let rel = self.relative_position.get(); + self.xdg.surface.client.event(self.configure(rel.x1(), rel.y1(), rel.width(), rel.height())); + let parent = parent.absolute_desired_extents.get(); + self.xdg.absolute_desired_extents.set(rel.move_(parent.x1(), parent.y1())); + } + Ok(()) + } + + fn post_commit(self: Rc) { + let mut wl = self.workspace_link.borrow_mut(); + let mut dl = self.display_link.borrow_mut(); + let ws = match self.clone().get_workspace() { + Some(ws) => ws, + _ => return, + }; + let surface = &self.xdg.surface; + let state = &surface.client.state; + if surface.buffer.get().is_some() { + if wl.is_none() { + *wl = Some(ws.stacked.add_last(StackedNode::Popup(self.clone()))); + *dl = Some(state.root.stacked.add_last(StackedNode::Popup(self.clone()))); + state.tree_changed(); + } + } else { + if wl.take().is_some() { + *dl = None; + state.tree_changed(); + surface.client.event(self.popup_done()); + } + } + } + + fn into_node(self: Rc) -> Option> { + Some(self) + } + + fn extents_changed(&self) { + self.xdg.surface.client.state.tree_changed(); + } +} diff --git a/src/ifs/wl_surface/xdg_surface/xdg_popup/types.rs b/src/ifs/wl_surface/xdg_surface/xdg_popup/types.rs index a0359bf2..498e0f6a 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_popup/types.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup/types.rs @@ -18,6 +18,10 @@ pub enum XdgPopupError { GrabError(#[from] GrabError), #[error("Could not process `reposition` request")] RepositionError(#[from] RepositionError), + #[error("The `xdg_positioner` is incomplete")] + Incomplete, + #[error("The anchor rectangle of the `xdg_positioner` extends outside the parent")] + AnchorRectOutside, } #[derive(Debug, Error)] @@ -46,9 +50,12 @@ pub enum RepositionError { ParseFailed(#[source] Box), #[error(transparent)] ClientError(Box), + #[error(transparent)] + XdgPopupError(Box), } efrom!(RepositionError, ParseFailed, MsgParserError); efrom!(RepositionError, ClientError); +efrom!(RepositionError, XdgPopupError); pub(super) struct Destroy; impl RequestParser<'_> for Destroy { diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs index 0e3b60a9..2c7a3a0c 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs @@ -3,12 +3,11 @@ mod types; use crate::client::DynEventFormatter; use crate::fixed::Fixed; use crate::ifs::wl_seat::WlSeatGlobal; -use crate::ifs::wl_surface::wl_subsurface::WlSubsurface; -use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceExt}; +use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceExt}; use crate::object::{Interface, Object, ObjectId}; use crate::rect::Rect; use crate::render::Renderer; -use crate::tree::ContainerNode; +use crate::tree::{ContainerNode, StackedNode}; use crate::tree::{FloatNode, FoundNode, Node, NodeId, ToplevelNodeId, WorkspaceNode}; use crate::utils::buffd::MsgParser; use crate::utils::clonecell::CloneCell; @@ -77,7 +76,6 @@ pub struct XdgToplevel { pub parent_node: CloneCell>>, pub parent: CloneCell>>, pub children: RefCell>>, - pub focus_subsurface: CloneCell>>, states: RefCell>, } @@ -95,7 +93,6 @@ impl XdgToplevel { parent_node: Default::default(), parent: Default::default(), children: RefCell::new(Default::default()), - focus_subsurface: Default::default(), states: RefCell::new(states), } } @@ -262,10 +259,10 @@ impl XdgToplevel { self.parent_node.set(Some(floater.clone())); floater .display_link - .set(Some(state.root.floaters.add_last(floater.clone()))); + .set(Some(state.root.stacked.add_last(StackedNode::Float(floater.clone())))); floater .workspace_link - .set(Some(workspace.floaters.add_last(floater.clone()))); + .set(Some(workspace.stacked.add_last(StackedNode::Float(floater.clone())))); } fn map_tiled(self: &Rc) { @@ -333,7 +330,6 @@ impl Object for XdgToplevel { } self.parent.set(None); let _children = mem::take(&mut *self.children.borrow_mut()); - self.focus_subsurface.set(None); } } @@ -346,29 +342,12 @@ impl Node for XdgToplevel { self.parent_node.set(None); } - fn find_child_at(&self, mut x: i32, mut y: i32) -> Option { - if let Some(geo) = self.xdg.geometry.get() { - let (xt, yt) = geo.translate_inv(x, y); - x = xt; - y = yt; - } - match self.xdg.surface.find_surface_at(x, y) { - Some((node, x, y)) => Some(FoundNode { - node: if std::ptr::eq(node.deref(), self.xdg.surface.deref()) { - node - } else { - node.ext.get().into_node().unwrap() - }, - x, - y, - contained: true, - }), - _ => None, - } + fn find_child_at(&self, x: i32, y: i32) -> Option { + self.xdg.find_child_at(x, y) } fn render(&self, renderer: &mut Renderer, x: i32, y: i32) { - renderer.render_toplevel(self, x, y) + renderer.render_xdg_surface(&self.xdg, x, y) } fn get_workspace(self: Rc) -> Option> { @@ -379,16 +358,23 @@ impl Node for XdgToplevel { seat.enter_toplevel(&self); } - fn change_size(self: Rc, width: i32, height: i32) { - self.xdg.surface.client.event(self.configure(width, height)); - self.xdg.send_configure(); - self.xdg.surface.client.flush(); + fn change_extents(self: Rc, rect: &Rect) { + let de = self.xdg.absolute_desired_extents.replace(*rect); + if de.width() != rect.width() || de.height() != rect.height() { + self.xdg.surface.client.event(self.configure(rect.width(), rect.height())); + self.xdg.send_configure(); + self.xdg.surface.client.flush(); + } + if de.x1() != rect.x1() || de.y1() != rect.y1() { + self.xdg.update_popup_positions(); + } } } impl XdgSurfaceExt for XdgToplevel { - fn initial_configure(self: Rc) { + fn initial_configure(self: Rc) -> Result<(), XdgSurfaceError> { self.xdg.surface.client.event(self.configure(0, 0)); + Ok(()) } fn post_commit(self: Rc) { diff --git a/src/ifs/xdg_positioner/mod.rs b/src/ifs/xdg_positioner/mod.rs index 7bbc2382..f7b3df42 100644 --- a/src/ifs/xdg_positioner/mod.rs +++ b/src/ifs/xdg_positioner/mod.rs @@ -3,10 +3,9 @@ mod types; use crate::client::Client; use crate::ifs::xdg_wm_base::XdgWmBaseObj; use crate::object::{Interface, Object, ObjectId}; +use crate::rect::Rect; use crate::utils::buffd::MsgParser; use bitflags::bitflags; -use num_derive::FromPrimitive; -use num_traits::FromPrimitive; use std::cell::RefCell; use std::rc::Rc; pub use types::*; @@ -24,41 +23,41 @@ const SET_PARENT_CONFIGURE: u32 = 9; const INVALID_INPUT: u32 = 0; -#[derive(Debug, Eq, PartialEq, Copy, Clone, FromPrimitive)] -pub enum Anchor { - None = 0, - Top = 1, - Bottom = 2, - Left = 3, - Right = 4, - TopLeft = 5, - BottomLeft = 6, - TopRight = 7, - BottomRight = 8, -} +const NONE: u32 = 0; +const TOP: u32 = 1; +const BOTTOM: u32 = 2; +const LEFT: u32 = 3; +const RIGHT: u32 = 4; +const TOP_LEFT: u32 = 5; +const BOTTOM_LEFT: u32 = 6; +const TOP_RIGHT: u32 = 7; +const BOTTOM_RIGHT: u32 = 8; -impl Default for Anchor { - fn default() -> Self { - Self::None +bitflags::bitflags! { + #[derive(Default)] + pub struct Square: u32 { + const TOP = 1 << 0; + const BOTTOM = 1 << 1; + const LEFT = 1 << 2; + const RIGHT = 1 << 3; } } -#[derive(Debug, Eq, PartialEq, Copy, Clone, FromPrimitive)] -pub enum Gravity { - None = 0, - Top = 1, - Bottom = 2, - Left = 3, - Right = 4, - TopLeft = 5, - BottomLeft = 6, - TopRight = 7, - BottomRight = 8, -} - -impl Default for Gravity { - fn default() -> Self { - Self::None +impl Square { + fn from_enum(e: u32) -> Option { + let s = match e { + NONE => Square::empty(), + TOP => Square::TOP, + BOTTOM => Square::BOTTOM, + LEFT => Square::LEFT, + RIGHT => Square::RIGHT, + TOP_LEFT => Square::TOP | Square::LEFT, + BOTTOM_LEFT => Square::BOTTOM | Square::LEFT, + TOP_RIGHT => Square::TOP | Square::RIGHT, + BOTTOM_RIGHT => Square::BOTTOM | Square::RIGHT, + _ => return None, + }; + Some(s) } } @@ -86,23 +85,61 @@ pub struct XdgPositioner { #[derive(Copy, Clone, Debug, Default)] pub struct XdgPositioned { - pub size_width: u32, - pub size_height: u32, - pub ar_x: i32, - pub ar_y: i32, - pub ar_width: u32, - pub ar_height: u32, - pub anchor: Anchor, - pub gravity: Gravity, + pub size_width: i32, + pub size_height: i32, + pub ar: Rect, + pub anchor: Square, + pub gravity: Square, pub ca: CA, pub off_x: i32, pub off_y: i32, pub reactive: bool, - pub parent_width: u32, - pub parent_height: u32, + pub parent_width: i32, + pub parent_height: i32, pub parent_serial: u32, } +impl XdgPositioned { + pub fn is_complete(&self) -> bool { + self.size_height != 0 && self.size_width != 0 + } + + pub fn get_position(&self) -> Rect { + let mut x1 = self.off_x; + let mut y1 = self.off_x; + + if self.anchor.contains(Square::LEFT) { + x1 += self.ar.x1(); + } else if self.anchor.contains(Square::RIGHT) { + x1 += self.ar.x2(); + } else { + x1 += self.ar.x1() + self.ar.width() / 2; + } + + if self.anchor.contains(Square::TOP) { + y1 += self.ar.y1(); + } else if self.anchor.contains(Square::BOTTOM) { + y1 += self.ar.y2(); + } else { + y1 += self.ar.y1() + self.ar.height() / 2; + } + + if self.gravity.contains(Square::LEFT) { + x1 -= self.size_width; + } else if !self.gravity.contains(Square::RIGHT) { + x1 -= self.size_width / 2; + } + + if self.gravity.contains(Square::TOP) { + y1 -= self.size_height; + } else if !self.gravity.contains(Square::BOTTOM) { + y1 -= self.size_height / 2; + } + + Rect::new_sized(x1, y1, self.size_width, self.size_height).unwrap() + } +} + impl XdgPositioner { pub fn new(base: &Rc, id: XdgPositionerId, client: &Rc) -> Self { Self { @@ -113,9 +150,8 @@ impl XdgPositioner { } } - #[allow(dead_code)] - pub fn clone(&self) -> Box { - Box::new(*self.position.borrow()) + pub fn value(&self) -> XdgPositioned { + *self.position.borrow() } fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { @@ -135,8 +171,8 @@ impl XdgPositioner { return Err(SetSizeError::NonPositiveSize); } let mut position = self.position.borrow_mut(); - position.size_width = req.width as u32; - position.size_height = req.height as u32; + position.size_width = req.width; + position.size_height = req.height; Ok(()) } @@ -151,16 +187,13 @@ impl XdgPositioner { return Err(SetAnchorRectError::NegativeAnchorRect); } let mut position = self.position.borrow_mut(); - position.ar_x = req.x; - position.ar_y = req.y; - position.ar_width = req.width as u32; - position.ar_height = req.height as u32; + position.ar = Rect::new_sized(req.x, req.y, req.width, req.height).unwrap(); Ok(()) } fn set_anchor(&self, parser: MsgParser<'_, '_>) -> Result<(), SetAnchorError> { let req: SetAnchor = self.client.parse(self, parser)?; - let anchor = match Anchor::from_u32(req.anchor) { + let anchor = match Square::from_enum(req.anchor) { Some(a) => a, _ => return Err(SetAnchorError::UnknownAnchor(req.anchor)), }; @@ -170,7 +203,7 @@ impl XdgPositioner { fn set_gravity(&self, parser: MsgParser<'_, '_>) -> Result<(), SetGravityError> { let req: SetGravity = self.client.parse(self, parser)?; - let gravity = match Gravity::from_u32(req.gravity) { + let gravity = match Square::from_enum(req.gravity) { Some(a) => a, _ => return Err(SetGravityError::UnknownGravity(req.gravity)), }; @@ -220,8 +253,8 @@ impl XdgPositioner { return Err(SetParentSizeError::NegativeParentSize); } let mut position = self.position.borrow_mut(); - position.parent_width = req.parent_width as u32; - position.parent_height = req.parent_height as u32; + position.parent_width = req.parent_width; + position.parent_height = req.parent_height; Ok(()) } diff --git a/src/rect.rs b/src/rect.rs index e874694a..f1226540 100644 --- a/src/rect.rs +++ b/src/rect.rs @@ -60,6 +60,10 @@ impl Rect { self.x1 <= x && self.y1 <= y && self.x2 > x && self.y2 > y } + pub fn contains_rect(&self, rect: &Self) -> bool { + self.x1 <= rect.x1 && self.y1 <= rect.x1 && rect.x2 <= self.x2 && rect.y2 <= self.y2 + } + pub fn is_empty(&self) -> bool { self.x1 == self.x2 || self.y1 == self.y2 } diff --git a/src/render/renderer/renderer.rs b/src/render/renderer/renderer.rs index 85171aa4..027ef482 100644 --- a/src/render/renderer/renderer.rs +++ b/src/render/renderer/renderer.rs @@ -1,5 +1,4 @@ use crate::ifs::wl_buffer::WlBuffer; -use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel; use crate::ifs::wl_surface::WlSurface; use crate::rect::Rect; use crate::render::gl::frame_buffer::{with_scissor, GlFrameBuffer}; @@ -10,13 +9,11 @@ use crate::render::gl::sys::{ GL_TEXTURE_MIN_FILTER, GL_TRIANGLES, GL_TRIANGLE_STRIP, }; use crate::render::renderer::context::RenderContext; -use crate::tree::{ - ContainerFocus, ContainerNode, ContainerSplit, FloatNode, OutputNode, WorkspaceNode, - CONTAINER_BORDER, CONTAINER_TITLE_HEIGHT, -}; +use crate::tree::{ContainerFocus, ContainerNode, ContainerSplit, FloatNode, OutputNode, WorkspaceNode, CONTAINER_BORDER, CONTAINER_TITLE_HEIGHT, StackedNode}; use std::ops::Deref; use std::rc::Rc; use std::slice; +use crate::ifs::wl_surface::xdg_surface::XdgSurface; const NON_COLOR: (f32, f32, f32) = (0.2, 0.2, 0.2); const CHILD_COLOR: (f32, f32, f32) = (0.8, 0.8, 0.8); @@ -46,6 +43,18 @@ impl Renderer<'_> { if let Some(node) = workspace.container.get() { self.render_container(&node, x, y) } + for stacked in workspace.stacked.iter() { + match &*stacked { + StackedNode::Float(f) => { + let pos = f.position.get(); + self.render_floating(f, pos.x1(), pos.y1()); + } + StackedNode::Popup(p) => { + let pos = p.xdg.absolute_desired_extents.get(); + self.render_xdg_surface(&p.xdg, pos.x1(), pos.y1()); + } + } + } } fn x_to_f(&self, x: i32) -> f32 { @@ -167,9 +176,9 @@ impl Renderer<'_> { } } - pub fn render_toplevel(&mut self, tl: &XdgToplevel, mut x: i32, mut y: i32) { - let surface = &tl.xdg.surface; - if let Some(geo) = tl.xdg.geometry() { + pub fn render_xdg_surface(&mut self, xdg: &XdgSurface, mut x: i32, mut y: i32) { + let surface = &xdg.surface; + if let Some(geo) = xdg.geometry() { let (xt, yt) = geo.translate(x, y); x = xt; y = yt; diff --git a/src/tasks/output.rs b/src/tasks/output.rs index 2fc0ecdd..949752fe 100644 --- a/src/tasks/output.rs +++ b/src/tasks/output.rs @@ -6,6 +6,7 @@ use crate::utils::clonecell::CloneCell; use crate::State; use std::cell::{Cell, RefCell}; use std::rc::Rc; +use crate::rect::Rect; pub struct OutputHandler { pub state: Rc, @@ -31,7 +32,7 @@ impl OutputHandler { id: self.state.node_ids.next(), output: CloneCell::new(on.clone()), container: Default::default(), - floaters: Default::default(), + stacked: Default::default(), }); on.workspace.set(Some(workspace)); self.state.root.outputs.set(self.output.id(), on.clone()); @@ -50,7 +51,7 @@ impl OutputHandler { if new_width != width || new_height != height { width = new_width; height = new_height; - on.clone().change_size(width, height); + on.clone().change_extents(&Rect::new_sized(0, 0, new_width, new_height).unwrap()); } global.update_properties(); ae.triggered().await; diff --git a/src/tree/container.rs b/src/tree/container.rs index eb749a7b..b5f66e67 100644 --- a/src/tree/container.rs +++ b/src/tree/container.rs @@ -35,6 +35,8 @@ pub struct ContainerNode { pub mono_child: CloneCell>>, pub mono_body: Cell, pub mono_content: Cell, + pub abs_x1: Cell, + pub abs_y1: Cell, pub width: Cell, pub height: Cell, pub content_width: Cell, @@ -90,6 +92,8 @@ impl ContainerNode { mono_child: CloneCell::new(None), mono_body: Cell::new(Default::default()), mono_content: Cell::new(Default::default()), + abs_x1: Cell::new(0), + abs_y1: Cell::new(0), width: Cell::new(0), height: Cell::new(0), content_width: Cell::new(0), @@ -225,8 +229,8 @@ impl ContainerNode { } } for child in self.children.iter() { - let body = child.body.get(); - child.node.clone().change_size(body.width(), body.height()); + let body = child.body.get().move_(self.abs_x1.get(), self.abs_y1.get()); + child.node.clone().change_extents(&body); child.position_content(); } } @@ -347,10 +351,20 @@ impl Node for ContainerNode { self.parent.get().get_workspace() } - fn change_size(self: Rc, width: i32, height: i32) { - self.width.set(width); - self.height.set(height); - self.update_content_size(); - self.apply_factors(1.0); + fn change_extents(self: Rc, rect: &Rect) { + self.abs_x1.set(rect.x1()); + self.abs_y1.set(rect.y1()); + let mut size_changed = false; + size_changed |= self.width.replace(rect.width()) != rect.width(); + size_changed |= self.height.replace(rect.height()) != rect.height(); + if size_changed { + self.update_content_size(); + self.apply_factors(1.0); + } else { + for child in self.children.iter() { + let body = child.body.get().move_(self.abs_x1.get(), self.abs_y1.get()); + child.node.clone().change_extents(&body); + } + } } } diff --git a/src/tree/mod.rs b/src/tree/mod.rs index e3fd84a0..7840985b 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -12,6 +12,7 @@ use std::cell::{Cell, RefCell}; use std::fmt::Display; use std::rc::Rc; pub use workspace::*; +use crate::ifs::wl_surface::xdg_surface::xdg_popup::XdgPopup; mod container; mod workspace; @@ -129,9 +130,8 @@ pub trait Node { None } - fn change_size(self: Rc, width: i32, height: i32) { - let _ = width; - let _ = height; + fn change_extents(self: Rc, rect: &Rect) { + let _ = rect; } } @@ -144,10 +144,15 @@ pub struct FoundNode { tree_id!(ToplevelNodeId); +pub enum StackedNode { + Float(Rc), + Popup(Rc), +} + pub struct DisplayNode { pub id: NodeId, pub outputs: CopyHashMap>, - pub floaters: LinkedList>, + pub stacked: LinkedList, } impl DisplayNode { @@ -155,7 +160,7 @@ impl DisplayNode { Self { id, outputs: Default::default(), - floaters: Default::default(), + stacked: Default::default(), } } } @@ -171,8 +176,11 @@ impl Node for DisplayNode { output.clear(); } outputs.clear(); - for floater in self.floaters.iter() { - floater.clear(); + for floater in self.stacked.iter() { + match &*floater { + StackedNode::Float(f) => f.clear(), + StackedNode::Popup(p) => p.clear(), + } } } @@ -237,11 +245,10 @@ impl Node for OutputNode { self.workspace.set(None); } - fn change_size(self: Rc, width: i32, height: i32) { - self.position - .set(Rect::new_sized(0, 0, width, height).unwrap()); + fn change_extents(self: Rc, rect: &Rect) { + self.position.set(*rect); if let Some(c) = self.workspace.get() { - c.change_size(width, height); + c.change_extents(rect); } } } @@ -252,8 +259,8 @@ pub struct FloatNode { pub visible: Cell, pub position: Cell, pub display: Rc, - pub display_link: Cell>>>, - pub workspace_link: Cell>>>, + pub display_link: Cell>>, + pub workspace_link: Cell>>, pub workspace: CloneCell>, pub child: CloneCell>>, } @@ -298,4 +305,10 @@ impl Node for FloatNode { self.position .set(Rect::new_sized(pos.x1(), pos.x2(), width, height).unwrap()); } + + fn change_extents(self: Rc, rect: &Rect) { + if let Some(child) = self.child.get() { + child.change_extents(rect); + } + } } diff --git a/src/tree/workspace.rs b/src/tree/workspace.rs index 421a8552..65e9761f 100644 --- a/src/tree/workspace.rs +++ b/src/tree/workspace.rs @@ -1,9 +1,11 @@ +use std::ops::Deref; use crate::render::Renderer; use crate::tree::container::ContainerNode; -use crate::tree::{FloatNode, FoundNode, Node, NodeId, OutputNode}; +use crate::tree::{FoundNode, Node, NodeId, OutputNode, StackedNode}; use crate::utils::clonecell::CloneCell; use crate::utils::linkedlist::LinkedList; use std::rc::Rc; +use crate::rect::Rect; tree_id!(WorkspaceNodeId); @@ -11,7 +13,7 @@ pub struct WorkspaceNode { pub id: WorkspaceNodeId, pub output: CloneCell>, pub container: CloneCell>>, - pub floaters: LinkedList>, + pub stacked: LinkedList, } impl WorkspaceNode { @@ -19,7 +21,7 @@ impl WorkspaceNode { let output = self.output.get().position.get(); container .clone() - .change_size(output.width(), output.height()); + .change_extents(&output); self.container.set(Some(container.clone())); } } @@ -36,6 +38,18 @@ impl Node for WorkspaceNode { } fn find_child_at(&self, x: i32, y: i32) -> Option { + for stacked in self.stacked.rev_iter() { + let (pos, node) = match stacked.deref() { + StackedNode::Float(f) => (f.position.get(), &**f as &dyn Node), + StackedNode::Popup(p) => (p.xdg.absolute_desired_extents.get(), &**p as &dyn Node), + }; + if pos.contains(x, y) { + let (x, y) = pos.translate(x, y); + if let Some(n) = node.find_child_at(x, y) { + return Some(n); + } + } + } match self.container.get() { Some(node) => Some(FoundNode { node, @@ -59,9 +73,9 @@ impl Node for WorkspaceNode { self.container.set(None); } - fn change_size(self: Rc, width: i32, height: i32) { + fn change_extents(self: Rc, rect: &Rect) { if let Some(c) = self.container.get() { - c.change_size(width, height); + c.change_extents(rect); } } }