1
0
Fork 0
forked from wry/wry

Merge pull request #197 from mahkoh/jorth/layer-shell

Implement remaining layer shell features
This commit is contained in:
mahkoh 2024-05-09 12:14:22 +02:00 committed by GitHub
commit 3c61dd5fd4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
45 changed files with 857 additions and 402 deletions

View file

@ -35,6 +35,7 @@ use {
clonecell::{CloneCell, UnsafeCellCloneSafe},
copyhashmap::CopyHashMap,
errorfmt::ErrorFmt,
hash_map_ext::HashMapExt,
numcell::NumCell,
oserror::OsError,
smallmap::SmallMap,
@ -184,7 +185,7 @@ impl Backend for MetalBackend {
dev.cb.take();
}
}
for (_, dev) in self.device_holder.drm_devices.lock().drain() {
for dev in self.device_holder.drm_devices.lock().drain_values() {
dev.futures.clear();
for crtc in dev.dev.crtcs.values() {
crtc.connector.take();
@ -196,13 +197,13 @@ impl Backend for MetalBackend {
lease.crtcs.clear();
lease.planes.clear();
};
for (_, mut lease) in dev.dev.leases.lock().drain() {
for mut lease in dev.dev.leases.lock().drain_values() {
clear_lease(&mut lease);
}
for (_, mut lease) in dev.dev.leases_to_break.lock().drain() {
for mut lease in dev.dev.leases_to_break.lock().drain_values() {
clear_lease(&mut lease);
}
for (_, connector) in dev.connectors.lock().drain() {
for connector in dev.connectors.lock().drain_values() {
{
let d = &mut *connector.display.borrow_mut();
d.crtcs.clear();

View file

@ -17,7 +17,7 @@ use {
wl_registry::WlRegistry,
wl_seat::{tablet::zwp_tablet_tool_v2::ZwpTabletToolV2, wl_pointer::WlPointer, WlSeat},
wl_surface::{
xdg_surface::{xdg_toplevel::XdgToplevel, XdgSurface},
xdg_surface::{xdg_popup::XdgPopup, xdg_toplevel::XdgToplevel, XdgSurface},
WlSurface,
},
wp_drm_lease_connector_v1::WpDrmLeaseConnectorV1,
@ -33,8 +33,8 @@ use {
wire::{
JayOutputId, JayScreencastId, JayToplevelId, JayWorkspaceId, WlBufferId,
WlDataSourceId, WlOutputId, WlPointerId, WlRegionId, WlRegistryId, WlSeatId,
WlSurfaceId, WpDrmLeaseConnectorV1Id, WpLinuxDrmSyncobjTimelineV1Id, XdgPositionerId,
XdgSurfaceId, XdgToplevelId, XdgWmBaseId, ZwlrDataControlSourceV1Id,
WlSurfaceId, WpDrmLeaseConnectorV1Id, WpLinuxDrmSyncobjTimelineV1Id, XdgPopupId,
XdgPositionerId, XdgSurfaceId, XdgToplevelId, XdgWmBaseId, ZwlrDataControlSourceV1Id,
ZwpPrimarySelectionSourceV1Id, ZwpTabletToolV2Id,
},
},
@ -66,6 +66,7 @@ pub struct Objects {
pub jay_toplevels: CopyHashMap<JayToplevelId, Rc<JayToplevel>>,
pub drm_lease_outputs: CopyHashMap<WpDrmLeaseConnectorV1Id, Rc<WpDrmLeaseConnectorV1>>,
pub tablet_tools: CopyHashMap<ZwpTabletToolV2Id, Rc<ZwpTabletToolV2>>,
pub xdg_popups: CopyHashMap<XdgPopupId, Rc<XdgPopup>>,
ids: RefCell<Vec<usize>>,
}
@ -98,6 +99,7 @@ impl Objects {
jay_toplevels: Default::default(),
drm_lease_outputs: Default::default(),
tablet_tools: Default::default(),
xdg_popups: Default::default(),
ids: RefCell::new(vec![]),
}
}
@ -134,6 +136,7 @@ impl Objects {
self.jay_toplevels.clear();
self.drm_lease_outputs.clear();
self.tablet_tools.clear();
self.xdg_popups.clear();
}
pub fn id<T>(&self, client_data: &Client) -> Result<T, ClientError>

View file

@ -449,6 +449,10 @@ fn create_dummy_output(state: &Rc<State>) {
workspace: Default::default(),
seat_state: Default::default(),
layers: Default::default(),
exclusive_zones: Default::default(),
workspace_rect: Default::default(),
non_exclusive_rect_rel: Default::default(),
non_exclusive_rect: Default::default(),
render_data: Default::default(),
state: state.clone(),
is_dummy: true,

View file

@ -6,8 +6,8 @@ use {
state::State,
tree::OutputNode,
utils::{
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, rc_eq::rc_eq,
transform_ext::TransformExt,
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt,
hash_map_ext::HashMapExt, rc_eq::rc_eq, transform_ext::TransformExt,
},
},
std::{cell::Cell, ops::Deref, rc::Rc},
@ -99,7 +99,7 @@ impl CursorUserGroup {
.set(self.state.dummy_output.get().unwrap());
self.state.remove_cursor_size(self.size.get());
self.state.cursor_user_groups.remove(&self.id);
for (_, user) in self.users.lock().drain() {
for user in self.users.lock().drain_values() {
user.detach();
}
}

View file

@ -4,7 +4,7 @@ use std::{
ops::{Add, AddAssign, Sub, SubAssign},
};
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
#[repr(transparent)]
pub struct Fixed(pub i32);

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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);

View file

@ -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,

View file

@ -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);
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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());
}
}

View file

@ -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);

View file

@ -107,7 +107,7 @@ impl Global for ZwlrLayerShellV1Global {
}
fn version(&self) -> u32 {
4
5
}
fn required_caps(&self) -> ClientCaps {

View file

@ -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 {

View file

@ -15,6 +15,7 @@ use {
bitfield::Bitfield,
buffd::{BufFdIn, BufFdOut, MsgFormatter, MsgParser, OutBuffer, OutBufferSwapchain},
copyhashmap::CopyHashMap,
hash_map_ext::HashMapExt,
stack::Stack,
vec_ext::VecExt,
},
@ -105,7 +106,7 @@ impl TestTransport {
pub fn kill(&self) {
self.outgoing.take();
self.incoming.take();
for (_, object) in self.objects.lock().drain() {
for object in self.objects.lock().drain_values() {
object.on_remove(self);
}
}

View file

@ -43,6 +43,7 @@ mod leaks {
crate::{
client::ClientId,
utils::{
hash_map_ext::HashMapExt,
ptr_ext::{MutPtrExt, PtrExt},
windows::WindowsExt,
},
@ -157,7 +158,7 @@ mod leaks {
if map.is_empty() {
log::info!("No leaks");
}
for (_, mut objs) in map.drain() {
for mut objs in map.drain_values() {
if objs.len() == 0 {
continue;
}

View file

@ -23,6 +23,7 @@ use {
clonecell::CloneCell,
copyhashmap::CopyHashMap,
errorfmt::ErrorFmt,
hash_map_ext::HashMapExt,
numcell::NumCell,
oserror::OsError,
xrd::xrd,
@ -122,7 +123,7 @@ impl PwCon {
}
pub fn kill(&self) {
for (_, obj) in self.objects.lock().drain() {
for obj in self.objects.lock().drain_values() {
obj.break_loops();
}
self.io.shutdown();

View file

@ -8,7 +8,7 @@ use {
},
utils::{
bitflags::BitflagsExt, clonecell::CloneCell, copyhashmap::CopyHashMap,
errorfmt::ErrorFmt, oserror::OsError,
errorfmt::ErrorFmt, hash_map_ext::HashMapExt, oserror::OsError,
},
video::drm::Drm,
wire::{
@ -191,7 +191,7 @@ impl UsrJayRenderCtxOwner for PortalDisplay {
impl UsrConOwner for PortalDisplay {
fn killed(&self) {
log::info!("Removing display {}", self.id);
for (_, sc) in self.screencasts.lock().drain() {
for sc in self.screencasts.lock().drain_values() {
sc.kill();
}
self.windows.clear();

View file

@ -21,6 +21,7 @@ use {
utils::{
clonecell::{CloneCell, UnsafeCellCloneSafe},
copyhashmap::CopyHashMap,
hash_map_ext::HashMapExt,
},
video::dmabuf::{DmaBuf, PlaneVec},
wire::jay_screencast::Ready,
@ -267,7 +268,7 @@ impl ScreencastSession {
ScreencastPhase::Terminated => {}
ScreencastPhase::Selecting(s) => {
s.core.reply.err("Session has been terminated");
for (_, gui) in s.guis.lock().drain() {
for gui in s.guis.lock().drain_values() {
gui.kill(false);
}
}

View file

@ -13,7 +13,7 @@ use {
},
},
theme::Color,
utils::copyhashmap::CopyHashMap,
utils::{copyhashmap::CopyHashMap, hash_map_ext::HashMapExt},
wl_usr::usr_ifs::{
usr_jay_select_toplevel::UsrJaySelectToplevelOwner,
usr_jay_select_workspace::UsrJaySelectWorkspaceOwner, usr_jay_toplevel::UsrJayToplevel,
@ -53,7 +53,7 @@ enum ButtonRole {
impl SelectionGui {
pub fn kill(&self, upwards: bool) {
for (_, surface) in self.surfaces.lock().drain() {
for surface in self.surfaces.lock().drain_values() {
surface.overlay.data.kill(false);
}
if let ScreencastPhase::Selecting(s) = self.screencast_session.phase.get() {
@ -159,7 +159,7 @@ impl ButtonOwner for StaticButton {
ScreencastPhase::Selecting(selecting) => selecting,
_ => return,
};
for (_, gui) in selecting.guis.lock().drain() {
for gui in selecting.guis.lock().drain_values() {
gui.kill(false);
}
let dpy = &self.surface.output.dpy;

View file

@ -13,7 +13,7 @@ use {
theme::Color,
utils::{
asyncevent::AsyncEvent, clonecell::CloneCell, copyhashmap::CopyHashMap,
errorfmt::ErrorFmt, rc_eq::rc_eq,
errorfmt::ErrorFmt, hash_map_ext::HashMapExt, rc_eq::rc_eq,
},
video::gbm::{GbmBo, GBM_BO_USE_RENDERING},
wire::{
@ -671,7 +671,7 @@ impl WindowData {
owner.kill(upwards);
}
self.render_task.take();
for (_, pb) in self.pending_bufs.lock().drain() {
for pb in self.pending_bufs.lock().drain_values() {
pb.params.con.remove_obj(pb.params.deref());
}
for buf in self.bufs.borrow_mut().drain(..) {
@ -689,7 +689,7 @@ impl WindowData {
pub fn allocate_buffers(self: &Rc<Self>) {
{
for (_, buf) in self.pending_bufs.lock().drain() {
for buf in self.pending_bufs.lock().drain_values() {
buf.params.con.remove_obj(buf.params.deref());
}
}

View file

@ -86,6 +86,11 @@ impl Rect {
Self::new(x1, y1, x1 + width, y1 + height)
}
#[track_caller]
pub fn new_sized_unchecked(x1: i32, y1: i32, width: i32, height: i32) -> Self {
Self::new_sized(x1, y1, width, height).unwrap()
}
pub fn union(&self, other: Self) -> Self {
Self {
raw: RectRaw {

View file

@ -103,12 +103,8 @@ impl Renderer<'_> {
macro_rules! render_layer {
($layer:expr) => {
for ls in $layer.iter() {
let pos = ls.position();
self.render_layer_surface(
ls.deref(),
x + pos.x1() - opos.x1(),
y + pos.y1() - opos.y1(),
);
let pos = ls.output_extents();
self.render_layer_surface(ls.deref(), x + pos.x1(), y + pos.y1());
self.base.ops.push(GfxApiOpt::Sync);
}
};
@ -124,10 +120,14 @@ impl Renderer<'_> {
} else {
render_layer!(output.layers[0]);
render_layer!(output.layers[1]);
let non_exclusive_rect = output.non_exclusive_rect_rel.get();
let (x, y) = non_exclusive_rect.translate_inv(x, y);
{
let c = theme.colors.bar_background.get();
self.base.fill_boxes2(
slice::from_ref(&Rect::new_sized(0, 0, opos.width(), th).unwrap()),
slice::from_ref(
&Rect::new_sized(0, 0, non_exclusive_rect.width(), th).unwrap(),
),
&c,
x,
y,
@ -189,18 +189,24 @@ impl Renderer<'_> {
self.render_workspace(&ws, x, y + th + 1);
}
}
for stacked in self.state.root.stacked.iter() {
if stacked.node_visible() {
self.base.ops.push(GfxApiOpt::Sync);
let pos = stacked.node_absolute_position();
if pos.intersects(&opos) {
let (x, y) = opos.translate(pos.x1(), pos.y1());
stacked.node_render(self, x, y, None);
macro_rules! render_stacked {
($stack:expr) => {
for stacked in $stack.iter() {
if stacked.node_visible() {
self.base.ops.push(GfxApiOpt::Sync);
let pos = stacked.node_absolute_position();
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[3]);
render_stacked!(self.state.root.stacked_above_layers);
if let Some(ws) = output.workspace.get() {
if ws.render_highlight.get() > 0 {
let color = self.state.theme.colors.highlight.get();
@ -539,8 +545,7 @@ impl Renderer<'_> {
}
pub fn render_layer_surface(&mut self, surface: &ZwlrLayerSurfaceV1, x: i32, y: i32) {
let body = surface.position().at_point(x, y);
let body = self.base.scale_rect(body);
self.render_surface(&surface.surface, x, y, Some(&body));
let (dx, dy) = surface.surface.extents.get().position();
self.render_surface(&surface.surface, x - dx, y - dy, None);
}
}

View file

@ -3,7 +3,7 @@ use {
async_engine::SpawnedFuture,
client::ClientCaps,
state::State,
utils::{copyhashmap::CopyHashMap, errorfmt::ErrorFmt},
utils::{copyhashmap::CopyHashMap, errorfmt::ErrorFmt, hash_map_ext::HashMapExt},
},
std::{
cell::Cell,
@ -36,7 +36,7 @@ struct Acceptor {
impl SecurityContextAcceptors {
pub fn clear(&self) {
for (_, acceptor) in self.acceptors.lock().drain() {
for acceptor in self.acceptors.lock().drain_values() {
acceptor.kill();
}
}

View file

@ -68,8 +68,8 @@ use {
utils::{
activation_token::ActivationToken, asyncevent::AsyncEvent, bindings::Bindings,
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, fdcloser::FdCloser,
linkedlist::LinkedList, numcell::NumCell, queue::AsyncQueue, refcounted::RefCounted,
run_toplevel::RunToplevel,
hash_map_ext::HashMapExt, linkedlist::LinkedList, numcell::NumCell, queue::AsyncQueue,
refcounted::RefCounted, run_toplevel::RunToplevel,
},
video::{
dmabuf::DmaBufIds,
@ -743,11 +743,11 @@ impl State {
self.xwayland.queue.clear();
self.idle.inhibitors.clear();
self.idle.change.clear();
for (_, drm_dev) in self.drm_devs.lock().drain() {
for drm_dev in self.drm_devs.lock().drain_values() {
drm_dev.handler.take();
drm_dev.connectors.clear();
}
for (_, connector) in self.connectors.lock().drain() {
for connector in self.connectors.lock().drain_values() {
connector.handler.take();
connector.async_event.clear();
}
@ -769,7 +769,7 @@ impl State {
self.toplevel_lists.clear();
self.security_context_acceptors.clear();
self.slow_clients.clear();
for (_, h) in self.input_device_handlers.borrow_mut().drain() {
for h in self.input_device_handlers.borrow_mut().drain_values() {
h.async_event.clear();
}
self.backend_events.clear();

View file

@ -5,7 +5,7 @@ use {
ifs::wl_output::{OutputId, PersistentOutputState, WlOutputGlobal},
state::{ConnectorData, OutputData, State},
tree::{move_ws_to_output, OutputNode, OutputRenderData, WsMoveConfig},
utils::{asyncevent::AsyncEvent, clonecell::CloneCell},
utils::{asyncevent::AsyncEvent, clonecell::CloneCell, hash_map_ext::HashMapExt},
},
std::{
cell::{Cell, RefCell},
@ -147,6 +147,10 @@ impl ConnectorHandler {
seat_state: Default::default(),
global: global.clone(),
layers: Default::default(),
exclusive_zones: Default::default(),
workspace_rect: Default::default(),
non_exclusive_rect: Default::default(),
non_exclusive_rect_rel: Default::default(),
render_data: RefCell::new(OutputRenderData {
active_workspace: None,
underline: Default::default(),
@ -169,6 +173,7 @@ impl ConnectorHandler {
hardware_cursor_needs_render: Cell::new(false),
screencopies: Default::default(),
});
on.update_rects();
self.state
.add_output_scale(on.global.persistent.scale.get());
let output_data = Rc::new(OutputData {
@ -244,14 +249,14 @@ impl ConnectorHandler {
config.connector_disconnected(self.id);
}
global.clear();
for (_, jo) in on.jay_outputs.lock().drain() {
for jo in on.jay_outputs.lock().drain_values() {
jo.send_destroyed();
}
let screencasts: Vec<_> = on.screencasts.lock().values().cloned().collect();
for sc in screencasts {
sc.do_destroy();
}
for (_, sc) in on.screencopies.lock().drain() {
for sc in on.screencopies.lock().drain_values() {
sc.send_failed();
}
global.destroyed.set(true);
@ -310,7 +315,7 @@ impl ConnectorHandler {
}
};
let withdraw = || {
for (_, con) in output_data.lease_connectors.lock().drain() {
for con in output_data.lease_connectors.lock().drain_values() {
con.send_withdrawn();
if !con.device.destroyed.get() {
con.device.send_done();

View file

@ -23,6 +23,7 @@ use {
clonecell::CloneCell,
double_click_state::DoubleClickState,
errorfmt::ErrorFmt,
hash_map_ext::HashMapExt,
linkedlist::{LinkedList, LinkedNode, NodeRef},
numcell::NumCell,
rc_eq::rc_eq,
@ -1613,7 +1614,7 @@ impl ToplevelNodeBase for ContainerNode {
fn tl_destroy_impl(&self) {
mem::take(self.cursors.borrow_mut().deref_mut());
let mut cn = self.child_nodes.borrow_mut();
for (_, n) in cn.drain() {
for n in cn.drain_values() {
n.node.tl_destroy();
}
}

View file

@ -20,7 +20,8 @@ pub struct DisplayNode {
pub id: NodeId,
pub extents: Cell<Rect>,
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,
}
@ -31,6 +32,7 @@ impl DisplayNode {
extents: Default::default(),
outputs: Default::default(),
stacked: Default::default(),
stacked_above_layers: Default::default(),
seat_state: Default::default(),
}
}

View file

@ -18,8 +18,8 @@ use {
},
wl_surface::{
ext_session_lock_surface_v1::ExtSessionLockSurfaceV1,
zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, SurfaceSendPreferredScaleVisitor,
SurfaceSendPreferredTransformVisitor,
zwlr_layer_surface_v1::{ExclusiveSize, ZwlrLayerSurfaceV1},
SurfaceSendPreferredScaleVisitor, SurfaceSendPreferredTransformVisitor,
},
zwlr_layer_shell_v1::{BACKGROUND, BOTTOM, OVERLAY, TOP},
zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1,
@ -32,11 +32,12 @@ use {
time::Time,
tree::{
walker::NodeVisitor, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node,
NodeId, WorkspaceNode,
NodeId, StackedNode, WorkspaceNode,
},
utils::{
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt,
linkedlist::LinkedList, scroller::Scroller, transform_ext::TransformExt,
hash_map_ext::HashMapExt, linkedlist::LinkedList, scroller::Scroller,
transform_ext::TransformExt,
},
wire::{JayOutputId, JayScreencastId, ZwlrScreencopyFrameV1Id},
},
@ -46,7 +47,7 @@ use {
std::{
cell::{Cell, RefCell},
fmt::{Debug, Formatter},
ops::{Deref, Sub},
ops::Deref,
rc::Rc,
},
};
@ -60,6 +61,10 @@ pub struct OutputNode {
pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
pub seat_state: NodeSeatState,
pub layers: [LinkedList<Rc<ZwlrLayerSurfaceV1>>; 4],
pub exclusive_zones: Cell<ExclusiveSize>,
pub workspace_rect: Cell<Rect>,
pub non_exclusive_rect: Cell<Rect>,
pub non_exclusive_rect_rel: Cell<Rect>,
pub render_data: RefCell<OutputRenderData>,
pub state: Rc<State>,
pub is_dummy: bool,
@ -93,6 +98,26 @@ pub async fn output_render_data(state: Rc<State>) {
}
impl OutputNode {
pub fn update_exclusive_zones(self: &Rc<Self>) {
let mut exclusive = ExclusiveSize::default();
for layer in &self.layers {
for surface in layer.iter() {
exclusive = exclusive.max(&surface.exclusive_size());
}
}
if self.exclusive_zones.replace(exclusive) != exclusive {
self.update_rects();
for layer in &self.layers {
for surface in layer.iter() {
surface.exclusive_zones_changed();
}
}
if let Some(c) = self.workspace.get() {
c.change_extents(&self.workspace_rect.get());
}
}
}
pub fn add_screencast(&self, sc: &Rc<JayScreencast>) {
self.screencasts.set((sc.client.id, sc.id), sc.clone());
self.screencast_changed();
@ -140,7 +165,7 @@ impl OutputNode {
return;
}
let now = Time::now().unwrap();
for (_, capture) in self.screencopies.lock().drain() {
for capture in self.screencopies.lock().drain_values() {
let wl_buffer = match capture.buffer.take() {
Some(b) => b,
_ => {
@ -221,9 +246,9 @@ impl OutputNode {
}
pub fn on_spaces_changed(self: &Rc<Self>) {
self.schedule_update_render_data();
self.update_rects();
if let Some(c) = self.workspace.get() {
c.change_extents(&self.workspace_rect());
c.change_extents(&self.workspace_rect.get());
}
}
@ -280,7 +305,7 @@ impl OutputNode {
texture_height = (th as f64 * scale).round() as _;
}
let active_id = self.workspace.get().map(|w| w.id);
let output_width = self.global.pos.get().width();
let output_width = self.non_exclusive_rect.get().width();
rd.underline = Rect::new_sized(0, th, output_width, 1).unwrap();
for ws in self.workspaces.iter() {
let old_tex = ws.title_texture.take();
@ -429,7 +454,7 @@ impl OutputNode {
if let Some(fs) = ws.fullscreen.get() {
fs.tl_change_extents(&self.global.pos.get());
}
ws.change_extents(&self.workspace_rect());
ws.change_extents(&self.workspace_rect.get());
for seat in seats {
ws.clone().node_do_focus(&seat, Direction::Unspecified);
}
@ -477,16 +502,29 @@ impl OutputNode {
ws
}
fn workspace_rect(&self) -> Rect {
pub fn update_rects(self: &Rc<Self>) {
let rect = self.global.pos.get();
let th = self.state.theme.sizes.title_height.get();
Rect::new_sized(
rect.x1(),
rect.y1() + th + 1,
rect.width(),
rect.height().sub(th + 1).max(0),
)
.unwrap()
let exclusive = self.exclusive_zones.get();
let y1 = rect.y1() + exclusive.top;
let x2 = rect.x2() - exclusive.right;
let y2 = rect.y2() - exclusive.bottom;
let x1 = rect.x1() + exclusive.left;
let width = (x2 - x1).max(0);
let height = (y2 - y1).max(0);
self.non_exclusive_rect
.set(Rect::new_sized_unchecked(x1, y1, width, height));
self.non_exclusive_rect_rel.set(Rect::new_sized_unchecked(
exclusive.left,
exclusive.top,
width,
height,
));
let y1 = y1 + th + 1;
let height = (y2 - y1).max(0);
self.workspace_rect
.set(Rect::new_sized_unchecked(x1, y1, width, height));
self.schedule_update_render_data();
}
pub fn set_position(self: &Rc<Self>, x: i32, y: i32) {
@ -545,7 +583,7 @@ impl OutputNode {
self.global.persistent.pos.set((rect.x1(), rect.y1()));
self.global.pos.set(*rect);
self.state.root.update_extents();
self.schedule_update_render_data();
self.update_rects();
if let Some(ls) = self.lock_surface.get() {
ls.change_extents(*rect);
}
@ -553,11 +591,11 @@ impl OutputNode {
if let Some(fs) = c.fullscreen.get() {
fs.tl_change_extents(rect);
}
c.change_extents(&self.workspace_rect());
c.change_extents(&self.workspace_rect.get());
}
for layer in &self.layers {
for surface in layer.iter() {
surface.compute_position();
surface.output_resized();
}
}
self.global.send_mode();
@ -567,6 +605,46 @@ impl OutputNode {
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(
&self,
x: i32,
@ -581,7 +659,7 @@ impl OutputNode {
let len = tree.len();
for layer in layers.iter().copied() {
for surface in self.layers[layer as usize].rev_iter() {
let pos = surface.output_position();
let pos = surface.output_extents();
if pos.contains(x, y) {
let (x, y) = pos.translate(x, y);
if surface.node_find_tree_at(x, y, tree, usecase)
@ -633,7 +711,7 @@ impl OutputNode {
macro_rules! set_layer_visible {
($layer:expr, $visible:expr) => {
for ls in $layer.iter() {
ls.surface.set_visible($visible);
ls.set_visible($visible);
}
};
}
@ -641,7 +719,7 @@ impl OutputNode {
if let Some(ws) = self.workspace.get() {
have_fullscreen = ws.fullscreen.is_some();
}
let lower_visible = visible && have_fullscreen;
let lower_visible = visible && !have_fullscreen;
set_layer_visible!(self.layers[0], lower_visible);
set_layer_visible!(self.layers[1], lower_visible);
if let Some(ws) = self.workspace.get() {
@ -656,6 +734,7 @@ impl OutputNode {
Some(p) => p,
_ => return,
};
let (x, y) = self.non_exclusive_rect_rel.get().translate(x, y);
if y >= self.state.theme.sizes.title_height.get() {
return;
}
@ -794,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);
if res.accepts_input() {
@ -801,33 +887,9 @@ impl Node for OutputNode {
}
}
{
let (x_abs, y_abs) = self.global.pos.get().translate_inv(x, y);
for stacked in self.state.root.stacked.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);
}
}
let res = self.find_stacked_at(&self.state.root.stacked, x, y, tree, usecase);
if res.accepts_input() {
return res;
}
}
let mut fullscreen = None;
@ -842,21 +904,33 @@ impl Node for OutputNode {
});
fs.tl_as_node().node_find_tree_at(x, y, tree, usecase)
} else {
if y >= bar_height {
y -= bar_height;
let len = tree.len();
if let Some(ws) = self.workspace.get() {
tree.push(FoundNode {
node: ws.clone(),
x,
y,
});
ws.node_find_tree_at(x, y, tree, usecase);
}
if tree.len() == len {
self.find_layer_surface_at(x, y, &[BOTTOM, BACKGROUND], tree, usecase);
let mut search_layers = true;
let non_exclusive_rect = self.non_exclusive_rect_rel.get();
if non_exclusive_rect.contains(x, y) {
let (x, y) = non_exclusive_rect.translate(x, y);
if y < bar_height {
search_layers = false;
} else {
if let Some(ws) = self.workspace.get() {
let y = y - bar_height;
let len = tree.len();
tree.push(FoundNode {
node: ws.clone(),
x,
y,
});
match ws.node_find_tree_at(x, y, tree, usecase) {
FindTreeResult::AcceptsInput => search_layers = false,
FindTreeResult::Other => {
tree.truncate(len);
}
}
}
}
}
if search_layers {
self.find_layer_surface_at(x, y, &[BOTTOM, BACKGROUND], tree, usecase);
}
FindTreeResult::AcceptsInput
}
}

View file

@ -15,6 +15,7 @@ use {
utils::{
clonecell::CloneCell,
copyhashmap::CopyHashMap,
hash_map_ext::HashMapExt,
numcell::NumCell,
smallmap::SmallMap,
threshold_counter::ThresholdCounter,
@ -289,16 +290,16 @@ impl ToplevelData {
}
pub fn destroy_node(&self, node: &dyn Node) {
for (_, jay_tl) in self.jay_toplevels.lock().drain() {
for jay_tl in self.jay_toplevels.lock().drain_values() {
jay_tl.destroy();
}
for (_, screencast) in self.jay_screencasts.lock().drain() {
for screencast in self.jay_screencasts.lock().drain_values() {
screencast.do_destroy();
}
self.identifier.set(toplevel_identifier());
{
let mut handles = self.handles.lock();
for (_, handle) in handles.drain() {
for handle in handles.drain_values() {
handle.send_closed();
}
}

View file

@ -264,9 +264,9 @@ impl Node for WorkspaceNode {
x,
y,
});
n.node_find_tree_at(x, y, tree, usecase);
return n.node_find_tree_at(x, y, tree, usecase);
}
FindTreeResult::AcceptsInput
FindTreeResult::Other
}
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, _bounds: Option<&Rect>) {

View file

@ -16,6 +16,7 @@ pub mod double_click_state;
pub mod errorfmt;
pub mod fdcloser;
pub mod gfx_api_ext;
pub mod hash_map_ext;
pub mod hex;
pub mod line_logger;
pub mod linkedlist;

15
src/utils/hash_map_ext.rs Normal file
View file

@ -0,0 +1,15 @@
use std::collections::HashMap;
pub trait HashMapExt {
type V;
fn drain_values(&mut self) -> impl Iterator<Item = Self::V>;
}
impl<K, V, S> HashMapExt for HashMap<K, V, S> {
type V = V;
fn drain_values(&mut self) -> impl Iterator<Item = Self::V> {
self.drain().map(|(_, v)| v)
}
}

View file

@ -5,6 +5,7 @@ use {
clonecell::{CloneCell, UnsafeCellCloneSafe},
copyhashmap::CopyHashMap,
errorfmt::ErrorFmt,
hash_map_ext::HashMapExt,
linkedlist::{LinkedList, LinkedNode},
oserror::OsError,
},
@ -230,7 +231,7 @@ impl Drop for SyncObjCtx {
fn drop(&mut self) {
self.inner.links.clear();
let mut map = self.inner.handles.lock();
for (_, handle) in map.drain() {
for handle in map.drain_values() {
destroy(&self.inner.drm, handle);
}
}

View file

@ -4,7 +4,7 @@ use {
io_uring::IoUring,
utils::{
asyncevent::AsyncEvent, buf::Buf, clonecell::CloneCell, copyhashmap::CopyHashMap,
numcell::NumCell, oserror::OsError, stack::Stack,
hash_map_ext::HashMapExt, numcell::NumCell, oserror::OsError, stack::Stack,
},
video::drm::{
sync_obj::{SyncObj, SyncObjCtx, SyncObjPoint},
@ -89,7 +89,7 @@ impl WaitForSyncObj {
pub fn set_ctx(&self, ctx: Option<Rc<SyncObjCtx>>) {
self.inner.ctx.set(ctx);
let busy_waiters: Vec<_> = self.inner.busy.lock().drain().map(|(_, w)| w).collect();
let busy_waiters: Vec<_> = self.inner.busy.lock().drain_values().collect();
for waiter in busy_waiters {
let res = self.submit_job(
waiter.job.id,

View file

@ -4,8 +4,8 @@ use {
io_uring::{IoUring, IoUringError},
time::{Time, TimeError},
utils::{
buf::TypedBuf, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell,
oserror::OsError, stack::Stack,
buf::TypedBuf, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, hash_map_ext::HashMapExt,
numcell::NumCell, oserror::OsError, stack::Stack,
},
},
std::{
@ -204,7 +204,7 @@ impl WheelData {
self.destroyed.set(true);
self.dispatcher.set(None);
self.cached_futures.take();
for (_, dispatcher) in self.dispatchers.lock().drain() {
for dispatcher in self.dispatchers.lock().drain_values() {
dispatcher.complete(Err(WheelError::Destroyed));
}
}

View file

@ -17,6 +17,7 @@ use {
clonecell::CloneCell,
copyhashmap::CopyHashMap,
errorfmt::ErrorFmt,
hash_map_ext::HashMapExt,
oserror::OsError,
vec_ext::VecExt,
},
@ -159,7 +160,7 @@ impl UsrCon {
pub fn kill(&self) {
self.dead.set(true);
for (_, obj) in self.objects.lock().drain() {
for obj in self.objects.lock().drain_values() {
if let Some(obj) = obj {
obj.break_loops();
}

View file

@ -27,8 +27,8 @@ use {
tree::{Node, ToplevelNode},
utils::{
bitflags::BitflagsExt, buf::Buf, cell_ext::CellExt, clonecell::CloneCell,
copyhashmap::CopyHashMap, errorfmt::ErrorFmt, linkedlist::LinkedList, numcell::NumCell,
oserror::OsError, rc_eq::rc_eq,
copyhashmap::CopyHashMap, errorfmt::ErrorFmt, hash_map_ext::HashMapExt,
linkedlist::LinkedList, numcell::NumCell, oserror::OsError, rc_eq::rc_eq,
},
wire::WlSurfaceId,
wire_xcon::{
@ -171,7 +171,7 @@ struct SelectionData<T: XIpc> {
impl<T: XIpc> SelectionData<T> {
fn destroy(&self) {
for (_, offer) in self.offers.lock().drain() {
for offer in self.offers.lock().drain_values() {
destroy_data_offer::<T>(&offer.offer);
}
self.active_offer.take();
@ -179,7 +179,7 @@ impl<T: XIpc> SelectionData<T> {
}
fn destroy_sources(&self) {
for (_, source) in self.sources.lock().drain() {
for source in self.sources.lock().drain_values() {
destroy_data_source::<T>(&source);
}
}
@ -207,7 +207,7 @@ impl Drop for XwmShared {
fn drop(&mut self) {
self.data.destroy();
self.primary_selection.destroy();
for (_, device) in self.devices.lock().drain() {
for device in self.devices.lock().drain_values() {
destroy_data_device::<XClipboardIpc>(&device);
destroy_data_device::<XPrimarySelectionIpc>(&device);
device.seat.unset_x_data_device(device.id);
@ -260,7 +260,7 @@ enum Initiator {
impl Drop for Wm {
fn drop(&mut self) {
for (_, window) in self.windows.drain() {
for window in self.windows.drain_values() {
if let Some(window) = window.window.take() {
window.break_loops();
}
@ -1985,7 +1985,7 @@ impl Wm {
}
{
let mut children = data.children.lock();
for (_, child) in children.drain() {
for child in children.drain_values() {
child.parent.set(None);
}
}