layer-shell: implement popups
This commit is contained in:
parent
c6ef63a85f
commit
52afd94f6e
9 changed files with 225 additions and 57 deletions
|
|
@ -1,5 +1,7 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- Needs jay-compositor release.
|
||||||
|
|
||||||
# 1.2.0
|
# 1.2.0
|
||||||
|
|
||||||
- Needs jay-config release.
|
- Needs jay-config release.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- Add remaining layer-shell features.
|
||||||
|
|
||||||
# 1.2.0 (2024-05-05)
|
# 1.2.0 (2024-05-05)
|
||||||
|
|
||||||
- Add support for wp-security-manager-v1.
|
- Add support for wp-security-manager-v1.
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ use {
|
||||||
wl_registry::WlRegistry,
|
wl_registry::WlRegistry,
|
||||||
wl_seat::{tablet::zwp_tablet_tool_v2::ZwpTabletToolV2, wl_pointer::WlPointer, WlSeat},
|
wl_seat::{tablet::zwp_tablet_tool_v2::ZwpTabletToolV2, wl_pointer::WlPointer, WlSeat},
|
||||||
wl_surface::{
|
wl_surface::{
|
||||||
xdg_surface::{xdg_toplevel::XdgToplevel, XdgSurface},
|
xdg_surface::{xdg_popup::XdgPopup, xdg_toplevel::XdgToplevel, XdgSurface},
|
||||||
WlSurface,
|
WlSurface,
|
||||||
},
|
},
|
||||||
wp_drm_lease_connector_v1::WpDrmLeaseConnectorV1,
|
wp_drm_lease_connector_v1::WpDrmLeaseConnectorV1,
|
||||||
|
|
@ -33,8 +33,8 @@ use {
|
||||||
wire::{
|
wire::{
|
||||||
JayOutputId, JayScreencastId, JayToplevelId, JayWorkspaceId, WlBufferId,
|
JayOutputId, JayScreencastId, JayToplevelId, JayWorkspaceId, WlBufferId,
|
||||||
WlDataSourceId, WlOutputId, WlPointerId, WlRegionId, WlRegistryId, WlSeatId,
|
WlDataSourceId, WlOutputId, WlPointerId, WlRegionId, WlRegistryId, WlSeatId,
|
||||||
WlSurfaceId, WpDrmLeaseConnectorV1Id, WpLinuxDrmSyncobjTimelineV1Id, XdgPositionerId,
|
WlSurfaceId, WpDrmLeaseConnectorV1Id, WpLinuxDrmSyncobjTimelineV1Id, XdgPopupId,
|
||||||
XdgSurfaceId, XdgToplevelId, XdgWmBaseId, ZwlrDataControlSourceV1Id,
|
XdgPositionerId, XdgSurfaceId, XdgToplevelId, XdgWmBaseId, ZwlrDataControlSourceV1Id,
|
||||||
ZwpPrimarySelectionSourceV1Id, ZwpTabletToolV2Id,
|
ZwpPrimarySelectionSourceV1Id, ZwpTabletToolV2Id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -66,6 +66,7 @@ pub struct Objects {
|
||||||
pub jay_toplevels: CopyHashMap<JayToplevelId, Rc<JayToplevel>>,
|
pub jay_toplevels: CopyHashMap<JayToplevelId, Rc<JayToplevel>>,
|
||||||
pub drm_lease_outputs: CopyHashMap<WpDrmLeaseConnectorV1Id, Rc<WpDrmLeaseConnectorV1>>,
|
pub drm_lease_outputs: CopyHashMap<WpDrmLeaseConnectorV1Id, Rc<WpDrmLeaseConnectorV1>>,
|
||||||
pub tablet_tools: CopyHashMap<ZwpTabletToolV2Id, Rc<ZwpTabletToolV2>>,
|
pub tablet_tools: CopyHashMap<ZwpTabletToolV2Id, Rc<ZwpTabletToolV2>>,
|
||||||
|
pub xdg_popups: CopyHashMap<XdgPopupId, Rc<XdgPopup>>,
|
||||||
ids: RefCell<Vec<usize>>,
|
ids: RefCell<Vec<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,6 +99,7 @@ impl Objects {
|
||||||
jay_toplevels: Default::default(),
|
jay_toplevels: Default::default(),
|
||||||
drm_lease_outputs: Default::default(),
|
drm_lease_outputs: Default::default(),
|
||||||
tablet_tools: Default::default(),
|
tablet_tools: Default::default(),
|
||||||
|
xdg_popups: Default::default(),
|
||||||
ids: RefCell::new(vec![]),
|
ids: RefCell::new(vec![]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -134,6 +136,7 @@ impl Objects {
|
||||||
self.jay_toplevels.clear();
|
self.jay_toplevels.clear();
|
||||||
self.drm_lease_outputs.clear();
|
self.drm_lease_outputs.clear();
|
||||||
self.tablet_tools.clear();
|
self.tablet_tools.clear();
|
||||||
|
self.xdg_popups.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id<T>(&self, client_data: &Client) -> Result<T, ClientError>
|
pub fn id<T>(&self, client_data: &Client) -> Result<T, ClientError>
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,13 @@ use {
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
tree::{FindTreeResult, FoundNode, OutputNode, StackedNode, WorkspaceNode},
|
tree::{FindTreeResult, FoundNode, OutputNode, StackedNode, WorkspaceNode},
|
||||||
utils::{
|
utils::{
|
||||||
clonecell::CloneCell, copyhashmap::CopyHashMap, hash_map_ext::HashMapExt,
|
clonecell::CloneCell,
|
||||||
linkedlist::LinkedNode, numcell::NumCell, option_ext::OptionExt,
|
copyhashmap::CopyHashMap,
|
||||||
|
hash_map_ext::HashMapExt,
|
||||||
|
linkedlist::{LinkedList, LinkedNode},
|
||||||
|
numcell::NumCell,
|
||||||
|
option_ext::OptionExt,
|
||||||
|
rc_eq::rc_eq,
|
||||||
},
|
},
|
||||||
wire::{xdg_surface::*, WlSurfaceId, XdgPopupId, XdgSurfaceId},
|
wire::{xdg_surface::*, WlSurfaceId, XdgPopupId, XdgSurfaceId},
|
||||||
},
|
},
|
||||||
|
|
@ -66,6 +71,7 @@ pub struct XdgSurface {
|
||||||
extents: Cell<Rect>,
|
extents: Cell<Rect>,
|
||||||
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>>>>,
|
||||||
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>,
|
||||||
|
|
@ -111,7 +117,12 @@ impl XdgPopupParent for Popup {
|
||||||
if wl.is_none() {
|
if wl.is_none() {
|
||||||
self.popup.xdg.set_workspace(&ws);
|
self.popup.xdg.set_workspace(&ws);
|
||||||
*wl = Some(ws.stacked.add_last(self.popup.clone()));
|
*wl = Some(ws.stacked.add_last(self.popup.clone()));
|
||||||
*dl = Some(state.root.stacked.add_last(self.popup.clone()));
|
*dl = Some(
|
||||||
|
self.parent
|
||||||
|
.popup_display_stack
|
||||||
|
.get()
|
||||||
|
.add_last(self.popup.clone()),
|
||||||
|
);
|
||||||
state.tree_changed();
|
state.tree_changed();
|
||||||
self.popup.set_visible(self.parent.surface.visible.get());
|
self.popup.set_visible(self.parent.surface.visible.get());
|
||||||
}
|
}
|
||||||
|
|
@ -171,6 +182,7 @@ impl XdgSurface {
|
||||||
extents: Cell::new(Default::default()),
|
extents: Cell::new(Default::default()),
|
||||||
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()),
|
||||||
popups: Default::default(),
|
popups: Default::default(),
|
||||||
workspace: Default::default(),
|
workspace: Default::default(),
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
|
|
@ -272,6 +284,19 @@ impl XdgSurface {
|
||||||
p.xdg_surface.get_or_insert_default_ext()
|
p.xdg_surface.get_or_insert_default_ext()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_popup_stack(&self, stack: &Rc<LinkedList<Rc<dyn StackedNode>>>) {
|
||||||
|
let prev = self.popup_display_stack.set(stack.clone());
|
||||||
|
if rc_eq(&prev, stack) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for popup in self.popups.lock().values() {
|
||||||
|
if let Some(dl) = &*popup.display_link.borrow() {
|
||||||
|
stack.add_last_existing(dl);
|
||||||
|
}
|
||||||
|
popup.popup.xdg.set_popup_stack(stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XdgSurfaceRequestHandler for XdgSurface {
|
impl XdgSurfaceRequestHandler for XdgSurface {
|
||||||
|
|
@ -416,14 +441,17 @@ impl XdgSurface {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restack_popups(&self) {
|
fn restack_popups(&self) {
|
||||||
let state = &self.surface.client.state;
|
if self.popups.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let stack = self.popup_display_stack.get();
|
||||||
for popup in self.popups.lock().values() {
|
for popup in self.popups.lock().values() {
|
||||||
if let Some(dl) = &*popup.display_link.borrow() {
|
if let Some(dl) = &*popup.display_link.borrow() {
|
||||||
state.root.stacked.add_last_existing(dl);
|
stack.add_last_existing(dl);
|
||||||
}
|
}
|
||||||
popup.popup.xdg.restack_popups();
|
popup.popup.xdg.restack_popups();
|
||||||
}
|
}
|
||||||
state.tree_changed();
|
self.surface.client.state.tree_changed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ pub struct XdgPopup {
|
||||||
pub id: XdgPopupId,
|
pub id: XdgPopupId,
|
||||||
node_id: PopupId,
|
node_id: PopupId,
|
||||||
pub xdg: Rc<XdgSurface>,
|
pub xdg: Rc<XdgSurface>,
|
||||||
pub(super) parent: CloneCell<Option<Rc<dyn XdgPopupParent>>>,
|
pub(in super::super) parent: CloneCell<Option<Rc<dyn XdgPopupParent>>>,
|
||||||
relative_position: Cell<Rect>,
|
relative_position: Cell<Rect>,
|
||||||
pos: RefCell<XdgPositioned>,
|
pos: RefCell<XdgPositioned>,
|
||||||
pub tracker: Tracker<Self>,
|
pub tracker: Tracker<Self>,
|
||||||
|
|
@ -273,7 +273,7 @@ impl Object for XdgPopup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
simple_add_obj!(XdgPopup);
|
dedicated_add_obj!(XdgPopup, XdgPopupId, xdg_popups);
|
||||||
|
|
||||||
impl Node for XdgPopup {
|
impl Node for XdgPopup {
|
||||||
fn node_id(&self) -> NodeId {
|
fn node_id(&self) -> NodeId {
|
||||||
|
|
|
||||||
|
|
@ -4,21 +4,32 @@ use {
|
||||||
ifs::{
|
ifs::{
|
||||||
wl_output::OutputGlobalOpt,
|
wl_output::OutputGlobalOpt,
|
||||||
wl_seat::NodeSeatState,
|
wl_seat::NodeSeatState,
|
||||||
wl_surface::{PendingState, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError},
|
wl_surface::{
|
||||||
|
xdg_surface::xdg_popup::{XdgPopup, XdgPopupParent},
|
||||||
|
PendingState, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError,
|
||||||
|
},
|
||||||
zwlr_layer_shell_v1::{ZwlrLayerShellV1, OVERLAY},
|
zwlr_layer_shell_v1::{ZwlrLayerShellV1, OVERLAY},
|
||||||
},
|
},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::Object,
|
object::Object,
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
renderer::Renderer,
|
renderer::Renderer,
|
||||||
tree::{FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeVisitor},
|
tree::{
|
||||||
utils::{
|
FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeVisitor, OutputNode,
|
||||||
bitflags::BitflagsExt, linkedlist::LinkedNode, numcell::NumCell, option_ext::OptionExt,
|
StackedNode,
|
||||||
},
|
},
|
||||||
wire::{zwlr_layer_surface_v1::*, WlSurfaceId, ZwlrLayerSurfaceV1Id},
|
utils::{
|
||||||
|
bitflags::BitflagsExt,
|
||||||
|
copyhashmap::CopyHashMap,
|
||||||
|
hash_map_ext::HashMapExt,
|
||||||
|
linkedlist::{LinkedList, LinkedNode},
|
||||||
|
numcell::NumCell,
|
||||||
|
option_ext::OptionExt,
|
||||||
|
},
|
||||||
|
wire::{zwlr_layer_surface_v1::*, WlSurfaceId, XdgPopupId, ZwlrLayerSurfaceV1Id},
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefMut},
|
cell::{Cell, RefCell, RefMut},
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
},
|
},
|
||||||
|
|
@ -60,6 +71,7 @@ pub struct ZwlrLayerSurfaceV1 {
|
||||||
last_configure: Cell<(i32, i32)>,
|
last_configure: Cell<(i32, i32)>,
|
||||||
exclusive_edge: Cell<Option<u32>>,
|
exclusive_edge: Cell<Option<u32>>,
|
||||||
exclusive_size: Cell<ExclusiveSize>,
|
exclusive_size: Cell<ExclusiveSize>,
|
||||||
|
popups: CopyHashMap<XdgPopupId, Rc<Popup>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
|
||||||
|
|
@ -96,6 +108,13 @@ pub enum ExclusiveZone {
|
||||||
Acquire(i32),
|
Acquire(i32),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Popup {
|
||||||
|
parent: Rc<ZwlrLayerSurfaceV1>,
|
||||||
|
popup: Rc<XdgPopup>,
|
||||||
|
stack: Rc<LinkedList<Rc<dyn StackedNode>>>,
|
||||||
|
stack_link: RefCell<Option<LinkedNode<Rc<dyn StackedNode>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct PendingLayerSurfaceData {
|
pub struct PendingLayerSurfaceData {
|
||||||
size: Option<(i32, i32)>,
|
size: Option<(i32, i32)>,
|
||||||
|
|
@ -158,6 +177,7 @@ impl ZwlrLayerSurfaceV1 {
|
||||||
last_configure: Default::default(),
|
last_configure: Default::default(),
|
||||||
exclusive_edge: Default::default(),
|
exclusive_edge: Default::default(),
|
||||||
exclusive_size: Default::default(),
|
exclusive_size: Default::default(),
|
||||||
|
popups: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -259,7 +279,21 @@ impl ZwlrLayerSurfaceV1RequestHandler for ZwlrLayerSurfaceV1 {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_popup(&self, _req: GetPopup, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn get_popup(&self, req: GetPopup, slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let popup = self.client.lookup(req.popup)?;
|
||||||
|
if popup.parent.is_some() {
|
||||||
|
return Err(ZwlrLayerSurfaceV1Error::PopupHasParent);
|
||||||
|
}
|
||||||
|
let stack = self.client.state.root.stacked_above_layers.clone();
|
||||||
|
popup.xdg.set_popup_stack(&stack);
|
||||||
|
let user = Rc::new(Popup {
|
||||||
|
parent: slf.clone(),
|
||||||
|
popup: popup.clone(),
|
||||||
|
stack,
|
||||||
|
stack_link: Default::default(),
|
||||||
|
});
|
||||||
|
popup.parent.set(Some(user.clone()));
|
||||||
|
self.popups.set(popup.id, user);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -268,6 +302,9 @@ impl ZwlrLayerSurfaceV1RequestHandler for ZwlrLayerSurfaceV1 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
if self.popups.is_not_empty() {
|
||||||
|
return Err(ZwlrLayerSurfaceV1Error::HasPopups);
|
||||||
|
}
|
||||||
self.destroy_node();
|
self.destroy_node();
|
||||||
self.client.remove_obj(self)?;
|
self.client.remove_obj(self)?;
|
||||||
self.surface.unset_ext();
|
self.surface.unset_ext();
|
||||||
|
|
@ -466,10 +503,15 @@ impl ZwlrLayerSurfaceV1 {
|
||||||
let a_rect = Rect::new_sized(x1 + rect.x1(), y1 + rect.y1(), width, height).unwrap();
|
let a_rect = Rect::new_sized(x1 + rect.x1(), y1 + rect.y1(), width, height).unwrap();
|
||||||
let o_rect = a_rect.move_(-opos.x1(), -opos.y1());
|
let o_rect = a_rect.move_(-opos.x1(), -opos.y1());
|
||||||
self.output_extents.set(o_rect);
|
self.output_extents.set(o_rect);
|
||||||
self.pos.set(a_rect);
|
let a_rect_old = self.pos.replace(a_rect);
|
||||||
let abs_x = a_rect.x1() - extents.x1();
|
let abs_x = a_rect.x1() - extents.x1();
|
||||||
let abs_y = a_rect.y1() - extents.y1();
|
let abs_y = a_rect.y1() - extents.y1();
|
||||||
self.surface.set_absolute_position(abs_x, abs_y);
|
self.surface.set_absolute_position(abs_x, abs_y);
|
||||||
|
if a_rect_old != a_rect {
|
||||||
|
for popup in self.popups.lock().values() {
|
||||||
|
popup.popup.update_absolute_position();
|
||||||
|
}
|
||||||
|
}
|
||||||
self.client.state.tree_changed();
|
self.client.state.tree_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -497,6 +539,19 @@ impl ZwlrLayerSurfaceV1 {
|
||||||
node.update_exclusive_zones();
|
node.update_exclusive_zones();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for popup in self.popups.lock().drain_values() {
|
||||||
|
popup.popup.destroy_node();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_visible(&self, visible: bool) {
|
||||||
|
self.surface.set_visible(visible);
|
||||||
|
if !visible {
|
||||||
|
for popup in self.popups.lock().drain_values() {
|
||||||
|
popup.popup.set_visible(false);
|
||||||
|
popup.popup.destroy_node();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -605,6 +660,49 @@ impl Node for ZwlrLayerSurfaceV1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl XdgPopupParent for Popup {
|
||||||
|
fn position(&self) -> Rect {
|
||||||
|
self.parent.pos.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_popup(&self) {
|
||||||
|
self.parent.popups.remove(&self.popup.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output(&self) -> Rc<OutputNode> {
|
||||||
|
self.parent.surface.output.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_workspace_link(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn post_commit(&self) {
|
||||||
|
let mut dl = self.stack_link.borrow_mut();
|
||||||
|
let output = self.output();
|
||||||
|
let surface = &self.popup.xdg.surface;
|
||||||
|
let state = &surface.client.state;
|
||||||
|
if surface.buffer.is_some() {
|
||||||
|
if dl.is_none() {
|
||||||
|
if self.parent.surface.visible.get() {
|
||||||
|
self.popup.xdg.set_output(&output);
|
||||||
|
*dl = Some(self.stack.add_last(self.popup.clone()));
|
||||||
|
state.tree_changed();
|
||||||
|
self.popup.set_visible(self.parent.surface.visible.get());
|
||||||
|
} else {
|
||||||
|
self.popup.destroy_node();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if dl.take().is_some() {
|
||||||
|
drop(dl);
|
||||||
|
self.popup.set_visible(false);
|
||||||
|
self.popup.destroy_node();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object_base! {
|
object_base! {
|
||||||
self = ZwlrLayerSurfaceV1;
|
self = ZwlrLayerSurfaceV1;
|
||||||
version = self.shell.version;
|
version = self.shell.version;
|
||||||
|
|
@ -647,6 +745,10 @@ pub enum ZwlrLayerSurfaceV1Error {
|
||||||
TooManyExclusiveEdges,
|
TooManyExclusiveEdges,
|
||||||
#[error("Exclusive zone not be larger than 65535")]
|
#[error("Exclusive zone not be larger than 65535")]
|
||||||
ExcessiveExclusive,
|
ExcessiveExclusive,
|
||||||
|
#[error("Popup already has a parent")]
|
||||||
|
PopupHasParent,
|
||||||
|
#[error("Surface still has popups")]
|
||||||
|
HasPopups,
|
||||||
}
|
}
|
||||||
efrom!(ZwlrLayerSurfaceV1Error, WlSurfaceError);
|
efrom!(ZwlrLayerSurfaceV1Error, WlSurfaceError);
|
||||||
efrom!(ZwlrLayerSurfaceV1Error, ClientError);
|
efrom!(ZwlrLayerSurfaceV1Error, ClientError);
|
||||||
|
|
|
||||||
|
|
@ -189,18 +189,24 @@ impl Renderer<'_> {
|
||||||
self.render_workspace(&ws, x, y + th + 1);
|
self.render_workspace(&ws, x, y + th + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for stacked in self.state.root.stacked.iter() {
|
macro_rules! render_stacked {
|
||||||
if stacked.node_visible() {
|
($stack:expr) => {
|
||||||
self.base.ops.push(GfxApiOpt::Sync);
|
for stacked in $stack.iter() {
|
||||||
let pos = stacked.node_absolute_position();
|
if stacked.node_visible() {
|
||||||
if pos.intersects(&opos) {
|
self.base.ops.push(GfxApiOpt::Sync);
|
||||||
let (x, y) = opos.translate(pos.x1(), pos.y1());
|
let pos = stacked.node_absolute_position();
|
||||||
stacked.node_render(self, x, y, None);
|
if pos.intersects(&opos) {
|
||||||
|
let (x, y) = opos.translate(pos.x1(), pos.y1());
|
||||||
|
stacked.node_render(self, x, y, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
render_stacked!(self.state.root.stacked);
|
||||||
render_layer!(output.layers[2]);
|
render_layer!(output.layers[2]);
|
||||||
render_layer!(output.layers[3]);
|
render_layer!(output.layers[3]);
|
||||||
|
render_stacked!(self.state.root.stacked_above_layers);
|
||||||
if let Some(ws) = output.workspace.get() {
|
if let Some(ws) = output.workspace.get() {
|
||||||
if ws.render_highlight.get() > 0 {
|
if ws.render_highlight.get() > 0 {
|
||||||
let color = self.state.theme.colors.highlight.get();
|
let color = self.state.theme.colors.highlight.get();
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ pub struct DisplayNode {
|
||||||
pub id: NodeId,
|
pub id: NodeId,
|
||||||
pub extents: Cell<Rect>,
|
pub extents: Cell<Rect>,
|
||||||
pub outputs: CopyHashMap<ConnectorId, Rc<OutputNode>>,
|
pub outputs: CopyHashMap<ConnectorId, Rc<OutputNode>>,
|
||||||
pub stacked: LinkedList<Rc<dyn StackedNode>>,
|
pub stacked: Rc<LinkedList<Rc<dyn StackedNode>>>,
|
||||||
|
pub stacked_above_layers: Rc<LinkedList<Rc<dyn StackedNode>>>,
|
||||||
pub seat_state: NodeSeatState,
|
pub seat_state: NodeSeatState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,6 +32,7 @@ impl DisplayNode {
|
||||||
extents: Default::default(),
|
extents: Default::default(),
|
||||||
outputs: Default::default(),
|
outputs: Default::default(),
|
||||||
stacked: Default::default(),
|
stacked: Default::default(),
|
||||||
|
stacked_above_layers: Default::default(),
|
||||||
seat_state: Default::default(),
|
seat_state: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ use {
|
||||||
time::Time,
|
time::Time,
|
||||||
tree::{
|
tree::{
|
||||||
walker::NodeVisitor, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node,
|
walker::NodeVisitor, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node,
|
||||||
NodeId, WorkspaceNode,
|
NodeId, StackedNode, WorkspaceNode,
|
||||||
},
|
},
|
||||||
utils::{
|
utils::{
|
||||||
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt,
|
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt,
|
||||||
|
|
@ -605,6 +605,46 @@ impl OutputNode {
|
||||||
self.state.tree_changed();
|
self.state.tree_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_stacked_at(
|
||||||
|
&self,
|
||||||
|
stack: &LinkedList<Rc<dyn StackedNode>>,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
tree: &mut Vec<FoundNode>,
|
||||||
|
usecase: FindTreeUsecase,
|
||||||
|
) -> FindTreeResult {
|
||||||
|
if stack.is_empty() {
|
||||||
|
return FindTreeResult::Other;
|
||||||
|
}
|
||||||
|
let (x_abs, y_abs) = self.global.pos.get().translate_inv(x, y);
|
||||||
|
for stacked in stack.rev_iter() {
|
||||||
|
let ext = stacked.node_absolute_position();
|
||||||
|
if !stacked.node_visible() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if stacked.stacked_absolute_position_constrains_input() && !ext.contains(x_abs, y_abs) {
|
||||||
|
// TODO: make constrain always true
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let (x, y) = ext.translate(x_abs, y_abs);
|
||||||
|
let idx = tree.len();
|
||||||
|
tree.push(FoundNode {
|
||||||
|
node: stacked.deref().clone().stacked_into_node(),
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
});
|
||||||
|
match stacked.node_find_tree_at(x, y, tree, usecase) {
|
||||||
|
FindTreeResult::AcceptsInput => {
|
||||||
|
return FindTreeResult::AcceptsInput;
|
||||||
|
}
|
||||||
|
FindTreeResult::Other => {
|
||||||
|
tree.truncate(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FindTreeResult::Other
|
||||||
|
}
|
||||||
|
|
||||||
pub fn find_layer_surface_at(
|
pub fn find_layer_surface_at(
|
||||||
&self,
|
&self,
|
||||||
x: i32,
|
x: i32,
|
||||||
|
|
@ -671,7 +711,7 @@ impl OutputNode {
|
||||||
macro_rules! set_layer_visible {
|
macro_rules! set_layer_visible {
|
||||||
($layer:expr, $visible:expr) => {
|
($layer:expr, $visible:expr) => {
|
||||||
for ls in $layer.iter() {
|
for ls in $layer.iter() {
|
||||||
ls.surface.set_visible($visible);
|
ls.set_visible($visible);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -833,6 +873,13 @@ impl Node for OutputNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
let res =
|
||||||
|
self.find_stacked_at(&self.state.root.stacked_above_layers, x, y, tree, usecase);
|
||||||
|
if res.accepts_input() {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
{
|
{
|
||||||
let res = self.find_layer_surface_at(x, y, &[OVERLAY, TOP], tree, usecase);
|
let res = self.find_layer_surface_at(x, y, &[OVERLAY, TOP], tree, usecase);
|
||||||
if res.accepts_input() {
|
if res.accepts_input() {
|
||||||
|
|
@ -840,33 +887,9 @@ impl Node for OutputNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let (x_abs, y_abs) = self.global.pos.get().translate_inv(x, y);
|
let res = self.find_stacked_at(&self.state.root.stacked, x, y, tree, usecase);
|
||||||
for stacked in self.state.root.stacked.rev_iter() {
|
if res.accepts_input() {
|
||||||
let ext = stacked.node_absolute_position();
|
return res;
|
||||||
if !stacked.node_visible() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if stacked.stacked_absolute_position_constrains_input()
|
|
||||||
&& !ext.contains(x_abs, y_abs)
|
|
||||||
{
|
|
||||||
// TODO: make constrain always true
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let (x, y) = ext.translate(x_abs, y_abs);
|
|
||||||
let idx = tree.len();
|
|
||||||
tree.push(FoundNode {
|
|
||||||
node: stacked.deref().clone().stacked_into_node(),
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
});
|
|
||||||
match stacked.node_find_tree_at(x, y, tree, usecase) {
|
|
||||||
FindTreeResult::AcceptsInput => {
|
|
||||||
return FindTreeResult::AcceptsInput;
|
|
||||||
}
|
|
||||||
FindTreeResult::Other => {
|
|
||||||
tree.truncate(idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut fullscreen = None;
|
let mut fullscreen = None;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue