1
0
Fork 0
forked from wry/wry

tree: add Node::node_layer

This commit is contained in:
Julian Orth 2025-07-19 21:57:47 +02:00
parent a5e8b39e4f
commit dbc954dded
19 changed files with 294 additions and 46 deletions

View file

@ -76,8 +76,8 @@ use {
renderer::Renderer, renderer::Renderer,
tree::{ tree::{
BeforeLatchListener, BeforeLatchResult, ContainerNode, FindTreeResult, FoundNode, BeforeLatchListener, BeforeLatchResult, ContainerNode, FindTreeResult, FoundNode,
LatchListener, Node, NodeId, NodeLocation, NodeVisitor, NodeVisitorBase, OutputNode, LatchListener, Node, NodeId, NodeLayerLink, NodeLocation, NodeVisitor, NodeVisitorBase,
PlaceholderNode, PresentationListener, ToplevelNode, VblankListener, OutputNode, PlaceholderNode, PresentationListener, ToplevelNode, VblankListener,
}, },
utils::{ utils::{
cell_ext::CellExt, clonecell::CloneCell, copyhashmap::CopyHashMap, cell_ext::CellExt, clonecell::CloneCell, copyhashmap::CopyHashMap,
@ -372,6 +372,8 @@ enum CommitAction {
} }
trait SurfaceExt { trait SurfaceExt {
fn node_layer(&self) -> NodeLayerLink;
fn commit_requested(self: Rc<Self>, pending: &mut Box<PendingState>) -> CommitAction { fn commit_requested(self: Rc<Self>, pending: &mut Box<PendingState>) -> CommitAction {
let _ = pending; let _ = pending;
CommitAction::ContinueCommit CommitAction::ContinueCommit
@ -444,6 +446,10 @@ trait SurfaceExt {
pub struct NoneSurfaceExt; pub struct NoneSurfaceExt;
impl SurfaceExt for NoneSurfaceExt { impl SurfaceExt for NoneSurfaceExt {
fn node_layer(&self) -> NodeLayerLink {
NodeLayerLink::Display
}
fn is_some(&self) -> bool { fn is_some(&self) -> bool {
false false
} }
@ -1796,6 +1802,10 @@ impl Node for WlSurface {
Some(self.location.get()) Some(self.location.get())
} }
fn node_layer(&self) -> NodeLayerLink {
self.ext.get().node_layer()
}
fn node_active_changed(&self, active: bool) { fn node_active_changed(&self, active: bool) {
if let Some(tl) = self.toplevel.get() { if let Some(tl) = self.toplevel.get() {
tl.tl_surface_active_changed(active); tl.tl_surface_active_changed(active);

View file

@ -11,8 +11,8 @@ use {
object::{Object, Version}, object::{Object, Version},
rect::Rect, rect::Rect,
tree::{ tree::{
FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeLocation, NodeVisitor, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeLayerLink, NodeLocation,
OutputNode, NodeVisitor, OutputNode,
}, },
utils::numcell::NumCell, utils::numcell::NumCell,
wire::{ExtSessionLockSurfaceV1Id, WlSurfaceId, ext_session_lock_surface_v1::*}, wire::{ExtSessionLockSurfaceV1Id, WlSurfaceId, ext_session_lock_surface_v1::*},
@ -95,6 +95,10 @@ impl ExtSessionLockSurfaceV1 {
} }
impl SurfaceExt for ExtSessionLockSurfaceV1 { impl SurfaceExt for ExtSessionLockSurfaceV1 {
fn node_layer(&self) -> NodeLayerLink {
NodeLayerLink::Lock
}
fn extents_changed(&self) { fn extents_changed(&self) {
self.client.state.tree_changed(); self.client.state.tree_changed();
} }
@ -138,6 +142,10 @@ impl Node for ExtSessionLockSurfaceV1 {
self.surface.node_location() self.surface.node_location()
} }
fn node_layer(&self) -> NodeLayerLink {
NodeLayerLink::Lock
}
fn node_find_tree_at( fn node_find_tree_at(
&self, &self,
x: i32, x: i32,

View file

@ -11,8 +11,8 @@ use {
}, },
rect::Rect, rect::Rect,
tree::{ tree::{
FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeLocation, NodeVisitor, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeLayerLink, NodeLocation,
OutputNode, StackedNode, NodeVisitor, OutputNode, StackedNode,
}, },
utils::{ utils::{
copyhashmap::CopyHashMap, copyhashmap::CopyHashMap,
@ -216,6 +216,13 @@ impl<T: TrayItem> XdgPopupParent for Popup<T> {
// nothing // nothing
} }
fn node_layer(&self) -> NodeLayerLink {
let Some(link) = self.stack_link.borrow().as_ref().map(|w| w.to_ref()) else {
return NodeLayerLink::Display;
};
NodeLayerLink::Stacked(link)
}
fn tray_item(&self) -> Option<TrayItemId> { fn tray_item(&self) -> Option<TrayItemId> {
Some(self.parent.data().tray_item_id) Some(self.parent.data().tray_item_id)
} }
@ -230,6 +237,10 @@ impl<T: TrayItem> XdgPopupParent for Popup<T> {
} }
impl<T: TrayItem> SurfaceExt for T { impl<T: TrayItem> SurfaceExt for T {
fn node_layer(&self) -> NodeLayerLink {
NodeLayerLink::Output
}
fn before_apply_commit( fn before_apply_commit(
self: Rc<Self>, self: Rc<Self>,
pending: &mut PendingState, pending: &mut PendingState,
@ -308,6 +319,10 @@ impl<T: TrayItem> Node for T {
self.data().surface.node_location() self.data().surface.node_location()
} }
fn node_layer(&self) -> NodeLayerLink {
NodeLayerLink::Output
}
fn node_find_tree_at( fn node_find_tree_at(
&self, &self,
x: i32, x: i32,
@ -384,7 +399,7 @@ fn get_popup<T: TrayItem>(
}; };
seat.add_tray_item_popup(item, &popup); seat.add_tray_item_popup(item, &popup);
let stack = data.client.state.root.stacked.clone(); let stack = data.client.state.root.stacked.clone();
popup.xdg.set_popup_stack(&stack); popup.xdg.set_popup_stack(&stack, false);
popup.xdg.set_output(&node); popup.xdg.set_output(&node);
let user = Rc::new(Popup { let user = Rc::new(Popup {
parent: item.clone(), parent: item.clone(),

View file

@ -7,7 +7,7 @@ use {
}, },
leaks::Tracker, leaks::Tracker,
object::{Object, Version}, object::{Object, Version},
tree::Node, tree::{Node, NodeLayerLink},
utils::{ utils::{
clonecell::CloneCell, clonecell::CloneCell,
linkedlist::{LinkedNode, NodeRef}, linkedlist::{LinkedNode, NodeRef},
@ -361,6 +361,10 @@ impl Object for WlSubsurface {
simple_add_obj!(WlSubsurface); simple_add_obj!(WlSubsurface);
impl SurfaceExt for WlSubsurface { impl SurfaceExt for WlSubsurface {
fn node_layer(&self) -> NodeLayerLink {
self.parent.node_layer()
}
fn commit_requested(self: Rc<Self>, pending: &mut Box<PendingState>) -> CommitAction { fn commit_requested(self: Rc<Self>, pending: &mut Box<PendingState>) -> CommitAction {
if self.sync() { if self.sync() {
let mut parent_pending = self.pending(); let mut parent_pending = self.pending();

View file

@ -5,7 +5,7 @@ use {
x_surface::{xwayland_surface_v1::XwaylandSurfaceV1, xwindow::Xwindow}, x_surface::{xwayland_surface_v1::XwaylandSurfaceV1, xwindow::Xwindow},
}, },
leaks::Tracker, leaks::Tracker,
tree::{Node, ToplevelNode, ToplevelNodeBase}, tree::{Node, NodeLayerLink, ToplevelNode, ToplevelNodeBase},
utils::clonecell::CloneCell, utils::clonecell::CloneCell,
xwayland::XWaylandEvent, xwayland::XWaylandEvent,
}, },
@ -23,6 +23,13 @@ pub struct XSurface {
} }
impl SurfaceExt for XSurface { impl SurfaceExt for XSurface {
fn node_layer(&self) -> NodeLayerLink {
let Some(win) = self.xwindow.get() else {
return NodeLayerLink::Display;
};
win.node_layer()
}
fn after_apply_commit(self: Rc<Self>) { fn after_apply_commit(self: Rc<Self>) {
if let Some(xwindow) = self.xwindow.get() { if let Some(xwindow) = self.xwindow.get() {
xwindow.map_status_changed(); xwindow.map_status_changed();

View file

@ -12,8 +12,8 @@ use {
state::State, state::State,
tree::{ tree::{
ContainerSplit, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, ContainerSplit, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId,
NodeLocation, NodeVisitor, OutputNode, StackedNode, TileDragDestination, ToplevelData, NodeLayerLink, NodeLocation, NodeVisitor, OutputNode, StackedNode, TileDragDestination,
ToplevelNode, ToplevelNodeBase, ToplevelType, WorkspaceNode, ToplevelData, ToplevelNode, ToplevelNodeBase, ToplevelType, WorkspaceNode,
default_tile_drag_destination, default_tile_drag_destination,
}, },
utils::{clonecell::CloneCell, copyhashmap::CopyHashMap, linkedlist::LinkedNode}, utils::{clonecell::CloneCell, copyhashmap::CopyHashMap, linkedlist::LinkedNode},
@ -375,6 +375,13 @@ impl Node for Xwindow {
self.x.surface.node_location() self.x.surface.node_location()
} }
fn node_layer(&self) -> NodeLayerLink {
if let Some(link) = self.display_link.borrow().as_ref() {
return NodeLayerLink::Stacked(link.to_ref());
}
self.toplevel_data.node_layer()
}
fn node_do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, _direction: Direction) { fn node_do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, _direction: Direction) {
seat.focus_toplevel(self.clone()); seat.focus_toplevel(self.clone());
} }

View file

@ -19,7 +19,8 @@ use {
object::Object, object::Object,
rect::Rect, rect::Rect,
tree::{ tree::{
FindTreeResult, FoundNode, Node, NodeLocation, OutputNode, StackedNode, WorkspaceNode, FindTreeResult, FoundNode, Node, NodeLayerLink, NodeLocation, OutputNode, StackedNode,
WorkspaceNode,
}, },
utils::{ utils::{
clonecell::CloneCell, clonecell::CloneCell,
@ -75,6 +76,7 @@ pub struct XdgSurface {
pub absolute_desired_extents: Cell<Rect>, pub absolute_desired_extents: Cell<Rect>,
ext: CloneCell<Option<Rc<dyn XdgSurfaceExt>>>, ext: CloneCell<Option<Rc<dyn XdgSurfaceExt>>>,
popup_display_stack: CloneCell<Rc<LinkedList<Rc<dyn StackedNode>>>>, popup_display_stack: CloneCell<Rc<LinkedList<Rc<dyn StackedNode>>>>,
is_above_layers: Cell<bool>,
popups: CopyHashMap<XdgPopupId, Rc<Popup>>, popups: CopyHashMap<XdgPopupId, Rc<Popup>>,
pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>, pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
pub tracker: Tracker<Self>, pub tracker: Tracker<Self>,
@ -152,6 +154,16 @@ impl XdgPopupParent for Popup {
} }
} }
fn node_layer(&self) -> NodeLayerLink {
let Some(link) = self.display_link.borrow().as_ref().map(|w| w.to_ref()) else {
return NodeLayerLink::Display;
};
match self.popup.xdg.is_above_layers.get() {
true => NodeLayerLink::StackedAboveLayers(link),
false => NodeLayerLink::Stacked(link),
}
}
fn tray_item(&self) -> Option<TrayItemId> { fn tray_item(&self) -> Option<TrayItemId> {
self.parent.clone().tray_item() self.parent.clone().tray_item()
} }
@ -201,6 +213,8 @@ pub trait XdgSurfaceExt: Debug {
} }
fn make_visible(self: Rc<Self>); fn make_visible(self: Rc<Self>);
fn node_layer(&self) -> NodeLayerLink;
} }
impl XdgSurface { impl XdgSurface {
@ -217,6 +231,7 @@ impl XdgSurface {
absolute_desired_extents: Cell::new(Default::default()), absolute_desired_extents: Cell::new(Default::default()),
ext: Default::default(), ext: Default::default(),
popup_display_stack: CloneCell::new(surface.client.state.root.stacked.clone()), popup_display_stack: CloneCell::new(surface.client.state.root.stacked.clone()),
is_above_layers: Cell::new(false),
popups: Default::default(), popups: Default::default(),
workspace: Default::default(), workspace: Default::default(),
tracker: Default::default(), tracker: Default::default(),
@ -331,7 +346,12 @@ impl XdgSurface {
}) })
} }
pub fn set_popup_stack(&self, stack: &Rc<LinkedList<Rc<dyn StackedNode>>>) { pub fn set_popup_stack(
&self,
stack: &Rc<LinkedList<Rc<dyn StackedNode>>>,
is_above_layers: bool,
) {
self.is_above_layers.set(is_above_layers);
let prev = self.popup_display_stack.set(stack.clone()); let prev = self.popup_display_stack.set(stack.clone());
if rc_eq(&prev, stack) { if rc_eq(&prev, stack) {
return; return;
@ -340,7 +360,7 @@ impl XdgSurface {
if let Some(dl) = &*popup.display_link.borrow() { if let Some(dl) = &*popup.display_link.borrow() {
stack.add_last_existing(dl); stack.add_last_existing(dl);
} }
popup.popup.xdg.set_popup_stack(stack); popup.popup.xdg.set_popup_stack(stack, is_above_layers);
} }
} }
@ -423,7 +443,10 @@ impl XdgSurfaceRequestHandler for XdgSurface {
workspace_link: Default::default(), workspace_link: Default::default(),
}); });
popup.parent.set(Some(user.clone())); popup.parent.set(Some(user.clone()));
popup.xdg.set_popup_stack(&parent.popup_display_stack.get()); popup.xdg.set_popup_stack(
&parent.popup_display_stack.get(),
parent.is_above_layers.get(),
);
popup.xdg.set_output(&parent.surface.output.get()); popup.xdg.set_output(&parent.surface.output.get());
parent.popups.set(req.id, user); parent.popups.set(req.id, user);
} }
@ -526,6 +549,13 @@ impl Object for XdgSurface {
dedicated_add_obj!(XdgSurface, XdgSurfaceId, xdg_surfaces); dedicated_add_obj!(XdgSurface, XdgSurfaceId, xdg_surfaces);
impl SurfaceExt for XdgSurface { impl SurfaceExt for XdgSurface {
fn node_layer(&self) -> NodeLayerLink {
let Some(ext) = self.ext.get() else {
return NodeLayerLink::Display;
};
ext.node_layer()
}
fn before_apply_commit( fn before_apply_commit(
self: Rc<Self>, self: Rc<Self>,
pending: &mut PendingState, pending: &mut PendingState,

View file

@ -19,8 +19,8 @@ use {
rect::Rect, rect::Rect,
renderer::Renderer, renderer::Renderer,
tree::{ tree::{
FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeLocation, NodeVisitor, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeLayerLink, NodeLocation,
OutputNode, StackedNode, NodeVisitor, OutputNode, StackedNode,
}, },
utils::clonecell::CloneCell, utils::clonecell::CloneCell,
wire::{XdgPopupId, xdg_popup::*}, wire::{XdgPopupId, xdg_popup::*},
@ -46,6 +46,7 @@ pub trait XdgPopupParent {
fn post_commit(&self); fn post_commit(&self);
fn visible(&self) -> bool; fn visible(&self) -> bool;
fn make_visible(self: Rc<Self>); fn make_visible(self: Rc<Self>);
fn node_layer(&self) -> NodeLayerLink;
fn tray_item(&self) -> Option<TrayItemId> { fn tray_item(&self) -> Option<TrayItemId> {
None None
} }
@ -324,6 +325,10 @@ impl Node for XdgPopup {
self.xdg.surface.node_location() self.xdg.surface.node_location()
} }
fn node_layer(&self) -> NodeLayerLink {
XdgSurfaceExt::node_layer(self)
}
fn node_find_tree_at( fn node_find_tree_at(
&self, &self,
x: i32, x: i32,
@ -441,6 +446,13 @@ impl XdgSurfaceExt for XdgPopup {
fn make_visible(self: Rc<Self>) { fn make_visible(self: Rc<Self>) {
self.node_make_visible(); self.node_make_visible();
} }
fn node_layer(&self) -> NodeLayerLink {
let Some(parent) = self.parent.get() else {
return NodeLayerLink::Display;
};
parent.node_layer()
}
} }
#[derive(Debug, Error)] #[derive(Debug, Error)]

View file

@ -27,9 +27,9 @@ use {
state::State, state::State,
tree::{ tree::{
ContainerSplit, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, ContainerSplit, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId,
NodeLocation, NodeVisitor, OutputNode, TileDragDestination, ToplevelData, ToplevelNode, NodeLayerLink, NodeLocation, NodeVisitor, OutputNode, TileDragDestination,
ToplevelNodeBase, ToplevelNodeId, ToplevelType, WorkspaceNode, ToplevelData, ToplevelNode, ToplevelNodeBase, ToplevelNodeId, ToplevelType,
default_tile_drag_destination, WorkspaceNode, default_tile_drag_destination,
}, },
utils::{clonecell::CloneCell, hash_map_ext::HashMapExt}, utils::{clonecell::CloneCell, hash_map_ext::HashMapExt},
wire::{XdgToplevelId, xdg_toplevel::*}, wire::{XdgToplevelId, xdg_toplevel::*},
@ -577,6 +577,10 @@ impl Node for XdgToplevel {
self.xdg.surface.node_location() self.xdg.surface.node_location()
} }
fn node_layer(&self) -> NodeLayerLink {
self.toplevel_data.node_layer()
}
fn node_do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, _direction: Direction) { fn node_do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, _direction: Direction) {
seat.focus_toplevel(self.clone()); seat.focus_toplevel(self.clone());
} }
@ -788,6 +792,10 @@ impl XdgSurfaceExt for XdgToplevel {
fn make_visible(self: Rc<Self>) { fn make_visible(self: Rc<Self>) {
self.node_make_visible(); self.node_make_visible();
} }
fn node_layer(&self) -> NodeLayerLink {
self.toplevel_data.node_layer()
}
} }
#[derive(Debug, Error)] #[derive(Debug, Error)]

View file

@ -15,8 +15,8 @@ use {
rect::Rect, rect::Rect,
renderer::Renderer, renderer::Renderer,
tree::{ tree::{
FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeLocation, NodeVisitor, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeLayerLink, NodeLocation,
OutputNode, StackedNode, NodeVisitor, OutputNode, StackedNode,
}, },
utils::{ utils::{
bitflags::BitflagsExt, bitflags::BitflagsExt,
@ -65,7 +65,7 @@ pub struct ZwlrLayerSurfaceV1 {
exclusive_zone: Cell<ExclusiveZone>, exclusive_zone: Cell<ExclusiveZone>,
margin: Cell<(i32, i32, i32, i32)>, margin: Cell<(i32, i32, i32, i32)>,
keyboard_interactivity: Cell<u32>, keyboard_interactivity: Cell<u32>,
link: Cell<Option<LinkedNode<Rc<Self>>>>, link: RefCell<Option<LinkedNode<Rc<Self>>>>,
seat_state: NodeSeatState, seat_state: NodeSeatState,
last_configure: Cell<(i32, i32)>, last_configure: Cell<(i32, i32)>,
exclusive_edge: Cell<Option<u32>>, exclusive_edge: Cell<Option<u32>>,
@ -171,7 +171,7 @@ impl ZwlrLayerSurfaceV1 {
exclusive_zone: Cell::new(ExclusiveZone::MoveSelf), exclusive_zone: Cell::new(ExclusiveZone::MoveSelf),
margin: Cell::new((0, 0, 0, 0)), margin: Cell::new((0, 0, 0, 0)),
keyboard_interactivity: Cell::new(0), keyboard_interactivity: Cell::new(0),
link: Cell::new(None), link: Default::default(),
seat_state: Default::default(), seat_state: Default::default(),
last_configure: Default::default(), last_configure: Default::default(),
exclusive_edge: Default::default(), exclusive_edge: Default::default(),
@ -291,7 +291,7 @@ impl ZwlrLayerSurfaceV1RequestHandler for ZwlrLayerSurfaceV1 {
return Err(ZwlrLayerSurfaceV1Error::PopupHasParent); return Err(ZwlrLayerSurfaceV1Error::PopupHasParent);
} }
let stack = self.client.state.root.stacked_above_layers.clone(); let stack = self.client.state.root.stacked_above_layers.clone();
popup.xdg.set_popup_stack(&stack); popup.xdg.set_popup_stack(&stack, true);
let user = Rc::new(Popup { let user = Rc::new(Popup {
parent: slf.clone(), parent: slf.clone(),
popup: popup.clone(), popup: popup.clone(),
@ -534,7 +534,7 @@ impl ZwlrLayerSurfaceV1 {
} }
pub fn destroy_node(&self) { pub fn destroy_node(&self) {
self.link.set(None); self.link.borrow_mut().take();
self.mapped.set(false); self.mapped.set(false);
self.surface.destroy_node(); self.surface.destroy_node();
self.seat_state.destroy_node(self); self.seat_state.destroy_node(self);
@ -562,6 +562,18 @@ impl ZwlrLayerSurfaceV1 {
} }
impl SurfaceExt for ZwlrLayerSurfaceV1 { impl SurfaceExt for ZwlrLayerSurfaceV1 {
fn node_layer(&self) -> NodeLayerLink {
let Some(link) = self.link.borrow().as_ref().map(|l| l.to_ref()) else {
return NodeLayerLink::Display;
};
match self.layer.get() {
0 => NodeLayerLink::Layer0(link),
1 => NodeLayerLink::Layer1(link),
2 => NodeLayerLink::Layer2(link),
_ => NodeLayerLink::Layer3(link),
}
}
fn before_apply_commit( fn before_apply_commit(
self: Rc<Self>, self: Rc<Self>,
pending: &mut PendingState, pending: &mut PendingState,
@ -587,7 +599,7 @@ impl SurfaceExt for ZwlrLayerSurfaceV1 {
} }
} else if buffer_is_some { } else if buffer_is_some {
let layer = &output.layers[self.layer.get() as usize]; let layer = &output.layers[self.layer.get() as usize];
self.link.set(Some(layer.add_last(self.clone()))); *self.link.borrow_mut() = Some(layer.add_last(self.clone()));
self.mapped.set(true); self.mapped.set(true);
self.compute_position(); self.compute_position();
self.update_exclusive_size(); self.update_exclusive_size();
@ -663,6 +675,10 @@ impl Node for ZwlrLayerSurfaceV1 {
self.surface.node_location() self.surface.node_location()
} }
fn node_layer(&self) -> NodeLayerLink {
SurfaceExt::node_layer(self)
}
fn node_find_tree_at( fn node_find_tree_at(
&self, &self,
x: i32, x: i32,
@ -728,6 +744,13 @@ impl XdgPopupParent for Popup {
fn make_visible(self: Rc<Self>) { fn make_visible(self: Rc<Self>) {
// nothing // nothing
} }
fn node_layer(&self) -> NodeLayerLink {
let Some(link) = self.stack_link.borrow().as_ref().map(|w| w.to_ref()) else {
return NodeLayerLink::Display;
};
NodeLayerLink::StackedAboveLayers(link)
}
} }
object_base! { object_base! {
@ -738,7 +761,7 @@ object_base! {
impl Object for ZwlrLayerSurfaceV1 { impl Object for ZwlrLayerSurfaceV1 {
fn break_loops(&self) { fn break_loops(&self) {
self.destroy_node(); self.destroy_node();
self.link.set(None); self.link.borrow_mut().take();
} }
} }

View file

@ -9,6 +9,7 @@ use {
object::{Object, Version}, object::{Object, Version},
rect::Rect, rect::Rect,
state::State, state::State,
tree::NodeLayerLink,
wire::{WlSurfaceId, ZwpInputPopupSurfaceV2Id, zwp_input_popup_surface_v2::*}, wire::{WlSurfaceId, ZwpInputPopupSurfaceV2Id, zwp_input_popup_surface_v2::*},
}, },
std::{cell::Cell, rc::Rc}, std::{cell::Cell, rc::Rc},
@ -27,6 +28,10 @@ pub struct ZwpInputPopupSurfaceV2 {
} }
impl SurfaceExt for ZwpInputPopupSurfaceV2 { impl SurfaceExt for ZwpInputPopupSurfaceV2 {
fn node_layer(&self) -> NodeLayerLink {
NodeLayerLink::InputMethod
}
fn after_apply_commit(self: Rc<Self>) { fn after_apply_commit(self: Rc<Self>) {
self.update_visible(); self.update_visible();
if self.surface.visible.get() { if self.surface.visible.get() {

View file

@ -13,14 +13,15 @@ use {
}, },
wl_pointer::PendingScroll, wl_pointer::PendingScroll,
}, },
wl_surface::{WlSurface, tray::TrayItemId}, wl_surface::{WlSurface, tray::TrayItemId, zwlr_layer_surface_v1::ZwlrLayerSurfaceV1},
}, },
keyboard::KeyboardState, keyboard::KeyboardState,
rect::Rect, rect::Rect,
renderer::Renderer, renderer::Renderer,
utils::numcell::NumCell, utils::{linkedlist::NodeRef, numcell::NumCell},
}, },
jay_config::Direction as JayDirection, jay_config::Direction as JayDirection,
linearize::{Linearize, LinearizeExt},
std::{ std::{
fmt::{Debug, Display}, fmt::{Debug, Display},
rc::Rc, rc::Rc,
@ -121,6 +122,84 @@ pub enum NodeLocation {
Output(OutputNodeId), Output(OutputNodeId),
} }
#[derive(Copy, Clone, Linearize, Eq, PartialEq, Debug)]
pub enum NodeLayer {
Display,
Layer0,
Layer1,
Output,
Workspace,
Tiled,
Fullscreen,
Stacked,
Layer2,
Layer3,
StackedAboveLayers,
Lock,
InputMethod,
}
pub enum NodeLayerLink {
Display,
Layer0(#[expect(dead_code)] NodeRef<Rc<ZwlrLayerSurfaceV1>>),
Layer1(#[expect(dead_code)] NodeRef<Rc<ZwlrLayerSurfaceV1>>),
Output,
Workspace,
Tiled,
Fullscreen,
Stacked(#[expect(dead_code)] NodeRef<Rc<dyn StackedNode>>),
Layer2(#[expect(dead_code)] NodeRef<Rc<ZwlrLayerSurfaceV1>>),
Layer3(#[expect(dead_code)] NodeRef<Rc<ZwlrLayerSurfaceV1>>),
StackedAboveLayers(#[expect(dead_code)] NodeRef<Rc<dyn StackedNode>>),
Lock,
InputMethod,
}
impl NodeLayerLink {
#[expect(dead_code)]
pub fn layer(&self) -> NodeLayer {
macro_rules! map {
($($id:ident,)*) => {
match self {
$(
Self::$id { .. } => NodeLayer::$id,
)*
}
};
}
map! {
Display,
Layer0,
Layer1,
Output,
Workspace,
Tiled,
Fullscreen,
Stacked,
Layer2,
Layer3,
StackedAboveLayers,
Lock,
InputMethod,
}
}
}
impl NodeLayer {
#[expect(dead_code)]
pub fn prev(self) -> Self {
if self == NodeLayer::Display {
return NodeLayer::InputMethod;
}
Self::from_linear(self.linearize() - 1).unwrap_or(NodeLayer::InputMethod)
}
#[expect(dead_code)]
pub fn next(self) -> Self {
Self::from_linear(self.linearize() + 1).unwrap_or(NodeLayer::Display)
}
}
pub trait Node: 'static { pub trait Node: 'static {
fn node_id(&self) -> NodeId; fn node_id(&self) -> NodeId;
fn node_seat_state(&self) -> &NodeSeatState; fn node_seat_state(&self) -> &NodeSeatState;
@ -130,6 +209,7 @@ pub trait Node: 'static {
fn node_absolute_position(&self) -> Rect; fn node_absolute_position(&self) -> Rect;
fn node_output(&self) -> Option<Rc<OutputNode>>; fn node_output(&self) -> Option<Rc<OutputNode>>;
fn node_location(&self) -> Option<NodeLocation>; fn node_location(&self) -> Option<NodeLocation>;
fn node_layer(&self) -> NodeLayerLink;
fn node_child_title_changed(self: Rc<Self>, child: &dyn Node, title: &str) { fn node_child_title_changed(self: Rc<Self>, child: &dyn Node, title: &str) {
let _ = child; let _ = child;

View file

@ -18,9 +18,9 @@ use {
text::TextTexture, text::TextTexture,
tree::{ tree::{
ContainingNode, Direction, FindTreeResult, FindTreeUsecase, FloatNode, FoundNode, Node, ContainingNode, Direction, FindTreeResult, FindTreeUsecase, FloatNode, FoundNode, Node,
NodeId, NodeLocation, OutputNode, TddType, TileDragDestination, ToplevelData, NodeId, NodeLayerLink, NodeLocation, OutputNode, TddType, TileDragDestination,
ToplevelNode, ToplevelNodeBase, ToplevelType, WorkspaceNode, default_tile_drag_bounds, ToplevelData, ToplevelNode, ToplevelNodeBase, ToplevelType, WorkspaceNode,
toplevel_set_floating, walker::NodeVisitor, default_tile_drag_bounds, toplevel_set_floating, walker::NodeVisitor,
}, },
utils::{ utils::{
asyncevent::AsyncEvent, asyncevent::AsyncEvent,
@ -1553,6 +1553,10 @@ impl Node for ContainerNode {
Some(self.location.get()) Some(self.location.get())
} }
fn node_layer(&self) -> NodeLayerLink {
self.toplevel_data.node_layer()
}
fn node_child_title_changed(self: Rc<Self>, child: &dyn Node, title: &str) { fn node_child_title_changed(self: Rc<Self>, child: &dyn Node, title: &str) {
if let Some(child) = self.child_nodes.borrow().get(&child.node_id()) { if let Some(child) = self.child_nodes.borrow().get(&child.node_id()) {
self.update_child_title(child, title); self.update_child_title(child, title);

View file

@ -8,9 +8,9 @@ use {
renderer::Renderer, renderer::Renderer,
state::State, state::State,
tree::{ tree::{
FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeLocation, OutputNode, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeLayerLink, NodeLocation,
StackedNode, TileDragDestination, WorkspaceDragDestination, WorkspaceNodeId, OutputNode, StackedNode, TileDragDestination, WorkspaceDragDestination,
walker::NodeVisitor, WorkspaceNodeId, walker::NodeVisitor,
}, },
utils::{copyhashmap::CopyHashMap, linkedlist::LinkedList}, utils::{copyhashmap::CopyHashMap, linkedlist::LinkedList},
}, },
@ -157,6 +157,10 @@ impl Node for DisplayNode {
None None
} }
fn node_layer(&self) -> NodeLayerLink {
NodeLayerLink::Display
}
fn node_find_tree_at( fn node_find_tree_at(
&self, &self,
x: i32, x: i32,

View file

@ -15,8 +15,8 @@ use {
text::TextTexture, text::TextTexture,
tree::{ tree::{
ContainingNode, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, ContainingNode, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId,
NodeLocation, OutputNode, PinnedNode, StackedNode, TileDragDestination, ToplevelNode, NodeLayerLink, NodeLocation, OutputNode, PinnedNode, StackedNode, TileDragDestination,
WorkspaceNode, toplevel_set_floating, walker::NodeVisitor, ToplevelNode, WorkspaceNode, toplevel_set_floating, walker::NodeVisitor,
}, },
utils::{ utils::{
asyncevent::AsyncEvent, clonecell::CloneCell, double_click_state::DoubleClickState, asyncevent::AsyncEvent, clonecell::CloneCell, double_click_state::DoubleClickState,
@ -709,6 +709,13 @@ impl Node for FloatNode {
Some(self.location.get()) Some(self.location.get())
} }
fn node_layer(&self) -> NodeLayerLink {
let Some(l) = self.display_link.borrow().as_ref().map(|l| l.to_ref()) else {
return NodeLayerLink::Display;
};
NodeLayerLink::Stacked(l)
}
fn node_child_title_changed(self: Rc<Self>, _child: &dyn Node, title: &str) { fn node_child_title_changed(self: Rc<Self>, _child: &dyn Node, title: &str) {
self.update_child_title(title); self.update_child_title(title);
} }

View file

@ -43,9 +43,9 @@ use {
state::State, state::State,
text::TextTexture, text::TextTexture,
tree::{ tree::{
Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeLocation, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeLayerLink,
PinnedNode, StackedNode, TddType, TileDragDestination, WorkspaceDragDestination, NodeLocation, PinnedNode, StackedNode, TddType, TileDragDestination,
WorkspaceNode, WorkspaceNodeId, walker::NodeVisitor, WorkspaceDragDestination, WorkspaceNode, WorkspaceNodeId, walker::NodeVisitor,
}, },
utils::{ utils::{
asyncevent::AsyncEvent, bitflags::BitflagsExt, clonecell::CloneCell, asyncevent::AsyncEvent, bitflags::BitflagsExt, clonecell::CloneCell,
@ -1478,6 +1478,10 @@ impl Node for OutputNode {
Some(NodeLocation::Output(self.id)) Some(NodeLocation::Output(self.id))
} }
fn node_layer(&self) -> NodeLayerLink {
NodeLayerLink::Output
}
fn node_do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) { fn node_do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
if self.state.lock.locked.get() { if self.state.lock.locked.get() {
if let Some(lock) = self.lock_surface.get() { if let Some(lock) = self.lock_surface.get() {

View file

@ -11,8 +11,9 @@ use {
text::TextTexture, text::TextTexture,
tree::{ tree::{
ContainerSplit, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, ContainerSplit, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId,
NodeLocation, NodeVisitor, OutputNode, TileDragDestination, ToplevelData, ToplevelNode, NodeLayerLink, NodeLocation, NodeVisitor, OutputNode, TileDragDestination,
ToplevelNodeBase, ToplevelType, WorkspaceNode, default_tile_drag_destination, ToplevelData, ToplevelNode, ToplevelNodeBase, ToplevelType, WorkspaceNode,
default_tile_drag_destination,
}, },
utils::{ utils::{
asyncevent::AsyncEvent, errorfmt::ErrorFmt, on_drop_event::OnDropEvent, asyncevent::AsyncEvent, errorfmt::ErrorFmt, on_drop_event::OnDropEvent,
@ -181,6 +182,10 @@ impl Node for PlaceholderNode {
self.location.get() self.location.get()
} }
fn node_layer(&self) -> NodeLayerLink {
self.toplevel.node_layer()
}
fn node_do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, _direction: Direction) { fn node_do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, _direction: Direction) {
seat.focus_toplevel(self.clone()); seat.focus_toplevel(self.clone());
} }

View file

@ -28,7 +28,7 @@ use {
state::State, state::State,
tree::{ tree::{
ContainerNode, ContainerSplit, ContainingNode, Direction, FloatNode, Node, NodeId, ContainerNode, ContainerSplit, ContainingNode, Direction, FloatNode, Node, NodeId,
OutputNode, PlaceholderNode, WorkspaceNode, NodeLayerLink, OutputNode, PlaceholderNode, WorkspaceNode,
}, },
utils::{ utils::{
array_to_tuple::ArrayToTuple, array_to_tuple::ArrayToTuple,
@ -902,6 +902,16 @@ impl ToplevelData {
parent.cnode_make_visible(slf); parent.cnode_make_visible(slf);
} }
} }
pub fn node_layer(&self) -> NodeLayerLink {
if self.self_or_ancestor_is_fullscreen.get() {
return NodeLayerLink::Fullscreen;
}
if let Some(float) = self.float.get() {
return float.node_layer();
}
NodeLayerLink::Tiled
}
} }
impl Drop for ToplevelData { impl Drop for ToplevelData {

View file

@ -21,8 +21,9 @@ use {
text::TextTexture, text::TextTexture,
tree::{ tree::{
ContainingNode, Direction, FindTreeResult, FindTreeUsecase, FloatNode, FoundNode, Node, ContainingNode, Direction, FindTreeResult, FindTreeUsecase, FloatNode, FoundNode, Node,
NodeId, NodeLocation, NodeVisitorBase, OutputNode, OutputNodeId, PlaceholderNode, NodeId, NodeLayerLink, NodeLocation, NodeVisitorBase, OutputNode, OutputNodeId,
StackedNode, ToplevelNode, container::ContainerNode, walker::NodeVisitor, PlaceholderNode, StackedNode, ToplevelNode, container::ContainerNode,
walker::NodeVisitor,
}, },
utils::{ utils::{
clonecell::CloneCell, clonecell::CloneCell,
@ -321,6 +322,10 @@ impl Node for WorkspaceNode {
Some(self.location()) Some(self.location())
} }
fn node_layer(&self) -> NodeLayerLink {
NodeLayerLink::Workspace
}
fn node_do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) { fn node_do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
if let Some(fs) = self.fullscreen.get() { if let Some(fs) = self.fullscreen.get() {
fs.node_do_focus(seat, direction); fs.node_do_focus(seat, direction);