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
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
10
src/state.rs
10
src/state.rs
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>) {
|
||||
|
|
|
|||
|
|
@ -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
15
src/utils/hash_map_ext.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue