Merge pull request #197 from mahkoh/jorth/layer-shell
Implement remaining layer shell features
This commit is contained in:
commit
3c61dd5fd4
45 changed files with 857 additions and 402 deletions
|
|
@ -33,7 +33,7 @@ use {
|
|||
object::Version,
|
||||
state::DeviceHandlerData,
|
||||
tree::{Direction, Node, ToplevelNode},
|
||||
utils::{bitflags::BitflagsExt, smallmap::SmallMap},
|
||||
utils::{bitflags::BitflagsExt, hash_map_ext::HashMapExt, smallmap::SmallMap},
|
||||
wire::WlDataOfferId,
|
||||
xkbcommon::{KeyboardState, XkbState, XKB_KEY_DOWN, XKB_KEY_UP},
|
||||
},
|
||||
|
|
@ -237,7 +237,7 @@ impl WlSeatGlobal {
|
|||
| InputEvent::TabletPadStrip { time_usec, .. } => {
|
||||
self.last_input_usec.set(time_usec);
|
||||
if self.idle_notifications.is_not_empty() {
|
||||
for (_, notification) in self.idle_notifications.lock().drain() {
|
||||
for notification in self.idle_notifications.lock().drain_values() {
|
||||
notification.resume.trigger();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,10 @@ use {
|
|||
object::Version,
|
||||
time::now_usec,
|
||||
tree::{FoundNode, Node},
|
||||
utils::{bindings::PerClientBindings, clonecell::CloneCell, copyhashmap::CopyHashMap},
|
||||
utils::{
|
||||
bindings::PerClientBindings, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
||||
hash_map_ext::HashMapExt,
|
||||
},
|
||||
},
|
||||
std::{
|
||||
cell::{Cell, RefCell},
|
||||
|
|
@ -293,18 +296,18 @@ impl WlSeatGlobal {
|
|||
|
||||
pub fn tablet_clear(&self) {
|
||||
self.tablet.seats.clear();
|
||||
for (_, tablet) in self.tablet.tablets.lock().drain() {
|
||||
for tablet in self.tablet.tablets.lock().drain_values() {
|
||||
tablet.pads.clear();
|
||||
tablet.bindings.clear();
|
||||
tablet.tools.clear();
|
||||
}
|
||||
for (_, tool) in self.tablet.tools.lock().drain() {
|
||||
for tool in self.tablet.tools.lock().drain_values() {
|
||||
tool.cursor.detach();
|
||||
tool.opt.tool.take();
|
||||
tool.tool_owner.destroy(&tool);
|
||||
tool.bindings.clear();
|
||||
}
|
||||
for (_, pad) in self.tablet.pads.lock().drain() {
|
||||
for pad in self.tablet.pads.lock().drain_values() {
|
||||
pad.pad_owner.destroy(&pad);
|
||||
pad.tablet.take();
|
||||
pad.bindings.clear();
|
||||
|
|
@ -324,14 +327,14 @@ impl WlSeatGlobal {
|
|||
let Some(tablet) = self.tablet.tablets.remove(&id) else {
|
||||
return;
|
||||
};
|
||||
for (_, tool) in tablet.tools.lock().drain() {
|
||||
for tool in tablet.tools.lock().drain_values() {
|
||||
self.tablet_handle_remove_tool(now_usec(), tool.id);
|
||||
}
|
||||
for (_, pad) in tablet.pads.lock().drain() {
|
||||
for pad in tablet.pads.lock().drain_values() {
|
||||
pad.pad_owner.destroy(&pad);
|
||||
pad.tablet.take();
|
||||
}
|
||||
for (_, binding) in tablet.bindings.lock().drain() {
|
||||
for binding in tablet.bindings.lock().drain_values() {
|
||||
binding.send_removed();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use {
|
|||
wl_surface::WlSurface,
|
||||
},
|
||||
time::{now_usec, usec_to_msec},
|
||||
utils::clonecell::CloneCell,
|
||||
utils::{clonecell::CloneCell, hash_map_ext::HashMapExt},
|
||||
},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
};
|
||||
|
|
@ -76,7 +76,7 @@ impl WlSeatGlobal {
|
|||
if let Some(tablet) = pad.tablet.take() {
|
||||
tablet.pads.remove(&pad.id);
|
||||
}
|
||||
for (_, binding) in pad.bindings.lock().drain() {
|
||||
for binding in pad.bindings.lock().drain_values() {
|
||||
binding.send_removed();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use {
|
|||
},
|
||||
rect::Rect,
|
||||
time::usec_to_msec,
|
||||
utils::clonecell::CloneCell,
|
||||
utils::{clonecell::CloneCell, hash_map_ext::HashMapExt},
|
||||
},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
};
|
||||
|
|
@ -31,7 +31,7 @@ impl WlSeatGlobal {
|
|||
tool.opt.tool.take();
|
||||
tool.cursor.detach();
|
||||
tool.tool_owner.destroy(&tool);
|
||||
for (_, binding) in tool.bindings.lock().drain() {
|
||||
for binding in tool.bindings.lock().drain_values() {
|
||||
binding.send_removed();
|
||||
}
|
||||
tool.tablet.tools.remove(&id);
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ pub struct WlPointer {
|
|||
id: WlPointerId,
|
||||
pub seat: Rc<WlSeat>,
|
||||
pub tracker: Tracker<Self>,
|
||||
last_motion: Cell<(Fixed, Fixed)>,
|
||||
}
|
||||
|
||||
impl WlPointer {
|
||||
|
|
@ -82,10 +83,12 @@ impl WlPointer {
|
|||
id,
|
||||
seat: seat.clone(),
|
||||
tracker: Default::default(),
|
||||
last_motion: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_enter(&self, serial: u32, surface: WlSurfaceId, x: Fixed, y: Fixed) {
|
||||
self.last_motion.set((x, y));
|
||||
self.seat.client.event(Enter {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
|
|
@ -104,6 +107,9 @@ impl WlPointer {
|
|||
}
|
||||
|
||||
pub fn send_motion(&self, time: u32, x: Fixed, y: Fixed) {
|
||||
if self.last_motion.replace((x, y)) == (x, y) {
|
||||
return;
|
||||
}
|
||||
self.seat.client.event(Motion {
|
||||
self_id: self.id,
|
||||
time,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use {
|
|||
utils::{
|
||||
clonecell::CloneCell,
|
||||
copyhashmap::CopyHashMap,
|
||||
hash_map_ext::HashMapExt,
|
||||
linkedlist::{LinkedList, LinkedNode, NodeRef},
|
||||
numcell::NumCell,
|
||||
},
|
||||
|
|
@ -102,7 +103,7 @@ impl CommitTimelines {
|
|||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
for (_, list) in self.gc.lock().drain() {
|
||||
for list in self.gc.lock().drain_values() {
|
||||
break_loops(&list);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use {
|
|||
ifs::{
|
||||
wl_surface::{
|
||||
xdg_surface::{
|
||||
xdg_popup::{XdgPopup, XdgPopupError},
|
||||
xdg_popup::{XdgPopup, XdgPopupError, XdgPopupParent},
|
||||
xdg_toplevel::{XdgToplevel, WM_CAPABILITIES_SINCE},
|
||||
},
|
||||
PendingState, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError,
|
||||
|
|
@ -17,14 +17,20 @@ use {
|
|||
leaks::Tracker,
|
||||
object::Object,
|
||||
rect::Rect,
|
||||
tree::{FindTreeResult, FoundNode, OutputNode, WorkspaceNode},
|
||||
tree::{FindTreeResult, FoundNode, OutputNode, StackedNode, WorkspaceNode},
|
||||
utils::{
|
||||
clonecell::CloneCell, copyhashmap::CopyHashMap, numcell::NumCell, option_ext::OptionExt,
|
||||
clonecell::CloneCell,
|
||||
copyhashmap::CopyHashMap,
|
||||
hash_map_ext::HashMapExt,
|
||||
linkedlist::{LinkedList, LinkedNode},
|
||||
numcell::NumCell,
|
||||
option_ext::OptionExt,
|
||||
rc_eq::rc_eq,
|
||||
},
|
||||
wire::{xdg_surface::*, WlSurfaceId, XdgPopupId, XdgSurfaceId},
|
||||
},
|
||||
std::{
|
||||
cell::{Cell, RefMut},
|
||||
cell::{Cell, RefCell, RefMut},
|
||||
fmt::Debug,
|
||||
rc::Rc,
|
||||
},
|
||||
|
|
@ -65,11 +71,72 @@ pub struct XdgSurface {
|
|||
extents: Cell<Rect>,
|
||||
pub absolute_desired_extents: Cell<Rect>,
|
||||
ext: CloneCell<Option<Rc<dyn XdgSurfaceExt>>>,
|
||||
popups: CopyHashMap<XdgPopupId, Rc<XdgPopup>>,
|
||||
popup_display_stack: CloneCell<Rc<LinkedList<Rc<dyn StackedNode>>>>,
|
||||
popups: CopyHashMap<XdgPopupId, Rc<Popup>>,
|
||||
pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
|
||||
pub tracker: Tracker<Self>,
|
||||
}
|
||||
|
||||
struct Popup {
|
||||
parent: Rc<XdgSurface>,
|
||||
popup: Rc<XdgPopup>,
|
||||
display_link: RefCell<Option<LinkedNode<Rc<dyn StackedNode>>>>,
|
||||
workspace_link: RefCell<Option<LinkedNode<Rc<dyn StackedNode>>>>,
|
||||
}
|
||||
|
||||
impl XdgPopupParent for Popup {
|
||||
fn position(&self) -> Rect {
|
||||
self.parent.absolute_desired_extents.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 {
|
||||
self.workspace_link.borrow().is_some()
|
||||
}
|
||||
|
||||
fn post_commit(&self) {
|
||||
let mut wl = self.workspace_link.borrow_mut();
|
||||
let mut dl = self.display_link.borrow_mut();
|
||||
let ws = match self.parent.workspace.get() {
|
||||
Some(ws) => ws,
|
||||
_ => {
|
||||
log::info!("no ws");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let surface = &self.popup.xdg.surface;
|
||||
let state = &surface.client.state;
|
||||
if surface.buffer.is_some() {
|
||||
if wl.is_none() {
|
||||
self.popup.xdg.set_workspace(&ws);
|
||||
*wl = Some(ws.stacked.add_last(self.popup.clone()));
|
||||
*dl = Some(
|
||||
self.parent
|
||||
.popup_display_stack
|
||||
.get()
|
||||
.add_last(self.popup.clone()),
|
||||
);
|
||||
state.tree_changed();
|
||||
self.popup.set_visible(self.parent.surface.visible.get());
|
||||
}
|
||||
} else {
|
||||
if wl.take().is_some() {
|
||||
drop(wl);
|
||||
drop(dl);
|
||||
self.popup.set_visible(false);
|
||||
self.popup.destroy_node();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct PendingXdgSurfaceData {
|
||||
geometry: Option<Rect>,
|
||||
|
|
@ -115,6 +182,7 @@ impl XdgSurface {
|
|||
extents: Cell::new(Default::default()),
|
||||
absolute_desired_extents: Cell::new(Default::default()),
|
||||
ext: Default::default(),
|
||||
popup_display_stack: CloneCell::new(surface.client.state.root.stacked.clone()),
|
||||
popups: Default::default(),
|
||||
workspace: Default::default(),
|
||||
tracker: Default::default(),
|
||||
|
|
@ -139,7 +207,7 @@ impl XdgSurface {
|
|||
self.surface.set_output(&ws.output.get());
|
||||
let pu = self.popups.lock();
|
||||
for pu in pu.values() {
|
||||
pu.xdg.set_workspace(ws);
|
||||
pu.popup.xdg.set_workspace(ws);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -147,7 +215,7 @@ impl XdgSurface {
|
|||
self.surface.set_output(output);
|
||||
let pu = self.popups.lock();
|
||||
for pu in pu.values() {
|
||||
pu.xdg.set_output(output);
|
||||
pu.popup.xdg.set_output(output);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -171,9 +239,8 @@ impl XdgSurface {
|
|||
fn destroy_node(&self) {
|
||||
self.workspace.set(None);
|
||||
self.surface.destroy_node();
|
||||
let popups = self.popups.lock();
|
||||
for popup in popups.values() {
|
||||
popup.destroy_node();
|
||||
for popup in self.popups.lock().drain_values() {
|
||||
popup.popup.destroy_node();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -182,7 +249,8 @@ impl XdgSurface {
|
|||
self.surface.detach_node(false);
|
||||
let popups = self.popups.lock();
|
||||
for popup in popups.values() {
|
||||
popup.detach_node();
|
||||
let _v = popup.workspace_link.borrow_mut().take();
|
||||
popup.popup.detach_node();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -216,6 +284,19 @@ impl XdgSurface {
|
|||
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 {
|
||||
|
|
@ -279,11 +360,18 @@ impl XdgSurfaceRequestHandler for XdgSurface {
|
|||
);
|
||||
return Err(XdgSurfaceError::AlreadyConstructed);
|
||||
}
|
||||
let popup = Rc::new(XdgPopup::new(req.id, slf, parent.as_ref(), &positioner)?);
|
||||
let popup = Rc::new(XdgPopup::new(req.id, slf, &positioner)?);
|
||||
track!(self.surface.client, popup);
|
||||
self.surface.client.add_client_obj(&popup)?;
|
||||
if let Some(parent) = &parent {
|
||||
parent.popups.set(req.id, popup.clone());
|
||||
let user = Rc::new(Popup {
|
||||
parent: parent.clone(),
|
||||
popup: popup.clone(),
|
||||
display_link: Default::default(),
|
||||
workspace_link: Default::default(),
|
||||
});
|
||||
popup.parent.set(Some(user.clone()));
|
||||
parent.popups.set(req.id, user);
|
||||
}
|
||||
self.ext.set(Some(popup));
|
||||
Ok(())
|
||||
|
|
@ -341,21 +429,29 @@ impl XdgSurface {
|
|||
fn update_popup_positions(&self) {
|
||||
let popups = self.popups.lock();
|
||||
for popup in popups.values() {
|
||||
popup.update_absolute_position();
|
||||
popup.popup.update_absolute_position();
|
||||
}
|
||||
}
|
||||
|
||||
fn set_visible(&self, visible: bool) {
|
||||
self.surface.set_visible(visible);
|
||||
for popup in self.popups.lock().values() {
|
||||
popup.set_visible(visible);
|
||||
popup.popup.set_visible(visible);
|
||||
}
|
||||
}
|
||||
|
||||
fn restack_popups(&self) {
|
||||
for popup in self.popups.lock().values() {
|
||||
popup.restack();
|
||||
if self.popups.is_empty() {
|
||||
return;
|
||||
}
|
||||
let stack = self.popup_display_stack.get();
|
||||
for popup in self.popups.lock().values() {
|
||||
if let Some(dl) = &*popup.display_link.borrow() {
|
||||
stack.add_last_existing(dl);
|
||||
}
|
||||
popup.popup.xdg.restack_popups();
|
||||
}
|
||||
self.surface.client.state.tree_changed();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@ use {
|
|||
rect::Rect,
|
||||
renderer::Renderer,
|
||||
tree::{
|
||||
FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeVisitor, StackedNode,
|
||||
WorkspaceNode,
|
||||
FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeVisitor, OutputNode,
|
||||
StackedNode,
|
||||
},
|
||||
utils::{clonecell::CloneCell, linkedlist::LinkedNode},
|
||||
utils::clonecell::CloneCell,
|
||||
wire::{xdg_popup::*, XdgPopupId},
|
||||
},
|
||||
std::{
|
||||
|
|
@ -35,14 +35,20 @@ const INVALID_GRAB: u32 = 1;
|
|||
|
||||
tree_id!(PopupId);
|
||||
|
||||
pub trait XdgPopupParent {
|
||||
fn position(&self) -> Rect;
|
||||
fn remove_popup(&self);
|
||||
fn output(&self) -> Rc<OutputNode>;
|
||||
fn has_workspace_link(&self) -> bool;
|
||||
fn post_commit(&self);
|
||||
}
|
||||
|
||||
pub struct XdgPopup {
|
||||
id: XdgPopupId,
|
||||
pub id: XdgPopupId,
|
||||
node_id: PopupId,
|
||||
pub xdg: Rc<XdgSurface>,
|
||||
pub(super) parent: CloneCell<Option<Rc<XdgSurface>>>,
|
||||
pub(in super::super) parent: CloneCell<Option<Rc<dyn XdgPopupParent>>>,
|
||||
relative_position: Cell<Rect>,
|
||||
display_link: RefCell<Option<LinkedNode<Rc<dyn StackedNode>>>>,
|
||||
workspace_link: RefCell<Option<LinkedNode<Rc<dyn StackedNode>>>>,
|
||||
pos: RefCell<XdgPositioned>,
|
||||
pub tracker: Tracker<Self>,
|
||||
seat_state: NodeSeatState,
|
||||
|
|
@ -59,7 +65,6 @@ impl XdgPopup {
|
|||
pub fn new(
|
||||
id: XdgPopupId,
|
||||
xdg: &Rc<XdgSurface>,
|
||||
parent: Option<&Rc<XdgSurface>>,
|
||||
pos: &Rc<XdgPositioner>,
|
||||
) -> Result<Self, XdgPopupError> {
|
||||
let pos = pos.value();
|
||||
|
|
@ -70,10 +75,8 @@ impl XdgPopup {
|
|||
id,
|
||||
node_id: xdg.surface.client.state.node_ids.next(),
|
||||
xdg: xdg.clone(),
|
||||
parent: CloneCell::new(parent.cloned()),
|
||||
parent: Default::default(),
|
||||
relative_position: Cell::new(Default::default()),
|
||||
display_link: RefCell::new(None),
|
||||
workspace_link: RefCell::new(None),
|
||||
pos: RefCell::new(pos),
|
||||
tracker: Default::default(),
|
||||
seat_state: Default::default(),
|
||||
|
|
@ -105,17 +108,13 @@ impl XdgPopup {
|
|||
.event(PopupDone { self_id: self.id })
|
||||
}
|
||||
|
||||
fn update_position(&self, parent: &XdgSurface) -> Result<(), XdgPopupError> {
|
||||
// let parent = parent.extents.get();
|
||||
fn update_position(&self, parent: &dyn XdgPopupParent) {
|
||||
let positioner = self.pos.borrow_mut();
|
||||
// if !parent.contains_rect(&positioner.ar) {
|
||||
// return Err(XdgPopupError::AnchorRectOutside);
|
||||
// }
|
||||
let parent_abs = parent.absolute_desired_extents.get();
|
||||
let parent_abs = parent.position();
|
||||
let mut rel_pos = positioner.get_position(false, false);
|
||||
let mut abs_pos = rel_pos.move_(parent_abs.x1(), parent_abs.y1());
|
||||
if let Some(ws) = parent.workspace.get() {
|
||||
let output_pos = ws.output.get().global.pos.get();
|
||||
{
|
||||
let output_pos = parent.output().global.pos.get();
|
||||
let mut overflow = output_pos.get_overflow(&abs_pos);
|
||||
if !overflow.is_contained() {
|
||||
let mut flip_x = positioner.ca.contains(CA_FLIP_X) && overflow.x_overflow();
|
||||
|
|
@ -146,17 +145,21 @@ impl XdgPopup {
|
|||
}
|
||||
let (mut dx, mut dy) = (0, 0);
|
||||
if positioner.ca.contains(CA_SLIDE_X) && overflow.x_overflow() {
|
||||
dx = if overflow.left > 0 || overflow.left + overflow.right > 0 {
|
||||
dx = if overflow.left + overflow.right > 0 {
|
||||
parent_abs.x1() - abs_pos.x1()
|
||||
} else if overflow.left > 0 {
|
||||
overflow.left
|
||||
} else {
|
||||
parent_abs.x2() - abs_pos.x2()
|
||||
-overflow.right
|
||||
};
|
||||
}
|
||||
if positioner.ca.contains(CA_SLIDE_Y) && overflow.y_overflow() {
|
||||
dy = if overflow.top > 0 || overflow.top + overflow.bottom > 0 {
|
||||
dy = if overflow.top + overflow.bottom > 0 {
|
||||
parent_abs.y1() - abs_pos.y1()
|
||||
} else if overflow.top > 0 {
|
||||
overflow.top
|
||||
} else {
|
||||
parent_abs.y2() - abs_pos.y2()
|
||||
-overflow.bottom
|
||||
};
|
||||
}
|
||||
if dx != 0 || dy != 0 {
|
||||
|
|
@ -174,32 +177,35 @@ impl XdgPopup {
|
|||
dy2 = -overflow.bottom.max(0);
|
||||
}
|
||||
if dx1 > 0 || dx2 < 0 || dy1 > 0 || dy2 < 0 {
|
||||
abs_pos = Rect::new(
|
||||
let maybe_abs_pos = Rect::new(
|
||||
abs_pos.x1() + dx1,
|
||||
abs_pos.y1() + dy1,
|
||||
abs_pos.x2() + dx2,
|
||||
abs_pos.y2() + dy2,
|
||||
)
|
||||
.unwrap();
|
||||
rel_pos = Rect::new_sized(
|
||||
abs_pos.x1() - parent_abs.x1(),
|
||||
abs_pos.y1() - parent_abs.y1(),
|
||||
abs_pos.width(),
|
||||
abs_pos.height(),
|
||||
)
|
||||
.unwrap();
|
||||
);
|
||||
// If the popup is completely outside the output, this will fail. Just
|
||||
// use its position as is.
|
||||
if let Some(maybe_abs_pos) = maybe_abs_pos {
|
||||
abs_pos = maybe_abs_pos;
|
||||
rel_pos = Rect::new_sized(
|
||||
abs_pos.x1() - parent_abs.x1(),
|
||||
abs_pos.y1() - parent_abs.y1(),
|
||||
abs_pos.width(),
|
||||
abs_pos.height(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.relative_position.set(rel_pos);
|
||||
self.xdg.set_absolute_desired_extents(&abs_pos);
|
||||
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();
|
||||
let parent = parent.position();
|
||||
self.xdg
|
||||
.set_absolute_desired_extents(&rel.move_(parent.x1(), parent.y1()));
|
||||
}
|
||||
|
|
@ -211,15 +217,8 @@ impl XdgPopupRequestHandler for XdgPopup {
|
|||
|
||||
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.destroy_node();
|
||||
{
|
||||
if let Some(parent) = self.parent.take() {
|
||||
parent.popups.remove(&self.id);
|
||||
}
|
||||
}
|
||||
self.xdg.ext.set(None);
|
||||
self.xdg.surface.client.remove_obj(self)?;
|
||||
*self.display_link.borrow_mut() = None;
|
||||
*self.workspace_link.borrow_mut() = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -230,7 +229,7 @@ impl XdgPopupRequestHandler for XdgPopup {
|
|||
fn reposition(&self, req: Reposition, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
*self.pos.borrow_mut() = self.xdg.surface.client.lookup(req.positioner)?.value();
|
||||
if let Some(parent) = self.parent.get() {
|
||||
self.update_position(&parent)?;
|
||||
self.update_position(&*parent);
|
||||
let rel = self.relative_position.get();
|
||||
self.send_repositioned(req.token);
|
||||
self.send_configure(rel.x1(), rel.y1(), rel.width(), rel.height());
|
||||
|
|
@ -241,10 +240,6 @@ impl XdgPopupRequestHandler for XdgPopup {
|
|||
}
|
||||
|
||||
impl XdgPopup {
|
||||
fn get_parent_workspace(&self) -> Option<Rc<WorkspaceNode>> {
|
||||
self.parent.get()?.workspace.get()
|
||||
}
|
||||
|
||||
pub fn set_visible(&self, visible: bool) {
|
||||
// log::info!("set visible = {}", visible);
|
||||
self.set_visible_prepared.set(false);
|
||||
|
|
@ -253,27 +248,18 @@ impl XdgPopup {
|
|||
}
|
||||
|
||||
pub fn destroy_node(&self) {
|
||||
let _v = self.display_link.borrow_mut().take();
|
||||
let _v = self.workspace_link.borrow_mut().take();
|
||||
self.xdg.destroy_node();
|
||||
self.seat_state.destroy_node(self);
|
||||
if let Some(parent) = self.parent.take() {
|
||||
parent.remove_popup();
|
||||
}
|
||||
self.send_popup_done();
|
||||
}
|
||||
|
||||
pub fn detach_node(&self) {
|
||||
let _v = self.workspace_link.borrow_mut().take();
|
||||
self.xdg.detach_node();
|
||||
self.seat_state.destroy_node(self);
|
||||
}
|
||||
|
||||
pub fn restack(&self) {
|
||||
let state = &self.xdg.surface.client.state;
|
||||
let dl = self.display_link.borrow();
|
||||
if let Some(dl) = &*dl {
|
||||
state.root.stacked.add_last_existing(dl);
|
||||
}
|
||||
self.xdg.restack_popups();
|
||||
state.tree_changed();
|
||||
}
|
||||
}
|
||||
|
||||
object_base! {
|
||||
|
|
@ -284,13 +270,10 @@ object_base! {
|
|||
impl Object for XdgPopup {
|
||||
fn break_loops(&self) {
|
||||
self.destroy_node();
|
||||
self.parent.set(None);
|
||||
*self.display_link.borrow_mut() = None;
|
||||
*self.workspace_link.borrow_mut() = None;
|
||||
}
|
||||
}
|
||||
|
||||
simple_add_obj!(XdgPopup);
|
||||
dedicated_add_obj!(XdgPopup, XdgPopupId, xdg_popups);
|
||||
|
||||
impl Node for XdgPopup {
|
||||
fn node_id(&self) -> NodeId {
|
||||
|
|
@ -374,7 +357,10 @@ impl StackedNode for XdgPopup {
|
|||
}
|
||||
|
||||
fn stacked_has_workspace_link(&self) -> bool {
|
||||
self.workspace_link.borrow().is_some()
|
||||
match self.parent.get() {
|
||||
Some(p) => p.has_workspace_link(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn stacked_absolute_position_constrains_input(&self) -> bool {
|
||||
|
|
@ -385,7 +371,7 @@ impl StackedNode for XdgPopup {
|
|||
impl XdgSurfaceExt for XdgPopup {
|
||||
fn initial_configure(self: Rc<Self>) -> Result<(), XdgSurfaceError> {
|
||||
if let Some(parent) = self.parent.get() {
|
||||
self.update_position(&parent)?;
|
||||
self.update_position(&*parent);
|
||||
let rel = self.relative_position.get();
|
||||
self.send_configure(rel.x1(), rel.y1(), rel.width(), rel.height());
|
||||
}
|
||||
|
|
@ -393,38 +379,8 @@ impl XdgSurfaceExt for XdgPopup {
|
|||
}
|
||||
|
||||
fn post_commit(self: Rc<Self>) {
|
||||
let mut wl = self.workspace_link.borrow_mut();
|
||||
let mut dl = self.display_link.borrow_mut();
|
||||
let ws = match self.get_parent_workspace() {
|
||||
Some(ws) => ws,
|
||||
_ => {
|
||||
log::info!("no ws");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let surface = &self.xdg.surface;
|
||||
let state = &surface.client.state;
|
||||
if surface.buffer.is_some() {
|
||||
if wl.is_none() {
|
||||
self.xdg.set_workspace(&ws);
|
||||
*wl = Some(ws.stacked.add_last(self.clone()));
|
||||
*dl = Some(state.root.stacked.add_last(self.clone()));
|
||||
state.tree_changed();
|
||||
self.set_visible(
|
||||
self.parent
|
||||
.get()
|
||||
.map(|p| p.surface.visible.get())
|
||||
.unwrap_or(false),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if wl.take().is_some() {
|
||||
drop(wl);
|
||||
drop(dl);
|
||||
self.set_visible(false);
|
||||
self.destroy_node();
|
||||
self.send_popup_done();
|
||||
}
|
||||
if let Some(parent) = self.parent.get() {
|
||||
parent.post_commit();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ use {
|
|||
OutputNode, ToplevelData, ToplevelNode, ToplevelNodeBase, ToplevelNodeId,
|
||||
WorkspaceNode,
|
||||
},
|
||||
utils::clonecell::CloneCell,
|
||||
utils::{clonecell::CloneCell, hash_map_ext::HashMapExt},
|
||||
wire::{xdg_toplevel::*, XdgToplevelId},
|
||||
},
|
||||
ahash::{AHashMap, AHashSet},
|
||||
|
|
@ -218,7 +218,7 @@ impl XdgToplevelRequestHandler for XdgToplevel {
|
|||
Some(p) => Some(p.children.borrow_mut()),
|
||||
_ => None,
|
||||
};
|
||||
for (_, child) in children.drain() {
|
||||
for child in children.drain_values() {
|
||||
child.parent.set(parent.clone());
|
||||
if let Some(parent_children) = &mut parent_children {
|
||||
parent_children.insert(child.id, child);
|
||||
|
|
@ -418,7 +418,7 @@ impl XdgToplevel {
|
|||
{
|
||||
let new_parent = self.parent.get();
|
||||
let mut children = self.children.borrow_mut();
|
||||
for (_, child) in children.drain() {
|
||||
for child in children.drain_values() {
|
||||
child.parent.set(new_parent.clone());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,23 +4,32 @@ use {
|
|||
ifs::{
|
||||
wl_output::OutputGlobalOpt,
|
||||
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},
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::Object,
|
||||
rect::Rect,
|
||||
renderer::Renderer,
|
||||
tree::{FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeVisitor},
|
||||
tree::{
|
||||
FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeVisitor, OutputNode,
|
||||
StackedNode,
|
||||
},
|
||||
utils::{
|
||||
bitflags::BitflagsExt, cell_ext::CellExt, linkedlist::LinkedNode, numcell::NumCell,
|
||||
bitflags::BitflagsExt,
|
||||
copyhashmap::CopyHashMap,
|
||||
hash_map_ext::HashMapExt,
|
||||
linkedlist::{LinkedList, LinkedNode},
|
||||
numcell::NumCell,
|
||||
option_ext::OptionExt,
|
||||
},
|
||||
wire::{zwlr_layer_surface_v1::*, WlSurfaceId, ZwlrLayerSurfaceV1Id},
|
||||
wire::{zwlr_layer_surface_v1::*, WlSurfaceId, XdgPopupId, ZwlrLayerSurfaceV1Id},
|
||||
},
|
||||
std::{
|
||||
cell::{Cell, RefMut},
|
||||
mem,
|
||||
cell::{Cell, RefCell, RefMut},
|
||||
ops::Deref,
|
||||
rc::Rc,
|
||||
},
|
||||
|
|
@ -47,30 +56,74 @@ pub struct ZwlrLayerSurfaceV1 {
|
|||
pub output: Rc<OutputGlobalOpt>,
|
||||
pub namespace: String,
|
||||
pub tracker: Tracker<Self>,
|
||||
output_pos: Cell<Rect>,
|
||||
output_extents: Cell<Rect>,
|
||||
pos: Cell<Rect>,
|
||||
mapped: Cell<bool>,
|
||||
layer: Cell<u32>,
|
||||
requested_serial: NumCell<u32>,
|
||||
acked_serial: Cell<Option<u32>>,
|
||||
size: Cell<(i32, i32)>,
|
||||
anchor: Cell<u32>,
|
||||
exclusive_zone: Cell<i32>,
|
||||
exclusive_zone: Cell<ExclusiveZone>,
|
||||
margin: Cell<(i32, i32, i32, i32)>,
|
||||
keyboard_interactivity: Cell<u32>,
|
||||
link: Cell<Option<LinkedNode<Rc<Self>>>>,
|
||||
seat_state: NodeSeatState,
|
||||
last_configure: Cell<(i32, i32)>,
|
||||
exclusive_edge: Cell<Option<u32>>,
|
||||
exclusive_size: Cell<ExclusiveSize>,
|
||||
popups: CopyHashMap<XdgPopupId, Rc<Popup>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
|
||||
pub struct ExclusiveSize {
|
||||
pub top: i32,
|
||||
pub right: i32,
|
||||
pub bottom: i32,
|
||||
pub left: i32,
|
||||
}
|
||||
|
||||
impl ExclusiveSize {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
*self == ExclusiveSize::default()
|
||||
}
|
||||
|
||||
pub fn is_not_empty(&self) -> bool {
|
||||
!self.is_empty()
|
||||
}
|
||||
|
||||
pub fn max(&self, other: &Self) -> Self {
|
||||
Self {
|
||||
top: self.top.max(other.top),
|
||||
right: self.right.max(other.right),
|
||||
bottom: self.bottom.max(other.bottom),
|
||||
left: self.left.max(other.left),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum ExclusiveZone {
|
||||
MoveSelf,
|
||||
FixedSelf,
|
||||
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)]
|
||||
pub struct PendingLayerSurfaceData {
|
||||
size: Option<(i32, i32)>,
|
||||
anchor: Option<u32>,
|
||||
exclusive_zone: Option<i32>,
|
||||
exclusive_zone: Option<ExclusiveZone>,
|
||||
margin: Option<(i32, i32, i32, i32)>,
|
||||
keyboard_interactivity: Option<u32>,
|
||||
layer: Option<u32>,
|
||||
any: bool,
|
||||
exclusive_edge: Option<u32>,
|
||||
}
|
||||
|
||||
impl PendingLayerSurfaceData {
|
||||
|
|
@ -88,7 +141,6 @@ impl PendingLayerSurfaceData {
|
|||
opt!(margin);
|
||||
opt!(keyboard_interactivity);
|
||||
opt!(layer);
|
||||
self.any |= mem::take(&mut next.any);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -110,19 +162,22 @@ impl ZwlrLayerSurfaceV1 {
|
|||
output: output.clone(),
|
||||
namespace: namespace.to_string(),
|
||||
tracker: Default::default(),
|
||||
output_pos: Default::default(),
|
||||
output_extents: Default::default(),
|
||||
pos: Default::default(),
|
||||
mapped: Cell::new(false),
|
||||
layer: Cell::new(layer),
|
||||
requested_serial: Default::default(),
|
||||
acked_serial: Cell::new(None),
|
||||
size: Cell::new((0, 0)),
|
||||
anchor: Cell::new(0),
|
||||
exclusive_zone: Cell::new(0),
|
||||
exclusive_zone: Cell::new(ExclusiveZone::MoveSelf),
|
||||
margin: Cell::new((0, 0, 0, 0)),
|
||||
keyboard_interactivity: Cell::new(0),
|
||||
link: Cell::new(None),
|
||||
seat_state: Default::default(),
|
||||
last_configure: Default::default(),
|
||||
exclusive_edge: Default::default(),
|
||||
exclusive_size: Default::default(),
|
||||
popups: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -167,7 +222,6 @@ impl ZwlrLayerSurfaceV1RequestHandler for ZwlrLayerSurfaceV1 {
|
|||
}
|
||||
let mut pending = self.pending();
|
||||
pending.size = Some((req.width as _, req.height as _));
|
||||
pending.any = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -177,7 +231,6 @@ impl ZwlrLayerSurfaceV1RequestHandler for ZwlrLayerSurfaceV1 {
|
|||
}
|
||||
let mut pending = self.pending();
|
||||
pending.anchor = Some(req.anchor);
|
||||
pending.any = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -187,15 +240,27 @@ impl ZwlrLayerSurfaceV1RequestHandler for ZwlrLayerSurfaceV1 {
|
|||
_slf: &Rc<Self>,
|
||||
) -> Result<(), Self::Error> {
|
||||
let mut pending = self.pending();
|
||||
pending.exclusive_zone = Some(req.zone);
|
||||
pending.any = true;
|
||||
let zone = if req.zone < 0 {
|
||||
ExclusiveZone::FixedSelf
|
||||
} else if req.zone == 0 {
|
||||
ExclusiveZone::MoveSelf
|
||||
} else if req.zone > u16::MAX as i32 {
|
||||
return Err(ZwlrLayerSurfaceV1Error::ExcessiveExclusive);
|
||||
} else {
|
||||
ExclusiveZone::Acquire(req.zone)
|
||||
};
|
||||
pending.exclusive_zone = Some(zone);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_margin(&self, req: SetMargin, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
let mut pending = self.pending();
|
||||
for s in [req.top, req.right, req.bottom, req.left] {
|
||||
if (s as i64).abs() > u16::MAX as i64 {
|
||||
return Err(ZwlrLayerSurfaceV1Error::ExcessiveMargin);
|
||||
}
|
||||
}
|
||||
pending.margin = Some((req.top, req.right, req.bottom, req.left));
|
||||
pending.any = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -211,20 +276,35 @@ impl ZwlrLayerSurfaceV1RequestHandler for ZwlrLayerSurfaceV1 {
|
|||
}
|
||||
let mut pending = self.pending();
|
||||
pending.keyboard_interactivity = Some(req.keyboard_interactivity);
|
||||
pending.any = true;
|
||||
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(())
|
||||
}
|
||||
|
||||
fn ack_configure(&self, req: AckConfigure, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.acked_serial.set(Some(req.serial));
|
||||
fn ack_configure(&self, _req: AckConfigure, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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.client.remove_obj(self)?;
|
||||
self.surface.unset_ext();
|
||||
|
|
@ -237,18 +317,77 @@ impl ZwlrLayerSurfaceV1RequestHandler for ZwlrLayerSurfaceV1 {
|
|||
}
|
||||
let mut pending = self.pending();
|
||||
pending.layer = Some(req.layer);
|
||||
pending.any = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_exclusive_edge(
|
||||
&self,
|
||||
req: SetExclusiveEdge,
|
||||
_slf: &Rc<Self>,
|
||||
) -> Result<(), Self::Error> {
|
||||
if req.edge & !(LEFT | RIGHT | TOP | BOTTOM) != 0 {
|
||||
return Err(ZwlrLayerSurfaceV1Error::UnknownAnchor(req.edge));
|
||||
}
|
||||
if req.edge.count_ones() > 1 {
|
||||
return Err(ZwlrLayerSurfaceV1Error::TooManyExclusiveEdges);
|
||||
}
|
||||
let mut pending = self.pending();
|
||||
if req.edge == 0 {
|
||||
pending.exclusive_edge = None;
|
||||
} else {
|
||||
pending.exclusive_edge = Some(req.edge);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ZwlrLayerSurfaceV1 {
|
||||
fn pre_commit(&self, pending: &mut PendingState) -> Result<(), ZwlrLayerSurfaceV1Error> {
|
||||
let Some(global) = self.output.get() else {
|
||||
return Ok(());
|
||||
pub fn exclusive_size(&self) -> ExclusiveSize {
|
||||
self.exclusive_size.get()
|
||||
}
|
||||
|
||||
fn update_exclusive_size(&self) {
|
||||
let exclusive_edge = {
|
||||
if let Some(ee) = self.exclusive_edge.get() {
|
||||
Some(ee)
|
||||
} else {
|
||||
let anchor = self.anchor.get();
|
||||
let edges = anchor.count_ones();
|
||||
if edges == 1 {
|
||||
Some(anchor)
|
||||
} else if edges == 3 {
|
||||
match (!anchor) & (TOP | BOTTOM | LEFT | RIGHT) {
|
||||
TOP => Some(BOTTOM),
|
||||
BOTTOM => Some(TOP),
|
||||
LEFT => Some(RIGHT),
|
||||
RIGHT => Some(LEFT),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
let mut exclusive_size = ExclusiveSize::default();
|
||||
if let (ExclusiveZone::Acquire(s), Some(edge)) = (self.exclusive_zone.get(), exclusive_edge)
|
||||
{
|
||||
match edge {
|
||||
TOP => exclusive_size.top = s,
|
||||
RIGHT => exclusive_size.right = s,
|
||||
BOTTOM => exclusive_size.bottom = s,
|
||||
LEFT => exclusive_size.left = s,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if self.exclusive_size.replace(exclusive_size) != exclusive_size {
|
||||
if let Some(output) = self.output.node.get() {
|
||||
output.update_exclusive_zones();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pre_commit(&self, pending: &mut PendingState) -> Result<(), ZwlrLayerSurfaceV1Error> {
|
||||
let pending = pending.layer_surface.get_or_insert_default_ext();
|
||||
let mut send_configure = mem::replace(&mut pending.any, false);
|
||||
if let Some(size) = pending.size.take() {
|
||||
self.size.set(size);
|
||||
}
|
||||
|
|
@ -267,84 +406,152 @@ impl ZwlrLayerSurfaceV1 {
|
|||
if let Some(layer) = pending.layer.take() {
|
||||
self.layer.set(layer);
|
||||
}
|
||||
{
|
||||
let (mut width, mut height) = self.size.get();
|
||||
let anchor = self.anchor.get();
|
||||
if width == 0 {
|
||||
if !anchor.contains(LEFT | RIGHT) {
|
||||
return Err(ZwlrLayerSurfaceV1Error::WidthZero);
|
||||
}
|
||||
send_configure = true;
|
||||
width = global.position().width();
|
||||
if let Some(edge) = pending.exclusive_edge.take() {
|
||||
self.exclusive_edge.set(Some(edge));
|
||||
}
|
||||
let anchor = self.anchor.get();
|
||||
let (width, height) = self.size.get();
|
||||
if width == 0 && !anchor.contains(LEFT | RIGHT) {
|
||||
return Err(ZwlrLayerSurfaceV1Error::WidthZero);
|
||||
}
|
||||
if height == 0 && !anchor.contains(TOP | BOTTOM) {
|
||||
return Err(ZwlrLayerSurfaceV1Error::HeightZero);
|
||||
}
|
||||
if let Some(ee) = self.exclusive_edge.get() {
|
||||
if !self.anchor.get().contains(ee) {
|
||||
return Err(ZwlrLayerSurfaceV1Error::ExclusiveEdgeNotAnchored);
|
||||
}
|
||||
if height == 0 {
|
||||
if !anchor.contains(TOP | BOTTOM) {
|
||||
return Err(ZwlrLayerSurfaceV1Error::HeightZero);
|
||||
}
|
||||
send_configure = true;
|
||||
height = global.position().height();
|
||||
}
|
||||
self.size.set((width, height));
|
||||
}
|
||||
if self.acked_serial.is_none() {
|
||||
send_configure = true;
|
||||
}
|
||||
if send_configure {
|
||||
let (width, height) = self.size.get();
|
||||
let serial = self.requested_serial.fetch_add(1) + 1;
|
||||
self.send_configure(serial, width as _, height as _);
|
||||
}
|
||||
self.configure();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn output_position(&self) -> Rect {
|
||||
self.output_pos.get()
|
||||
}
|
||||
|
||||
pub fn position(&self) -> Rect {
|
||||
self.pos.get()
|
||||
}
|
||||
|
||||
pub fn compute_position(&self) {
|
||||
let Some(global) = self.output.get() else {
|
||||
fn configure(&self) {
|
||||
let Some(node) = self.output.node() else {
|
||||
return;
|
||||
};
|
||||
let (width, height) = self.size.get();
|
||||
let (mut width, mut height) = self.size.get();
|
||||
let (mt, mr, mb, ml) = self.margin.get();
|
||||
let (mut available_width, mut available_height) = match self.exclusive_zone.get() {
|
||||
ExclusiveZone::MoveSelf => node.non_exclusive_rect.get().size(),
|
||||
_ => node.global.pos.get().size(),
|
||||
};
|
||||
let anchor = self.anchor.get();
|
||||
if anchor.contains(LEFT) {
|
||||
available_width -= ml;
|
||||
}
|
||||
if anchor.contains(RIGHT) {
|
||||
available_width -= mr;
|
||||
}
|
||||
if anchor.contains(TOP) {
|
||||
available_height -= mt;
|
||||
}
|
||||
if anchor.contains(BOTTOM) {
|
||||
available_height -= mb;
|
||||
}
|
||||
if width == 0 {
|
||||
width = available_width;
|
||||
}
|
||||
width = width.min(available_width).max(1);
|
||||
if height == 0 {
|
||||
height = available_height;
|
||||
}
|
||||
height = height.min(available_height).max(1);
|
||||
let serial = self.requested_serial.fetch_add(1) + 1;
|
||||
if self.last_configure.replace((width, height)) != (width, height) {
|
||||
self.send_configure(serial, width as _, height as _);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn output_extents(&self) -> Rect {
|
||||
self.output_extents.get()
|
||||
}
|
||||
|
||||
fn compute_position(&self) {
|
||||
let Some(output) = self.output.node() else {
|
||||
return;
|
||||
};
|
||||
let extents = self.surface.extents.get();
|
||||
let (width, height) = extents.size();
|
||||
let mut anchor = self.anchor.get();
|
||||
if anchor == 0 {
|
||||
anchor = LEFT | RIGHT | TOP | BOTTOM;
|
||||
}
|
||||
let opos = global.pos.get();
|
||||
let (mt, mr, mb, ml) = self.margin.get();
|
||||
let opos = output.global.pos.get();
|
||||
let rect = match self.exclusive_zone.get() {
|
||||
ExclusiveZone::MoveSelf => output.non_exclusive_rect.get(),
|
||||
_ => opos,
|
||||
};
|
||||
let (owidth, oheight) = rect.size();
|
||||
let mut x1 = 0;
|
||||
let mut y1 = 0;
|
||||
if anchor.contains(LEFT) {
|
||||
if anchor.contains(RIGHT) {
|
||||
x1 += (opos.width() - width) / 2;
|
||||
}
|
||||
if anchor.contains(LEFT | RIGHT) {
|
||||
x1 = (owidth - width - ml - mr) / 2;
|
||||
} else if anchor.contains(LEFT) {
|
||||
x1 = ml;
|
||||
} else if anchor.contains(RIGHT) {
|
||||
x1 += opos.width() - width;
|
||||
x1 = owidth - width - mr;
|
||||
}
|
||||
if anchor.contains(TOP) {
|
||||
if anchor.contains(BOTTOM) {
|
||||
y1 += (opos.height() - height) / 2;
|
||||
}
|
||||
if anchor.contains(TOP | BOTTOM) {
|
||||
y1 = (oheight - height - mt - mb) / 2;
|
||||
} else if anchor.contains(TOP) {
|
||||
y1 = mt;
|
||||
} else if anchor.contains(BOTTOM) {
|
||||
y1 += opos.height() - height;
|
||||
y1 = oheight - height - mb;
|
||||
}
|
||||
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());
|
||||
self.output_extents.set(o_rect);
|
||||
let a_rect_old = self.pos.replace(a_rect);
|
||||
let abs_x = a_rect.x1() - extents.x1();
|
||||
let abs_y = a_rect.y1() - extents.y1();
|
||||
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();
|
||||
}
|
||||
}
|
||||
let o_rect = Rect::new_sized(x1, y1, width, height).unwrap();
|
||||
let a_rect = o_rect.move_(opos.x1(), opos.y1());
|
||||
self.output_pos.set(o_rect);
|
||||
self.pos.set(a_rect);
|
||||
self.surface.set_absolute_position(a_rect.x1(), a_rect.y1());
|
||||
self.client.state.tree_changed();
|
||||
}
|
||||
|
||||
pub fn output_resized(&self) {
|
||||
self.configure();
|
||||
self.compute_position();
|
||||
}
|
||||
|
||||
pub fn exclusive_zones_changed(&self) {
|
||||
if self.exclusive_zone.get() != ExclusiveZone::MoveSelf {
|
||||
return;
|
||||
}
|
||||
self.output_resized();
|
||||
}
|
||||
|
||||
pub fn destroy_node(&self) {
|
||||
self.link.set(None);
|
||||
self.mapped.set(false);
|
||||
self.surface.destroy_node();
|
||||
self.seat_state.destroy_node(self);
|
||||
self.client.state.tree_changed();
|
||||
self.last_configure.take();
|
||||
if self.exclusive_size.take().is_not_empty() {
|
||||
if let Some(node) = self.output.node() {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -367,17 +574,17 @@ impl SurfaceExt for ZwlrLayerSurfaceV1 {
|
|||
if !buffer_is_some {
|
||||
self.destroy_node();
|
||||
} else {
|
||||
let pos = self.pos.get();
|
||||
let (width, height) = self.size.get();
|
||||
if width != pos.width() || height != pos.height() {
|
||||
if self.surface.extents.get().size() != self.pos.get().size() {
|
||||
self.compute_position();
|
||||
}
|
||||
self.update_exclusive_size();
|
||||
}
|
||||
} else if buffer_is_some {
|
||||
let layer = &output.layers[self.layer.get() as usize];
|
||||
self.link.set(Some(layer.add_last(self.clone())));
|
||||
self.mapped.set(true);
|
||||
self.compute_position();
|
||||
self.update_exclusive_size();
|
||||
}
|
||||
if self.mapped.get() != was_mapped {
|
||||
output.update_visible();
|
||||
|
|
@ -444,7 +651,8 @@ impl Node for ZwlrLayerSurfaceV1 {
|
|||
tree: &mut Vec<FoundNode>,
|
||||
_usecase: FindTreeUsecase,
|
||||
) -> FindTreeResult {
|
||||
self.surface.find_tree_at_(x, y, tree)
|
||||
let (dx, dy) = self.surface.extents.get().position();
|
||||
self.surface.find_tree_at_(x + dx, y + dy, tree)
|
||||
}
|
||||
|
||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, _bounds: Option<&Rect>) {
|
||||
|
|
@ -452,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! {
|
||||
self = ZwlrLayerSurfaceV1;
|
||||
version = self.shell.version;
|
||||
|
|
@ -482,10 +733,22 @@ pub enum ZwlrLayerSurfaceV1Error {
|
|||
UnknownLayer(u32),
|
||||
#[error("Surface size must not be larger than 65535x65535")]
|
||||
ExcessiveSize,
|
||||
#[error("Margin must not be larger than 65535")]
|
||||
ExcessiveMargin,
|
||||
#[error("Unknown anchor {0}")]
|
||||
UnknownAnchor(u32),
|
||||
#[error("Unknown keyboard interactivity {0}")]
|
||||
UnknownKi(u32),
|
||||
#[error("Surface is not anchored at exclusive edge")]
|
||||
ExclusiveEdgeNotAnchored,
|
||||
#[error("Request must contain exactly one edge")]
|
||||
TooManyExclusiveEdges,
|
||||
#[error("Exclusive zone not be larger than 65535")]
|
||||
ExcessiveExclusive,
|
||||
#[error("Popup already has a parent")]
|
||||
PopupHasParent,
|
||||
#[error("Surface still has popups")]
|
||||
HasPopups,
|
||||
}
|
||||
efrom!(ZwlrLayerSurfaceV1Error, WlSurfaceError);
|
||||
efrom!(ZwlrLayerSurfaceV1Error, ClientError);
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ impl Global for ZwlrLayerShellV1Global {
|
|||
}
|
||||
|
||||
fn version(&self) -> u32 {
|
||||
4
|
||||
5
|
||||
}
|
||||
|
||||
fn required_caps(&self) -> ClientCaps {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use {
|
|||
ifs::{wl_buffer::WlBuffer, zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1},
|
||||
leaks::Tracker,
|
||||
object::Object,
|
||||
utils::errorfmt::ErrorFmt,
|
||||
utils::{errorfmt::ErrorFmt, hash_map_ext::HashMapExt},
|
||||
video::dmabuf::{DmaBuf, DmaBufPlane, PlaneVec, MAX_PLANES},
|
||||
wire::{zwp_linux_buffer_params_v1::*, WlBufferId, ZwpLinuxBufferParamsV1Id},
|
||||
},
|
||||
|
|
@ -90,7 +90,7 @@ impl ZwpLinuxBufferParamsV1 {
|
|||
modifier,
|
||||
planes: PlaneVec::new(),
|
||||
};
|
||||
let mut planes: Vec<_> = self.planes.borrow_mut().drain().map(|v| v.1).collect();
|
||||
let mut planes: Vec<_> = self.planes.borrow_mut().drain_values().collect();
|
||||
planes.sort_by_key(|a| a.plane_idx);
|
||||
for (i, p) in planes.into_iter().enumerate() {
|
||||
if p.plane_idx as usize != i {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue