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
|
|
@ -1,5 +1,7 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- Needs jay-compositor release.
|
||||||
|
|
||||||
# 1.2.0
|
# 1.2.0
|
||||||
|
|
||||||
- Needs jay-config release.
|
- Needs jay-config release.
|
||||||
|
|
|
||||||
|
|
@ -126,54 +126,53 @@ Jay's supports leasing VR headsets to applications.
|
||||||
|
|
||||||
Jay supports the following wayland protocols:
|
Jay supports the following wayland protocols:
|
||||||
|
|
||||||
| Global | Version | Privileged |
|
| Global | Version | Privileged |
|
||||||
|-----------------------------------------|:-----------------|---------------|
|
|-----------------------------------------|:----------------|---------------|
|
||||||
| ext_foreign_toplevel_list_v1 | 1 | Yes |
|
| ext_foreign_toplevel_list_v1 | 1 | Yes |
|
||||||
| ext_idle_notifier_v1 | 1 | Yes |
|
| ext_idle_notifier_v1 | 1 | Yes |
|
||||||
| ext_session_lock_manager_v1 | 1 | Yes |
|
| ext_session_lock_manager_v1 | 1 | Yes |
|
||||||
| ext_transient_seat_manager_v1 | 1[^ts_rejected] | Yes |
|
| ext_transient_seat_manager_v1 | 1[^ts_rejected] | Yes |
|
||||||
| org_kde_kwin_server_decoration_manager | 1 | |
|
| org_kde_kwin_server_decoration_manager | 1 | |
|
||||||
| wl_compositor | 6[^no_touch] | |
|
| wl_compositor | 6[^no_touch] | |
|
||||||
| wl_data_device_manager | 3 | |
|
| wl_data_device_manager | 3 | |
|
||||||
| wl_drm | 2 | |
|
| wl_drm | 2 | |
|
||||||
| wl_output | 4 | |
|
| wl_output | 4 | |
|
||||||
| wl_seat | 9 | |
|
| wl_seat | 9 | |
|
||||||
| wl_shm | 2 | |
|
| wl_shm | 2 | |
|
||||||
| wl_subcompositor | 1 | |
|
| wl_subcompositor | 1 | |
|
||||||
| wp_alpha_modifier_v1 | 1 | |
|
| wp_alpha_modifier_v1 | 1 | |
|
||||||
| wp_content_type_manager_v1 | 1 | |
|
| wp_content_type_manager_v1 | 1 | |
|
||||||
| wp_cursor_shape_manager_v1 | 1 | |
|
| wp_cursor_shape_manager_v1 | 1 | |
|
||||||
| wp_drm_lease_device_v1 | 1 | |
|
| wp_drm_lease_device_v1 | 1 | |
|
||||||
| wp_fractional_scale_manager_v1 | 1 | |
|
| wp_fractional_scale_manager_v1 | 1 | |
|
||||||
| wp_linux_drm_syncobj_manager_v1 | 1 | |
|
| wp_linux_drm_syncobj_manager_v1 | 1 | |
|
||||||
| wp_presentation | 1 | |
|
| wp_presentation | 1 | |
|
||||||
| wp_security_context_manager_v1 | 1 | |
|
| wp_security_context_manager_v1 | 1 | |
|
||||||
| wp_single_pixel_buffer_manager_v1 | 1 | |
|
| wp_single_pixel_buffer_manager_v1 | 1 | |
|
||||||
| wp_tearing_control_manager_v1 | 1[^no_tearing] | |
|
| wp_tearing_control_manager_v1 | 1[^no_tearing] | |
|
||||||
| wp_viewporter | 1 | |
|
| wp_viewporter | 1 | |
|
||||||
| xdg_activation_v1 | 1 | |
|
| xdg_activation_v1 | 1 | |
|
||||||
| xdg_toplevel_drag_manager_v1 | 1 | |
|
| xdg_toplevel_drag_manager_v1 | 1 | |
|
||||||
| xdg_wm_base | 6 | |
|
| xdg_wm_base | 6 | |
|
||||||
| xdg_wm_dialog_v1 | 1 | |
|
| xdg_wm_dialog_v1 | 1 | |
|
||||||
| zwlr_data_control_manager_v1 | 2 | Yes |
|
| zwlr_data_control_manager_v1 | 2 | Yes |
|
||||||
| zwlr_layer_shell_v1 | 4[^no_exclusive] | No[^lsaccess] |
|
| zwlr_layer_shell_v1 | 5 | No[^lsaccess] |
|
||||||
| zwlr_screencopy_manager_v1 | 3 | Yes |
|
| zwlr_screencopy_manager_v1 | 3 | Yes |
|
||||||
| zwp_idle_inhibit_manager_v1 | 1 | |
|
| zwp_idle_inhibit_manager_v1 | 1 | |
|
||||||
| zwp_input_method_manager_v2 | 1 | Yes |
|
| zwp_input_method_manager_v2 | 1 | Yes |
|
||||||
| zwp_linux_dmabuf_v1 | 5 | |
|
| zwp_linux_dmabuf_v1 | 5 | |
|
||||||
| zwp_pointer_constraints_v1 | 1 | |
|
| zwp_pointer_constraints_v1 | 1 | |
|
||||||
| zwp_pointer_gestures_v1 | 3 | |
|
| zwp_pointer_gestures_v1 | 3 | |
|
||||||
| zwp_primary_selection_device_manager_v1 | 1 | |
|
| zwp_primary_selection_device_manager_v1 | 1 | |
|
||||||
| zwp_relative_pointer_manager_v1 | 1 | |
|
| zwp_relative_pointer_manager_v1 | 1 | |
|
||||||
| zwp_tablet_manager_v2 | 1 | |
|
| zwp_tablet_manager_v2 | 1 | |
|
||||||
| zwp_text_input_manager_v3 | 1 | |
|
| zwp_text_input_manager_v3 | 1 | |
|
||||||
| zwp_virtual_keyboard_manager_v1 | 1 | Yes |
|
| zwp_virtual_keyboard_manager_v1 | 1 | Yes |
|
||||||
| zxdg_decoration_manager_v1 | 1 | |
|
| zxdg_decoration_manager_v1 | 1 | |
|
||||||
| zxdg_output_manager_v1 | 3 | |
|
| zxdg_output_manager_v1 | 3 | |
|
||||||
|
|
||||||
[^no_touch]: Touch input is not supported.
|
[^no_touch]: Touch input is not supported.
|
||||||
[^no_tearing]: Tearing screen updates are not supported.
|
[^no_tearing]: Tearing screen updates are not supported.
|
||||||
[^no_exclusive]: Exclusive zones are not supported.
|
|
||||||
[^lsaccess]: Sandboxes can restrict access to this protocol.
|
[^lsaccess]: Sandboxes can restrict access to this protocol.
|
||||||
[^ts_rejected]: Seat creation is always rejected.
|
[^ts_rejected]: Seat creation is always rejected.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- Add remaining layer-shell features.
|
||||||
|
|
||||||
# 1.2.0 (2024-05-05)
|
# 1.2.0 (2024-05-05)
|
||||||
|
|
||||||
- Add support for wp-security-manager-v1.
|
- Add support for wp-security-manager-v1.
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ use {
|
||||||
clonecell::{CloneCell, UnsafeCellCloneSafe},
|
clonecell::{CloneCell, UnsafeCellCloneSafe},
|
||||||
copyhashmap::CopyHashMap,
|
copyhashmap::CopyHashMap,
|
||||||
errorfmt::ErrorFmt,
|
errorfmt::ErrorFmt,
|
||||||
|
hash_map_ext::HashMapExt,
|
||||||
numcell::NumCell,
|
numcell::NumCell,
|
||||||
oserror::OsError,
|
oserror::OsError,
|
||||||
smallmap::SmallMap,
|
smallmap::SmallMap,
|
||||||
|
|
@ -184,7 +185,7 @@ impl Backend for MetalBackend {
|
||||||
dev.cb.take();
|
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();
|
dev.futures.clear();
|
||||||
for crtc in dev.dev.crtcs.values() {
|
for crtc in dev.dev.crtcs.values() {
|
||||||
crtc.connector.take();
|
crtc.connector.take();
|
||||||
|
|
@ -196,13 +197,13 @@ impl Backend for MetalBackend {
|
||||||
lease.crtcs.clear();
|
lease.crtcs.clear();
|
||||||
lease.planes.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);
|
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);
|
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();
|
let d = &mut *connector.display.borrow_mut();
|
||||||
d.crtcs.clear();
|
d.crtcs.clear();
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ use {
|
||||||
wl_registry::WlRegistry,
|
wl_registry::WlRegistry,
|
||||||
wl_seat::{tablet::zwp_tablet_tool_v2::ZwpTabletToolV2, wl_pointer::WlPointer, WlSeat},
|
wl_seat::{tablet::zwp_tablet_tool_v2::ZwpTabletToolV2, wl_pointer::WlPointer, WlSeat},
|
||||||
wl_surface::{
|
wl_surface::{
|
||||||
xdg_surface::{xdg_toplevel::XdgToplevel, XdgSurface},
|
xdg_surface::{xdg_popup::XdgPopup, xdg_toplevel::XdgToplevel, XdgSurface},
|
||||||
WlSurface,
|
WlSurface,
|
||||||
},
|
},
|
||||||
wp_drm_lease_connector_v1::WpDrmLeaseConnectorV1,
|
wp_drm_lease_connector_v1::WpDrmLeaseConnectorV1,
|
||||||
|
|
@ -33,8 +33,8 @@ use {
|
||||||
wire::{
|
wire::{
|
||||||
JayOutputId, JayScreencastId, JayToplevelId, JayWorkspaceId, WlBufferId,
|
JayOutputId, JayScreencastId, JayToplevelId, JayWorkspaceId, WlBufferId,
|
||||||
WlDataSourceId, WlOutputId, WlPointerId, WlRegionId, WlRegistryId, WlSeatId,
|
WlDataSourceId, WlOutputId, WlPointerId, WlRegionId, WlRegistryId, WlSeatId,
|
||||||
WlSurfaceId, WpDrmLeaseConnectorV1Id, WpLinuxDrmSyncobjTimelineV1Id, XdgPositionerId,
|
WlSurfaceId, WpDrmLeaseConnectorV1Id, WpLinuxDrmSyncobjTimelineV1Id, XdgPopupId,
|
||||||
XdgSurfaceId, XdgToplevelId, XdgWmBaseId, ZwlrDataControlSourceV1Id,
|
XdgPositionerId, XdgSurfaceId, XdgToplevelId, XdgWmBaseId, ZwlrDataControlSourceV1Id,
|
||||||
ZwpPrimarySelectionSourceV1Id, ZwpTabletToolV2Id,
|
ZwpPrimarySelectionSourceV1Id, ZwpTabletToolV2Id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -66,6 +66,7 @@ pub struct Objects {
|
||||||
pub jay_toplevels: CopyHashMap<JayToplevelId, Rc<JayToplevel>>,
|
pub jay_toplevels: CopyHashMap<JayToplevelId, Rc<JayToplevel>>,
|
||||||
pub drm_lease_outputs: CopyHashMap<WpDrmLeaseConnectorV1Id, Rc<WpDrmLeaseConnectorV1>>,
|
pub drm_lease_outputs: CopyHashMap<WpDrmLeaseConnectorV1Id, Rc<WpDrmLeaseConnectorV1>>,
|
||||||
pub tablet_tools: CopyHashMap<ZwpTabletToolV2Id, Rc<ZwpTabletToolV2>>,
|
pub tablet_tools: CopyHashMap<ZwpTabletToolV2Id, Rc<ZwpTabletToolV2>>,
|
||||||
|
pub xdg_popups: CopyHashMap<XdgPopupId, Rc<XdgPopup>>,
|
||||||
ids: RefCell<Vec<usize>>,
|
ids: RefCell<Vec<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,6 +99,7 @@ impl Objects {
|
||||||
jay_toplevels: Default::default(),
|
jay_toplevels: Default::default(),
|
||||||
drm_lease_outputs: Default::default(),
|
drm_lease_outputs: Default::default(),
|
||||||
tablet_tools: Default::default(),
|
tablet_tools: Default::default(),
|
||||||
|
xdg_popups: Default::default(),
|
||||||
ids: RefCell::new(vec![]),
|
ids: RefCell::new(vec![]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -134,6 +136,7 @@ impl Objects {
|
||||||
self.jay_toplevels.clear();
|
self.jay_toplevels.clear();
|
||||||
self.drm_lease_outputs.clear();
|
self.drm_lease_outputs.clear();
|
||||||
self.tablet_tools.clear();
|
self.tablet_tools.clear();
|
||||||
|
self.xdg_popups.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id<T>(&self, client_data: &Client) -> Result<T, ClientError>
|
pub fn id<T>(&self, client_data: &Client) -> Result<T, ClientError>
|
||||||
|
|
|
||||||
|
|
@ -449,6 +449,10 @@ fn create_dummy_output(state: &Rc<State>) {
|
||||||
workspace: Default::default(),
|
workspace: Default::default(),
|
||||||
seat_state: Default::default(),
|
seat_state: Default::default(),
|
||||||
layers: 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(),
|
render_data: Default::default(),
|
||||||
state: state.clone(),
|
state: state.clone(),
|
||||||
is_dummy: true,
|
is_dummy: true,
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ use {
|
||||||
state::State,
|
state::State,
|
||||||
tree::OutputNode,
|
tree::OutputNode,
|
||||||
utils::{
|
utils::{
|
||||||
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, rc_eq::rc_eq,
|
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt,
|
||||||
transform_ext::TransformExt,
|
hash_map_ext::HashMapExt, rc_eq::rc_eq, transform_ext::TransformExt,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
std::{cell::Cell, ops::Deref, rc::Rc},
|
std::{cell::Cell, ops::Deref, rc::Rc},
|
||||||
|
|
@ -99,7 +99,7 @@ impl CursorUserGroup {
|
||||||
.set(self.state.dummy_output.get().unwrap());
|
.set(self.state.dummy_output.get().unwrap());
|
||||||
self.state.remove_cursor_size(self.size.get());
|
self.state.remove_cursor_size(self.size.get());
|
||||||
self.state.cursor_user_groups.remove(&self.id);
|
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();
|
user.detach();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use std::{
|
||||||
ops::{Add, AddAssign, Sub, SubAssign},
|
ops::{Add, AddAssign, Sub, SubAssign},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct Fixed(pub i32);
|
pub struct Fixed(pub i32);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ use {
|
||||||
object::Version,
|
object::Version,
|
||||||
state::DeviceHandlerData,
|
state::DeviceHandlerData,
|
||||||
tree::{Direction, Node, ToplevelNode},
|
tree::{Direction, Node, ToplevelNode},
|
||||||
utils::{bitflags::BitflagsExt, smallmap::SmallMap},
|
utils::{bitflags::BitflagsExt, hash_map_ext::HashMapExt, smallmap::SmallMap},
|
||||||
wire::WlDataOfferId,
|
wire::WlDataOfferId,
|
||||||
xkbcommon::{KeyboardState, XkbState, XKB_KEY_DOWN, XKB_KEY_UP},
|
xkbcommon::{KeyboardState, XkbState, XKB_KEY_DOWN, XKB_KEY_UP},
|
||||||
},
|
},
|
||||||
|
|
@ -237,7 +237,7 @@ impl WlSeatGlobal {
|
||||||
| InputEvent::TabletPadStrip { time_usec, .. } => {
|
| InputEvent::TabletPadStrip { time_usec, .. } => {
|
||||||
self.last_input_usec.set(time_usec);
|
self.last_input_usec.set(time_usec);
|
||||||
if self.idle_notifications.is_not_empty() {
|
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();
|
notification.resume.trigger();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,10 @@ use {
|
||||||
object::Version,
|
object::Version,
|
||||||
time::now_usec,
|
time::now_usec,
|
||||||
tree::{FoundNode, Node},
|
tree::{FoundNode, Node},
|
||||||
utils::{bindings::PerClientBindings, clonecell::CloneCell, copyhashmap::CopyHashMap},
|
utils::{
|
||||||
|
bindings::PerClientBindings, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
||||||
|
hash_map_ext::HashMapExt,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
|
|
@ -293,18 +296,18 @@ impl WlSeatGlobal {
|
||||||
|
|
||||||
pub fn tablet_clear(&self) {
|
pub fn tablet_clear(&self) {
|
||||||
self.tablet.seats.clear();
|
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.pads.clear();
|
||||||
tablet.bindings.clear();
|
tablet.bindings.clear();
|
||||||
tablet.tools.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.cursor.detach();
|
||||||
tool.opt.tool.take();
|
tool.opt.tool.take();
|
||||||
tool.tool_owner.destroy(&tool);
|
tool.tool_owner.destroy(&tool);
|
||||||
tool.bindings.clear();
|
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.pad_owner.destroy(&pad);
|
||||||
pad.tablet.take();
|
pad.tablet.take();
|
||||||
pad.bindings.clear();
|
pad.bindings.clear();
|
||||||
|
|
@ -324,14 +327,14 @@ impl WlSeatGlobal {
|
||||||
let Some(tablet) = self.tablet.tablets.remove(&id) else {
|
let Some(tablet) = self.tablet.tablets.remove(&id) else {
|
||||||
return;
|
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);
|
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.pad_owner.destroy(&pad);
|
||||||
pad.tablet.take();
|
pad.tablet.take();
|
||||||
}
|
}
|
||||||
for (_, binding) in tablet.bindings.lock().drain() {
|
for binding in tablet.bindings.lock().drain_values() {
|
||||||
binding.send_removed();
|
binding.send_removed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use {
|
||||||
wl_surface::WlSurface,
|
wl_surface::WlSurface,
|
||||||
},
|
},
|
||||||
time::{now_usec, usec_to_msec},
|
time::{now_usec, usec_to_msec},
|
||||||
utils::clonecell::CloneCell,
|
utils::{clonecell::CloneCell, hash_map_ext::HashMapExt},
|
||||||
},
|
},
|
||||||
std::{cell::Cell, rc::Rc},
|
std::{cell::Cell, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
@ -76,7 +76,7 @@ impl WlSeatGlobal {
|
||||||
if let Some(tablet) = pad.tablet.take() {
|
if let Some(tablet) = pad.tablet.take() {
|
||||||
tablet.pads.remove(&pad.id);
|
tablet.pads.remove(&pad.id);
|
||||||
}
|
}
|
||||||
for (_, binding) in pad.bindings.lock().drain() {
|
for binding in pad.bindings.lock().drain_values() {
|
||||||
binding.send_removed();
|
binding.send_removed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use {
|
||||||
},
|
},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
time::usec_to_msec,
|
time::usec_to_msec,
|
||||||
utils::clonecell::CloneCell,
|
utils::{clonecell::CloneCell, hash_map_ext::HashMapExt},
|
||||||
},
|
},
|
||||||
std::{cell::Cell, rc::Rc},
|
std::{cell::Cell, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
@ -31,7 +31,7 @@ impl WlSeatGlobal {
|
||||||
tool.opt.tool.take();
|
tool.opt.tool.take();
|
||||||
tool.cursor.detach();
|
tool.cursor.detach();
|
||||||
tool.tool_owner.destroy(&tool);
|
tool.tool_owner.destroy(&tool);
|
||||||
for (_, binding) in tool.bindings.lock().drain() {
|
for binding in tool.bindings.lock().drain_values() {
|
||||||
binding.send_removed();
|
binding.send_removed();
|
||||||
}
|
}
|
||||||
tool.tablet.tools.remove(&id);
|
tool.tablet.tools.remove(&id);
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ pub struct WlPointer {
|
||||||
id: WlPointerId,
|
id: WlPointerId,
|
||||||
pub seat: Rc<WlSeat>,
|
pub seat: Rc<WlSeat>,
|
||||||
pub tracker: Tracker<Self>,
|
pub tracker: Tracker<Self>,
|
||||||
|
last_motion: Cell<(Fixed, Fixed)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WlPointer {
|
impl WlPointer {
|
||||||
|
|
@ -82,10 +83,12 @@ impl WlPointer {
|
||||||
id,
|
id,
|
||||||
seat: seat.clone(),
|
seat: seat.clone(),
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
|
last_motion: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_enter(&self, serial: u32, surface: WlSurfaceId, x: Fixed, y: Fixed) {
|
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.seat.client.event(Enter {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
serial,
|
serial,
|
||||||
|
|
@ -104,6 +107,9 @@ impl WlPointer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_motion(&self, time: u32, x: Fixed, y: Fixed) {
|
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.seat.client.event(Motion {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
time,
|
time,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use {
|
||||||
utils::{
|
utils::{
|
||||||
clonecell::CloneCell,
|
clonecell::CloneCell,
|
||||||
copyhashmap::CopyHashMap,
|
copyhashmap::CopyHashMap,
|
||||||
|
hash_map_ext::HashMapExt,
|
||||||
linkedlist::{LinkedList, LinkedNode, NodeRef},
|
linkedlist::{LinkedList, LinkedNode, NodeRef},
|
||||||
numcell::NumCell,
|
numcell::NumCell,
|
||||||
},
|
},
|
||||||
|
|
@ -102,7 +103,7 @@ impl CommitTimelines {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&self) {
|
pub fn clear(&self) {
|
||||||
for (_, list) in self.gc.lock().drain() {
|
for list in self.gc.lock().drain_values() {
|
||||||
break_loops(&list);
|
break_loops(&list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use {
|
||||||
ifs::{
|
ifs::{
|
||||||
wl_surface::{
|
wl_surface::{
|
||||||
xdg_surface::{
|
xdg_surface::{
|
||||||
xdg_popup::{XdgPopup, XdgPopupError},
|
xdg_popup::{XdgPopup, XdgPopupError, XdgPopupParent},
|
||||||
xdg_toplevel::{XdgToplevel, WM_CAPABILITIES_SINCE},
|
xdg_toplevel::{XdgToplevel, WM_CAPABILITIES_SINCE},
|
||||||
},
|
},
|
||||||
PendingState, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError,
|
PendingState, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError,
|
||||||
|
|
@ -17,14 +17,20 @@ use {
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::Object,
|
object::Object,
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
tree::{FindTreeResult, FoundNode, OutputNode, WorkspaceNode},
|
tree::{FindTreeResult, FoundNode, OutputNode, StackedNode, WorkspaceNode},
|
||||||
utils::{
|
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},
|
wire::{xdg_surface::*, WlSurfaceId, XdgPopupId, XdgSurfaceId},
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefMut},
|
cell::{Cell, RefCell, RefMut},
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
},
|
},
|
||||||
|
|
@ -65,11 +71,72 @@ pub struct XdgSurface {
|
||||||
extents: Cell<Rect>,
|
extents: Cell<Rect>,
|
||||||
pub absolute_desired_extents: Cell<Rect>,
|
pub absolute_desired_extents: Cell<Rect>,
|
||||||
ext: CloneCell<Option<Rc<dyn XdgSurfaceExt>>>,
|
ext: CloneCell<Option<Rc<dyn XdgSurfaceExt>>>,
|
||||||
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 workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
|
||||||
pub tracker: Tracker<Self>,
|
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)]
|
#[derive(Default, Debug)]
|
||||||
pub struct PendingXdgSurfaceData {
|
pub struct PendingXdgSurfaceData {
|
||||||
geometry: Option<Rect>,
|
geometry: Option<Rect>,
|
||||||
|
|
@ -115,6 +182,7 @@ impl XdgSurface {
|
||||||
extents: Cell::new(Default::default()),
|
extents: Cell::new(Default::default()),
|
||||||
absolute_desired_extents: Cell::new(Default::default()),
|
absolute_desired_extents: Cell::new(Default::default()),
|
||||||
ext: Default::default(),
|
ext: Default::default(),
|
||||||
|
popup_display_stack: CloneCell::new(surface.client.state.root.stacked.clone()),
|
||||||
popups: Default::default(),
|
popups: Default::default(),
|
||||||
workspace: Default::default(),
|
workspace: Default::default(),
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
|
|
@ -139,7 +207,7 @@ impl XdgSurface {
|
||||||
self.surface.set_output(&ws.output.get());
|
self.surface.set_output(&ws.output.get());
|
||||||
let pu = self.popups.lock();
|
let pu = self.popups.lock();
|
||||||
for pu in pu.values() {
|
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);
|
self.surface.set_output(output);
|
||||||
let pu = self.popups.lock();
|
let pu = self.popups.lock();
|
||||||
for pu in pu.values() {
|
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) {
|
fn destroy_node(&self) {
|
||||||
self.workspace.set(None);
|
self.workspace.set(None);
|
||||||
self.surface.destroy_node();
|
self.surface.destroy_node();
|
||||||
let popups = self.popups.lock();
|
for popup in self.popups.lock().drain_values() {
|
||||||
for popup in popups.values() {
|
popup.popup.destroy_node();
|
||||||
popup.destroy_node();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,7 +249,8 @@ impl XdgSurface {
|
||||||
self.surface.detach_node(false);
|
self.surface.detach_node(false);
|
||||||
let popups = self.popups.lock();
|
let popups = self.popups.lock();
|
||||||
for popup in popups.values() {
|
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()
|
p.xdg_surface.get_or_insert_default_ext()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_popup_stack(&self, stack: &Rc<LinkedList<Rc<dyn StackedNode>>>) {
|
||||||
|
let prev = self.popup_display_stack.set(stack.clone());
|
||||||
|
if rc_eq(&prev, stack) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for popup in self.popups.lock().values() {
|
||||||
|
if let Some(dl) = &*popup.display_link.borrow() {
|
||||||
|
stack.add_last_existing(dl);
|
||||||
|
}
|
||||||
|
popup.popup.xdg.set_popup_stack(stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XdgSurfaceRequestHandler for XdgSurface {
|
impl XdgSurfaceRequestHandler for XdgSurface {
|
||||||
|
|
@ -279,11 +360,18 @@ impl XdgSurfaceRequestHandler for XdgSurface {
|
||||||
);
|
);
|
||||||
return Err(XdgSurfaceError::AlreadyConstructed);
|
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);
|
track!(self.surface.client, popup);
|
||||||
self.surface.client.add_client_obj(&popup)?;
|
self.surface.client.add_client_obj(&popup)?;
|
||||||
if let Some(parent) = &parent {
|
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));
|
self.ext.set(Some(popup));
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -341,21 +429,29 @@ impl XdgSurface {
|
||||||
fn update_popup_positions(&self) {
|
fn update_popup_positions(&self) {
|
||||||
let popups = self.popups.lock();
|
let popups = self.popups.lock();
|
||||||
for popup in popups.values() {
|
for popup in popups.values() {
|
||||||
popup.update_absolute_position();
|
popup.popup.update_absolute_position();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_visible(&self, visible: bool) {
|
fn set_visible(&self, visible: bool) {
|
||||||
self.surface.set_visible(visible);
|
self.surface.set_visible(visible);
|
||||||
for popup in self.popups.lock().values() {
|
for popup in self.popups.lock().values() {
|
||||||
popup.set_visible(visible);
|
popup.popup.set_visible(visible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restack_popups(&self) {
|
fn restack_popups(&self) {
|
||||||
for popup in self.popups.lock().values() {
|
if self.popups.is_empty() {
|
||||||
popup.restack();
|
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,
|
rect::Rect,
|
||||||
renderer::Renderer,
|
renderer::Renderer,
|
||||||
tree::{
|
tree::{
|
||||||
FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeVisitor, StackedNode,
|
FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeVisitor, OutputNode,
|
||||||
WorkspaceNode,
|
StackedNode,
|
||||||
},
|
},
|
||||||
utils::{clonecell::CloneCell, linkedlist::LinkedNode},
|
utils::clonecell::CloneCell,
|
||||||
wire::{xdg_popup::*, XdgPopupId},
|
wire::{xdg_popup::*, XdgPopupId},
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
|
|
@ -35,14 +35,20 @@ const INVALID_GRAB: u32 = 1;
|
||||||
|
|
||||||
tree_id!(PopupId);
|
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 {
|
pub struct XdgPopup {
|
||||||
id: XdgPopupId,
|
pub id: XdgPopupId,
|
||||||
node_id: PopupId,
|
node_id: PopupId,
|
||||||
pub xdg: Rc<XdgSurface>,
|
pub xdg: Rc<XdgSurface>,
|
||||||
pub(super) parent: CloneCell<Option<Rc<XdgSurface>>>,
|
pub(in super::super) parent: CloneCell<Option<Rc<dyn XdgPopupParent>>>,
|
||||||
relative_position: Cell<Rect>,
|
relative_position: Cell<Rect>,
|
||||||
display_link: RefCell<Option<LinkedNode<Rc<dyn StackedNode>>>>,
|
|
||||||
workspace_link: RefCell<Option<LinkedNode<Rc<dyn StackedNode>>>>,
|
|
||||||
pos: RefCell<XdgPositioned>,
|
pos: RefCell<XdgPositioned>,
|
||||||
pub tracker: Tracker<Self>,
|
pub tracker: Tracker<Self>,
|
||||||
seat_state: NodeSeatState,
|
seat_state: NodeSeatState,
|
||||||
|
|
@ -59,7 +65,6 @@ impl XdgPopup {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
id: XdgPopupId,
|
id: XdgPopupId,
|
||||||
xdg: &Rc<XdgSurface>,
|
xdg: &Rc<XdgSurface>,
|
||||||
parent: Option<&Rc<XdgSurface>>,
|
|
||||||
pos: &Rc<XdgPositioner>,
|
pos: &Rc<XdgPositioner>,
|
||||||
) -> Result<Self, XdgPopupError> {
|
) -> Result<Self, XdgPopupError> {
|
||||||
let pos = pos.value();
|
let pos = pos.value();
|
||||||
|
|
@ -70,10 +75,8 @@ impl XdgPopup {
|
||||||
id,
|
id,
|
||||||
node_id: xdg.surface.client.state.node_ids.next(),
|
node_id: xdg.surface.client.state.node_ids.next(),
|
||||||
xdg: xdg.clone(),
|
xdg: xdg.clone(),
|
||||||
parent: CloneCell::new(parent.cloned()),
|
parent: Default::default(),
|
||||||
relative_position: Cell::new(Default::default()),
|
relative_position: Cell::new(Default::default()),
|
||||||
display_link: RefCell::new(None),
|
|
||||||
workspace_link: RefCell::new(None),
|
|
||||||
pos: RefCell::new(pos),
|
pos: RefCell::new(pos),
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
seat_state: Default::default(),
|
seat_state: Default::default(),
|
||||||
|
|
@ -105,17 +108,13 @@ impl XdgPopup {
|
||||||
.event(PopupDone { self_id: self.id })
|
.event(PopupDone { self_id: self.id })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_position(&self, parent: &XdgSurface) -> Result<(), XdgPopupError> {
|
fn update_position(&self, parent: &dyn XdgPopupParent) {
|
||||||
// let parent = parent.extents.get();
|
|
||||||
let positioner = self.pos.borrow_mut();
|
let positioner = self.pos.borrow_mut();
|
||||||
// if !parent.contains_rect(&positioner.ar) {
|
let parent_abs = parent.position();
|
||||||
// return Err(XdgPopupError::AnchorRectOutside);
|
|
||||||
// }
|
|
||||||
let parent_abs = parent.absolute_desired_extents.get();
|
|
||||||
let mut rel_pos = positioner.get_position(false, false);
|
let mut rel_pos = positioner.get_position(false, false);
|
||||||
let mut abs_pos = rel_pos.move_(parent_abs.x1(), parent_abs.y1());
|
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);
|
let mut overflow = output_pos.get_overflow(&abs_pos);
|
||||||
if !overflow.is_contained() {
|
if !overflow.is_contained() {
|
||||||
let mut flip_x = positioner.ca.contains(CA_FLIP_X) && overflow.x_overflow();
|
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);
|
let (mut dx, mut dy) = (0, 0);
|
||||||
if positioner.ca.contains(CA_SLIDE_X) && overflow.x_overflow() {
|
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()
|
parent_abs.x1() - abs_pos.x1()
|
||||||
|
} else if overflow.left > 0 {
|
||||||
|
overflow.left
|
||||||
} else {
|
} else {
|
||||||
parent_abs.x2() - abs_pos.x2()
|
-overflow.right
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if positioner.ca.contains(CA_SLIDE_Y) && overflow.y_overflow() {
|
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()
|
parent_abs.y1() - abs_pos.y1()
|
||||||
|
} else if overflow.top > 0 {
|
||||||
|
overflow.top
|
||||||
} else {
|
} else {
|
||||||
parent_abs.y2() - abs_pos.y2()
|
-overflow.bottom
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if dx != 0 || dy != 0 {
|
if dx != 0 || dy != 0 {
|
||||||
|
|
@ -174,32 +177,35 @@ impl XdgPopup {
|
||||||
dy2 = -overflow.bottom.max(0);
|
dy2 = -overflow.bottom.max(0);
|
||||||
}
|
}
|
||||||
if dx1 > 0 || dx2 < 0 || dy1 > 0 || dy2 < 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.x1() + dx1,
|
||||||
abs_pos.y1() + dy1,
|
abs_pos.y1() + dy1,
|
||||||
abs_pos.x2() + dx2,
|
abs_pos.x2() + dx2,
|
||||||
abs_pos.y2() + dy2,
|
abs_pos.y2() + dy2,
|
||||||
)
|
);
|
||||||
.unwrap();
|
// If the popup is completely outside the output, this will fail. Just
|
||||||
rel_pos = Rect::new_sized(
|
// use its position as is.
|
||||||
abs_pos.x1() - parent_abs.x1(),
|
if let Some(maybe_abs_pos) = maybe_abs_pos {
|
||||||
abs_pos.y1() - parent_abs.y1(),
|
abs_pos = maybe_abs_pos;
|
||||||
abs_pos.width(),
|
rel_pos = Rect::new_sized(
|
||||||
abs_pos.height(),
|
abs_pos.x1() - parent_abs.x1(),
|
||||||
)
|
abs_pos.y1() - parent_abs.y1(),
|
||||||
.unwrap();
|
abs_pos.width(),
|
||||||
|
abs_pos.height(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.relative_position.set(rel_pos);
|
self.relative_position.set(rel_pos);
|
||||||
self.xdg.set_absolute_desired_extents(&abs_pos);
|
self.xdg.set_absolute_desired_extents(&abs_pos);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_absolute_position(&self) {
|
pub fn update_absolute_position(&self) {
|
||||||
if let Some(parent) = self.parent.get() {
|
if let Some(parent) = self.parent.get() {
|
||||||
let rel = self.relative_position.get();
|
let rel = self.relative_position.get();
|
||||||
let parent = parent.absolute_desired_extents.get();
|
let parent = parent.position();
|
||||||
self.xdg
|
self.xdg
|
||||||
.set_absolute_desired_extents(&rel.move_(parent.x1(), parent.y1()));
|
.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> {
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
self.destroy_node();
|
self.destroy_node();
|
||||||
{
|
|
||||||
if let Some(parent) = self.parent.take() {
|
|
||||||
parent.popups.remove(&self.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.xdg.ext.set(None);
|
self.xdg.ext.set(None);
|
||||||
self.xdg.surface.client.remove_obj(self)?;
|
self.xdg.surface.client.remove_obj(self)?;
|
||||||
*self.display_link.borrow_mut() = None;
|
|
||||||
*self.workspace_link.borrow_mut() = None;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -230,7 +229,7 @@ impl XdgPopupRequestHandler for XdgPopup {
|
||||||
fn reposition(&self, req: Reposition, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn reposition(&self, req: Reposition, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
*self.pos.borrow_mut() = self.xdg.surface.client.lookup(req.positioner)?.value();
|
*self.pos.borrow_mut() = self.xdg.surface.client.lookup(req.positioner)?.value();
|
||||||
if let Some(parent) = self.parent.get() {
|
if let Some(parent) = self.parent.get() {
|
||||||
self.update_position(&parent)?;
|
self.update_position(&*parent);
|
||||||
let rel = self.relative_position.get();
|
let rel = self.relative_position.get();
|
||||||
self.send_repositioned(req.token);
|
self.send_repositioned(req.token);
|
||||||
self.send_configure(rel.x1(), rel.y1(), rel.width(), rel.height());
|
self.send_configure(rel.x1(), rel.y1(), rel.width(), rel.height());
|
||||||
|
|
@ -241,10 +240,6 @@ impl XdgPopupRequestHandler for XdgPopup {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XdgPopup {
|
impl XdgPopup {
|
||||||
fn get_parent_workspace(&self) -> Option<Rc<WorkspaceNode>> {
|
|
||||||
self.parent.get()?.workspace.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_visible(&self, visible: bool) {
|
pub fn set_visible(&self, visible: bool) {
|
||||||
// log::info!("set visible = {}", visible);
|
// log::info!("set visible = {}", visible);
|
||||||
self.set_visible_prepared.set(false);
|
self.set_visible_prepared.set(false);
|
||||||
|
|
@ -253,27 +248,18 @@ impl XdgPopup {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy_node(&self) {
|
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.xdg.destroy_node();
|
||||||
self.seat_state.destroy_node(self);
|
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) {
|
pub fn detach_node(&self) {
|
||||||
let _v = self.workspace_link.borrow_mut().take();
|
|
||||||
self.xdg.detach_node();
|
self.xdg.detach_node();
|
||||||
self.seat_state.destroy_node(self);
|
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! {
|
object_base! {
|
||||||
|
|
@ -284,13 +270,10 @@ object_base! {
|
||||||
impl Object for XdgPopup {
|
impl Object for XdgPopup {
|
||||||
fn break_loops(&self) {
|
fn break_loops(&self) {
|
||||||
self.destroy_node();
|
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 {
|
impl Node for XdgPopup {
|
||||||
fn node_id(&self) -> NodeId {
|
fn node_id(&self) -> NodeId {
|
||||||
|
|
@ -374,7 +357,10 @@ impl StackedNode for XdgPopup {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stacked_has_workspace_link(&self) -> bool {
|
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 {
|
fn stacked_absolute_position_constrains_input(&self) -> bool {
|
||||||
|
|
@ -385,7 +371,7 @@ impl StackedNode for XdgPopup {
|
||||||
impl XdgSurfaceExt for XdgPopup {
|
impl XdgSurfaceExt for XdgPopup {
|
||||||
fn initial_configure(self: Rc<Self>) -> Result<(), XdgSurfaceError> {
|
fn initial_configure(self: Rc<Self>) -> Result<(), XdgSurfaceError> {
|
||||||
if let Some(parent) = self.parent.get() {
|
if let Some(parent) = self.parent.get() {
|
||||||
self.update_position(&parent)?;
|
self.update_position(&*parent);
|
||||||
let rel = self.relative_position.get();
|
let rel = self.relative_position.get();
|
||||||
self.send_configure(rel.x1(), rel.y1(), rel.width(), rel.height());
|
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>) {
|
fn post_commit(self: Rc<Self>) {
|
||||||
let mut wl = self.workspace_link.borrow_mut();
|
if let Some(parent) = self.parent.get() {
|
||||||
let mut dl = self.display_link.borrow_mut();
|
parent.post_commit();
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ use {
|
||||||
OutputNode, ToplevelData, ToplevelNode, ToplevelNodeBase, ToplevelNodeId,
|
OutputNode, ToplevelData, ToplevelNode, ToplevelNodeBase, ToplevelNodeId,
|
||||||
WorkspaceNode,
|
WorkspaceNode,
|
||||||
},
|
},
|
||||||
utils::clonecell::CloneCell,
|
utils::{clonecell::CloneCell, hash_map_ext::HashMapExt},
|
||||||
wire::{xdg_toplevel::*, XdgToplevelId},
|
wire::{xdg_toplevel::*, XdgToplevelId},
|
||||||
},
|
},
|
||||||
ahash::{AHashMap, AHashSet},
|
ahash::{AHashMap, AHashSet},
|
||||||
|
|
@ -218,7 +218,7 @@ impl XdgToplevelRequestHandler for XdgToplevel {
|
||||||
Some(p) => Some(p.children.borrow_mut()),
|
Some(p) => Some(p.children.borrow_mut()),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
for (_, child) in children.drain() {
|
for child in children.drain_values() {
|
||||||
child.parent.set(parent.clone());
|
child.parent.set(parent.clone());
|
||||||
if let Some(parent_children) = &mut parent_children {
|
if let Some(parent_children) = &mut parent_children {
|
||||||
parent_children.insert(child.id, child);
|
parent_children.insert(child.id, child);
|
||||||
|
|
@ -418,7 +418,7 @@ impl XdgToplevel {
|
||||||
{
|
{
|
||||||
let new_parent = self.parent.get();
|
let new_parent = self.parent.get();
|
||||||
let mut children = self.children.borrow_mut();
|
let mut children = self.children.borrow_mut();
|
||||||
for (_, child) in children.drain() {
|
for child in children.drain_values() {
|
||||||
child.parent.set(new_parent.clone());
|
child.parent.set(new_parent.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,23 +4,32 @@ use {
|
||||||
ifs::{
|
ifs::{
|
||||||
wl_output::OutputGlobalOpt,
|
wl_output::OutputGlobalOpt,
|
||||||
wl_seat::NodeSeatState,
|
wl_seat::NodeSeatState,
|
||||||
wl_surface::{PendingState, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError},
|
wl_surface::{
|
||||||
|
xdg_surface::xdg_popup::{XdgPopup, XdgPopupParent},
|
||||||
|
PendingState, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError,
|
||||||
|
},
|
||||||
zwlr_layer_shell_v1::{ZwlrLayerShellV1, OVERLAY},
|
zwlr_layer_shell_v1::{ZwlrLayerShellV1, OVERLAY},
|
||||||
},
|
},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::Object,
|
object::Object,
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
renderer::Renderer,
|
renderer::Renderer,
|
||||||
tree::{FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeVisitor},
|
tree::{
|
||||||
|
FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeVisitor, OutputNode,
|
||||||
|
StackedNode,
|
||||||
|
},
|
||||||
utils::{
|
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,
|
option_ext::OptionExt,
|
||||||
},
|
},
|
||||||
wire::{zwlr_layer_surface_v1::*, WlSurfaceId, ZwlrLayerSurfaceV1Id},
|
wire::{zwlr_layer_surface_v1::*, WlSurfaceId, XdgPopupId, ZwlrLayerSurfaceV1Id},
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefMut},
|
cell::{Cell, RefCell, RefMut},
|
||||||
mem,
|
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
},
|
},
|
||||||
|
|
@ -47,30 +56,74 @@ pub struct ZwlrLayerSurfaceV1 {
|
||||||
pub output: Rc<OutputGlobalOpt>,
|
pub output: Rc<OutputGlobalOpt>,
|
||||||
pub namespace: String,
|
pub namespace: String,
|
||||||
pub tracker: Tracker<Self>,
|
pub tracker: Tracker<Self>,
|
||||||
output_pos: Cell<Rect>,
|
output_extents: Cell<Rect>,
|
||||||
pos: Cell<Rect>,
|
pos: Cell<Rect>,
|
||||||
mapped: Cell<bool>,
|
mapped: Cell<bool>,
|
||||||
layer: Cell<u32>,
|
layer: Cell<u32>,
|
||||||
requested_serial: NumCell<u32>,
|
requested_serial: NumCell<u32>,
|
||||||
acked_serial: Cell<Option<u32>>,
|
|
||||||
size: Cell<(i32, i32)>,
|
size: Cell<(i32, i32)>,
|
||||||
anchor: Cell<u32>,
|
anchor: Cell<u32>,
|
||||||
exclusive_zone: Cell<i32>,
|
exclusive_zone: Cell<ExclusiveZone>,
|
||||||
margin: Cell<(i32, i32, i32, i32)>,
|
margin: Cell<(i32, i32, i32, i32)>,
|
||||||
keyboard_interactivity: Cell<u32>,
|
keyboard_interactivity: Cell<u32>,
|
||||||
link: Cell<Option<LinkedNode<Rc<Self>>>>,
|
link: Cell<Option<LinkedNode<Rc<Self>>>>,
|
||||||
seat_state: NodeSeatState,
|
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)]
|
#[derive(Default)]
|
||||||
pub struct PendingLayerSurfaceData {
|
pub struct PendingLayerSurfaceData {
|
||||||
size: Option<(i32, i32)>,
|
size: Option<(i32, i32)>,
|
||||||
anchor: Option<u32>,
|
anchor: Option<u32>,
|
||||||
exclusive_zone: Option<i32>,
|
exclusive_zone: Option<ExclusiveZone>,
|
||||||
margin: Option<(i32, i32, i32, i32)>,
|
margin: Option<(i32, i32, i32, i32)>,
|
||||||
keyboard_interactivity: Option<u32>,
|
keyboard_interactivity: Option<u32>,
|
||||||
layer: Option<u32>,
|
layer: Option<u32>,
|
||||||
any: bool,
|
exclusive_edge: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PendingLayerSurfaceData {
|
impl PendingLayerSurfaceData {
|
||||||
|
|
@ -88,7 +141,6 @@ impl PendingLayerSurfaceData {
|
||||||
opt!(margin);
|
opt!(margin);
|
||||||
opt!(keyboard_interactivity);
|
opt!(keyboard_interactivity);
|
||||||
opt!(layer);
|
opt!(layer);
|
||||||
self.any |= mem::take(&mut next.any);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,19 +162,22 @@ impl ZwlrLayerSurfaceV1 {
|
||||||
output: output.clone(),
|
output: output.clone(),
|
||||||
namespace: namespace.to_string(),
|
namespace: namespace.to_string(),
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
output_pos: Default::default(),
|
output_extents: Default::default(),
|
||||||
pos: Default::default(),
|
pos: Default::default(),
|
||||||
mapped: Cell::new(false),
|
mapped: Cell::new(false),
|
||||||
layer: Cell::new(layer),
|
layer: Cell::new(layer),
|
||||||
requested_serial: Default::default(),
|
requested_serial: Default::default(),
|
||||||
acked_serial: Cell::new(None),
|
|
||||||
size: Cell::new((0, 0)),
|
size: Cell::new((0, 0)),
|
||||||
anchor: Cell::new(0),
|
anchor: Cell::new(0),
|
||||||
exclusive_zone: Cell::new(0),
|
exclusive_zone: Cell::new(ExclusiveZone::MoveSelf),
|
||||||
margin: Cell::new((0, 0, 0, 0)),
|
margin: Cell::new((0, 0, 0, 0)),
|
||||||
keyboard_interactivity: Cell::new(0),
|
keyboard_interactivity: Cell::new(0),
|
||||||
link: Cell::new(None),
|
link: Cell::new(None),
|
||||||
seat_state: Default::default(),
|
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();
|
let mut pending = self.pending();
|
||||||
pending.size = Some((req.width as _, req.height as _));
|
pending.size = Some((req.width as _, req.height as _));
|
||||||
pending.any = true;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,7 +231,6 @@ impl ZwlrLayerSurfaceV1RequestHandler for ZwlrLayerSurfaceV1 {
|
||||||
}
|
}
|
||||||
let mut pending = self.pending();
|
let mut pending = self.pending();
|
||||||
pending.anchor = Some(req.anchor);
|
pending.anchor = Some(req.anchor);
|
||||||
pending.any = true;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -187,15 +240,27 @@ impl ZwlrLayerSurfaceV1RequestHandler for ZwlrLayerSurfaceV1 {
|
||||||
_slf: &Rc<Self>,
|
_slf: &Rc<Self>,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
let mut pending = self.pending();
|
let mut pending = self.pending();
|
||||||
pending.exclusive_zone = Some(req.zone);
|
let zone = if req.zone < 0 {
|
||||||
pending.any = true;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_margin(&self, req: SetMargin, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn set_margin(&self, req: SetMargin, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
let mut pending = self.pending();
|
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.margin = Some((req.top, req.right, req.bottom, req.left));
|
||||||
pending.any = true;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,20 +276,35 @@ impl ZwlrLayerSurfaceV1RequestHandler for ZwlrLayerSurfaceV1 {
|
||||||
}
|
}
|
||||||
let mut pending = self.pending();
|
let mut pending = self.pending();
|
||||||
pending.keyboard_interactivity = Some(req.keyboard_interactivity);
|
pending.keyboard_interactivity = Some(req.keyboard_interactivity);
|
||||||
pending.any = true;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_popup(&self, _req: GetPopup, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn get_popup(&self, req: GetPopup, slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let popup = self.client.lookup(req.popup)?;
|
||||||
|
if popup.parent.is_some() {
|
||||||
|
return Err(ZwlrLayerSurfaceV1Error::PopupHasParent);
|
||||||
|
}
|
||||||
|
let stack = self.client.state.root.stacked_above_layers.clone();
|
||||||
|
popup.xdg.set_popup_stack(&stack);
|
||||||
|
let user = Rc::new(Popup {
|
||||||
|
parent: slf.clone(),
|
||||||
|
popup: popup.clone(),
|
||||||
|
stack,
|
||||||
|
stack_link: Default::default(),
|
||||||
|
});
|
||||||
|
popup.parent.set(Some(user.clone()));
|
||||||
|
self.popups.set(popup.id, user);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ack_configure(&self, req: AckConfigure, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn ack_configure(&self, _req: AckConfigure, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
self.acked_serial.set(Some(req.serial));
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
if self.popups.is_not_empty() {
|
||||||
|
return Err(ZwlrLayerSurfaceV1Error::HasPopups);
|
||||||
|
}
|
||||||
self.destroy_node();
|
self.destroy_node();
|
||||||
self.client.remove_obj(self)?;
|
self.client.remove_obj(self)?;
|
||||||
self.surface.unset_ext();
|
self.surface.unset_ext();
|
||||||
|
|
@ -237,18 +317,77 @@ impl ZwlrLayerSurfaceV1RequestHandler for ZwlrLayerSurfaceV1 {
|
||||||
}
|
}
|
||||||
let mut pending = self.pending();
|
let mut pending = self.pending();
|
||||||
pending.layer = Some(req.layer);
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ZwlrLayerSurfaceV1 {
|
impl ZwlrLayerSurfaceV1 {
|
||||||
fn pre_commit(&self, pending: &mut PendingState) -> Result<(), ZwlrLayerSurfaceV1Error> {
|
pub fn exclusive_size(&self) -> ExclusiveSize {
|
||||||
let Some(global) = self.output.get() else {
|
self.exclusive_size.get()
|
||||||
return Ok(());
|
}
|
||||||
|
|
||||||
|
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 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() {
|
if let Some(size) = pending.size.take() {
|
||||||
self.size.set(size);
|
self.size.set(size);
|
||||||
}
|
}
|
||||||
|
|
@ -267,84 +406,152 @@ impl ZwlrLayerSurfaceV1 {
|
||||||
if let Some(layer) = pending.layer.take() {
|
if let Some(layer) = pending.layer.take() {
|
||||||
self.layer.set(layer);
|
self.layer.set(layer);
|
||||||
}
|
}
|
||||||
{
|
if let Some(edge) = pending.exclusive_edge.take() {
|
||||||
let (mut width, mut height) = self.size.get();
|
self.exclusive_edge.set(Some(edge));
|
||||||
let anchor = self.anchor.get();
|
}
|
||||||
if width == 0 {
|
let anchor = self.anchor.get();
|
||||||
if !anchor.contains(LEFT | RIGHT) {
|
let (width, height) = self.size.get();
|
||||||
return Err(ZwlrLayerSurfaceV1Error::WidthZero);
|
if width == 0 && !anchor.contains(LEFT | RIGHT) {
|
||||||
}
|
return Err(ZwlrLayerSurfaceV1Error::WidthZero);
|
||||||
send_configure = true;
|
}
|
||||||
width = global.position().width();
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn output_position(&self) -> Rect {
|
fn configure(&self) {
|
||||||
self.output_pos.get()
|
let Some(node) = self.output.node() else {
|
||||||
}
|
|
||||||
|
|
||||||
pub fn position(&self) -> Rect {
|
|
||||||
self.pos.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compute_position(&self) {
|
|
||||||
let Some(global) = self.output.get() else {
|
|
||||||
return;
|
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();
|
let mut anchor = self.anchor.get();
|
||||||
if anchor == 0 {
|
if anchor == 0 {
|
||||||
anchor = LEFT | RIGHT | TOP | BOTTOM;
|
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 x1 = 0;
|
||||||
let mut y1 = 0;
|
let mut y1 = 0;
|
||||||
if anchor.contains(LEFT) {
|
if anchor.contains(LEFT | RIGHT) {
|
||||||
if anchor.contains(RIGHT) {
|
x1 = (owidth - width - ml - mr) / 2;
|
||||||
x1 += (opos.width() - width) / 2;
|
} else if anchor.contains(LEFT) {
|
||||||
}
|
x1 = ml;
|
||||||
} else if anchor.contains(RIGHT) {
|
} else if anchor.contains(RIGHT) {
|
||||||
x1 += opos.width() - width;
|
x1 = owidth - width - mr;
|
||||||
}
|
}
|
||||||
if anchor.contains(TOP) {
|
if anchor.contains(TOP | BOTTOM) {
|
||||||
if anchor.contains(BOTTOM) {
|
y1 = (oheight - height - mt - mb) / 2;
|
||||||
y1 += (opos.height() - height) / 2;
|
} else if anchor.contains(TOP) {
|
||||||
}
|
y1 = mt;
|
||||||
} else if anchor.contains(BOTTOM) {
|
} 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();
|
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) {
|
pub fn destroy_node(&self) {
|
||||||
self.link.set(None);
|
self.link.set(None);
|
||||||
self.mapped.set(false);
|
self.mapped.set(false);
|
||||||
self.surface.destroy_node();
|
self.surface.destroy_node();
|
||||||
self.seat_state.destroy_node(self);
|
self.seat_state.destroy_node(self);
|
||||||
self.client.state.tree_changed();
|
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 {
|
if !buffer_is_some {
|
||||||
self.destroy_node();
|
self.destroy_node();
|
||||||
} else {
|
} else {
|
||||||
let pos = self.pos.get();
|
if self.surface.extents.get().size() != self.pos.get().size() {
|
||||||
let (width, height) = self.size.get();
|
|
||||||
if width != pos.width() || height != pos.height() {
|
|
||||||
self.compute_position();
|
self.compute_position();
|
||||||
}
|
}
|
||||||
|
self.update_exclusive_size();
|
||||||
}
|
}
|
||||||
} else if buffer_is_some {
|
} else if buffer_is_some {
|
||||||
let layer = &output.layers[self.layer.get() as usize];
|
let layer = &output.layers[self.layer.get() as usize];
|
||||||
self.link.set(Some(layer.add_last(self.clone())));
|
self.link.set(Some(layer.add_last(self.clone())));
|
||||||
self.mapped.set(true);
|
self.mapped.set(true);
|
||||||
self.compute_position();
|
self.compute_position();
|
||||||
|
self.update_exclusive_size();
|
||||||
}
|
}
|
||||||
if self.mapped.get() != was_mapped {
|
if self.mapped.get() != was_mapped {
|
||||||
output.update_visible();
|
output.update_visible();
|
||||||
|
|
@ -444,7 +651,8 @@ impl Node for ZwlrLayerSurfaceV1 {
|
||||||
tree: &mut Vec<FoundNode>,
|
tree: &mut Vec<FoundNode>,
|
||||||
_usecase: FindTreeUsecase,
|
_usecase: FindTreeUsecase,
|
||||||
) -> FindTreeResult {
|
) -> 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>) {
|
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! {
|
object_base! {
|
||||||
self = ZwlrLayerSurfaceV1;
|
self = ZwlrLayerSurfaceV1;
|
||||||
version = self.shell.version;
|
version = self.shell.version;
|
||||||
|
|
@ -482,10 +733,22 @@ pub enum ZwlrLayerSurfaceV1Error {
|
||||||
UnknownLayer(u32),
|
UnknownLayer(u32),
|
||||||
#[error("Surface size must not be larger than 65535x65535")]
|
#[error("Surface size must not be larger than 65535x65535")]
|
||||||
ExcessiveSize,
|
ExcessiveSize,
|
||||||
|
#[error("Margin must not be larger than 65535")]
|
||||||
|
ExcessiveMargin,
|
||||||
#[error("Unknown anchor {0}")]
|
#[error("Unknown anchor {0}")]
|
||||||
UnknownAnchor(u32),
|
UnknownAnchor(u32),
|
||||||
#[error("Unknown keyboard interactivity {0}")]
|
#[error("Unknown keyboard interactivity {0}")]
|
||||||
UnknownKi(u32),
|
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, WlSurfaceError);
|
||||||
efrom!(ZwlrLayerSurfaceV1Error, ClientError);
|
efrom!(ZwlrLayerSurfaceV1Error, ClientError);
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ impl Global for ZwlrLayerShellV1Global {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn version(&self) -> u32 {
|
fn version(&self) -> u32 {
|
||||||
4
|
5
|
||||||
}
|
}
|
||||||
|
|
||||||
fn required_caps(&self) -> ClientCaps {
|
fn required_caps(&self) -> ClientCaps {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use {
|
||||||
ifs::{wl_buffer::WlBuffer, zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1},
|
ifs::{wl_buffer::WlBuffer, zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::Object,
|
object::Object,
|
||||||
utils::errorfmt::ErrorFmt,
|
utils::{errorfmt::ErrorFmt, hash_map_ext::HashMapExt},
|
||||||
video::dmabuf::{DmaBuf, DmaBufPlane, PlaneVec, MAX_PLANES},
|
video::dmabuf::{DmaBuf, DmaBufPlane, PlaneVec, MAX_PLANES},
|
||||||
wire::{zwp_linux_buffer_params_v1::*, WlBufferId, ZwpLinuxBufferParamsV1Id},
|
wire::{zwp_linux_buffer_params_v1::*, WlBufferId, ZwpLinuxBufferParamsV1Id},
|
||||||
},
|
},
|
||||||
|
|
@ -90,7 +90,7 @@ impl ZwpLinuxBufferParamsV1 {
|
||||||
modifier,
|
modifier,
|
||||||
planes: PlaneVec::new(),
|
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);
|
planes.sort_by_key(|a| a.plane_idx);
|
||||||
for (i, p) in planes.into_iter().enumerate() {
|
for (i, p) in planes.into_iter().enumerate() {
|
||||||
if p.plane_idx as usize != i {
|
if p.plane_idx as usize != i {
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ use {
|
||||||
bitfield::Bitfield,
|
bitfield::Bitfield,
|
||||||
buffd::{BufFdIn, BufFdOut, MsgFormatter, MsgParser, OutBuffer, OutBufferSwapchain},
|
buffd::{BufFdIn, BufFdOut, MsgFormatter, MsgParser, OutBuffer, OutBufferSwapchain},
|
||||||
copyhashmap::CopyHashMap,
|
copyhashmap::CopyHashMap,
|
||||||
|
hash_map_ext::HashMapExt,
|
||||||
stack::Stack,
|
stack::Stack,
|
||||||
vec_ext::VecExt,
|
vec_ext::VecExt,
|
||||||
},
|
},
|
||||||
|
|
@ -105,7 +106,7 @@ impl TestTransport {
|
||||||
pub fn kill(&self) {
|
pub fn kill(&self) {
|
||||||
self.outgoing.take();
|
self.outgoing.take();
|
||||||
self.incoming.take();
|
self.incoming.take();
|
||||||
for (_, object) in self.objects.lock().drain() {
|
for object in self.objects.lock().drain_values() {
|
||||||
object.on_remove(self);
|
object.on_remove(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ mod leaks {
|
||||||
crate::{
|
crate::{
|
||||||
client::ClientId,
|
client::ClientId,
|
||||||
utils::{
|
utils::{
|
||||||
|
hash_map_ext::HashMapExt,
|
||||||
ptr_ext::{MutPtrExt, PtrExt},
|
ptr_ext::{MutPtrExt, PtrExt},
|
||||||
windows::WindowsExt,
|
windows::WindowsExt,
|
||||||
},
|
},
|
||||||
|
|
@ -157,7 +158,7 @@ mod leaks {
|
||||||
if map.is_empty() {
|
if map.is_empty() {
|
||||||
log::info!("No leaks");
|
log::info!("No leaks");
|
||||||
}
|
}
|
||||||
for (_, mut objs) in map.drain() {
|
for mut objs in map.drain_values() {
|
||||||
if objs.len() == 0 {
|
if objs.len() == 0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ use {
|
||||||
clonecell::CloneCell,
|
clonecell::CloneCell,
|
||||||
copyhashmap::CopyHashMap,
|
copyhashmap::CopyHashMap,
|
||||||
errorfmt::ErrorFmt,
|
errorfmt::ErrorFmt,
|
||||||
|
hash_map_ext::HashMapExt,
|
||||||
numcell::NumCell,
|
numcell::NumCell,
|
||||||
oserror::OsError,
|
oserror::OsError,
|
||||||
xrd::xrd,
|
xrd::xrd,
|
||||||
|
|
@ -122,7 +123,7 @@ impl PwCon {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kill(&self) {
|
pub fn kill(&self) {
|
||||||
for (_, obj) in self.objects.lock().drain() {
|
for obj in self.objects.lock().drain_values() {
|
||||||
obj.break_loops();
|
obj.break_loops();
|
||||||
}
|
}
|
||||||
self.io.shutdown();
|
self.io.shutdown();
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use {
|
||||||
},
|
},
|
||||||
utils::{
|
utils::{
|
||||||
bitflags::BitflagsExt, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
bitflags::BitflagsExt, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
||||||
errorfmt::ErrorFmt, oserror::OsError,
|
errorfmt::ErrorFmt, hash_map_ext::HashMapExt, oserror::OsError,
|
||||||
},
|
},
|
||||||
video::drm::Drm,
|
video::drm::Drm,
|
||||||
wire::{
|
wire::{
|
||||||
|
|
@ -191,7 +191,7 @@ impl UsrJayRenderCtxOwner for PortalDisplay {
|
||||||
impl UsrConOwner for PortalDisplay {
|
impl UsrConOwner for PortalDisplay {
|
||||||
fn killed(&self) {
|
fn killed(&self) {
|
||||||
log::info!("Removing display {}", self.id);
|
log::info!("Removing display {}", self.id);
|
||||||
for (_, sc) in self.screencasts.lock().drain() {
|
for sc in self.screencasts.lock().drain_values() {
|
||||||
sc.kill();
|
sc.kill();
|
||||||
}
|
}
|
||||||
self.windows.clear();
|
self.windows.clear();
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ use {
|
||||||
utils::{
|
utils::{
|
||||||
clonecell::{CloneCell, UnsafeCellCloneSafe},
|
clonecell::{CloneCell, UnsafeCellCloneSafe},
|
||||||
copyhashmap::CopyHashMap,
|
copyhashmap::CopyHashMap,
|
||||||
|
hash_map_ext::HashMapExt,
|
||||||
},
|
},
|
||||||
video::dmabuf::{DmaBuf, PlaneVec},
|
video::dmabuf::{DmaBuf, PlaneVec},
|
||||||
wire::jay_screencast::Ready,
|
wire::jay_screencast::Ready,
|
||||||
|
|
@ -267,7 +268,7 @@ impl ScreencastSession {
|
||||||
ScreencastPhase::Terminated => {}
|
ScreencastPhase::Terminated => {}
|
||||||
ScreencastPhase::Selecting(s) => {
|
ScreencastPhase::Selecting(s) => {
|
||||||
s.core.reply.err("Session has been terminated");
|
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);
|
gui.kill(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
theme::Color,
|
theme::Color,
|
||||||
utils::copyhashmap::CopyHashMap,
|
utils::{copyhashmap::CopyHashMap, hash_map_ext::HashMapExt},
|
||||||
wl_usr::usr_ifs::{
|
wl_usr::usr_ifs::{
|
||||||
usr_jay_select_toplevel::UsrJaySelectToplevelOwner,
|
usr_jay_select_toplevel::UsrJaySelectToplevelOwner,
|
||||||
usr_jay_select_workspace::UsrJaySelectWorkspaceOwner, usr_jay_toplevel::UsrJayToplevel,
|
usr_jay_select_workspace::UsrJaySelectWorkspaceOwner, usr_jay_toplevel::UsrJayToplevel,
|
||||||
|
|
@ -53,7 +53,7 @@ enum ButtonRole {
|
||||||
|
|
||||||
impl SelectionGui {
|
impl SelectionGui {
|
||||||
pub fn kill(&self, upwards: bool) {
|
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);
|
surface.overlay.data.kill(false);
|
||||||
}
|
}
|
||||||
if let ScreencastPhase::Selecting(s) = self.screencast_session.phase.get() {
|
if let ScreencastPhase::Selecting(s) = self.screencast_session.phase.get() {
|
||||||
|
|
@ -159,7 +159,7 @@ impl ButtonOwner for StaticButton {
|
||||||
ScreencastPhase::Selecting(selecting) => selecting,
|
ScreencastPhase::Selecting(selecting) => selecting,
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
for (_, gui) in selecting.guis.lock().drain() {
|
for gui in selecting.guis.lock().drain_values() {
|
||||||
gui.kill(false);
|
gui.kill(false);
|
||||||
}
|
}
|
||||||
let dpy = &self.surface.output.dpy;
|
let dpy = &self.surface.output.dpy;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use {
|
||||||
theme::Color,
|
theme::Color,
|
||||||
utils::{
|
utils::{
|
||||||
asyncevent::AsyncEvent, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
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},
|
video::gbm::{GbmBo, GBM_BO_USE_RENDERING},
|
||||||
wire::{
|
wire::{
|
||||||
|
|
@ -671,7 +671,7 @@ impl WindowData {
|
||||||
owner.kill(upwards);
|
owner.kill(upwards);
|
||||||
}
|
}
|
||||||
self.render_task.take();
|
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());
|
pb.params.con.remove_obj(pb.params.deref());
|
||||||
}
|
}
|
||||||
for buf in self.bufs.borrow_mut().drain(..) {
|
for buf in self.bufs.borrow_mut().drain(..) {
|
||||||
|
|
@ -689,7 +689,7 @@ impl WindowData {
|
||||||
|
|
||||||
pub fn allocate_buffers(self: &Rc<Self>) {
|
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());
|
buf.params.con.remove_obj(buf.params.deref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,11 @@ impl Rect {
|
||||||
Self::new(x1, y1, x1 + width, y1 + height)
|
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 {
|
pub fn union(&self, other: Self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
raw: RectRaw {
|
raw: RectRaw {
|
||||||
|
|
|
||||||
|
|
@ -103,12 +103,8 @@ impl Renderer<'_> {
|
||||||
macro_rules! render_layer {
|
macro_rules! render_layer {
|
||||||
($layer:expr) => {
|
($layer:expr) => {
|
||||||
for ls in $layer.iter() {
|
for ls in $layer.iter() {
|
||||||
let pos = ls.position();
|
let pos = ls.output_extents();
|
||||||
self.render_layer_surface(
|
self.render_layer_surface(ls.deref(), x + pos.x1(), y + pos.y1());
|
||||||
ls.deref(),
|
|
||||||
x + pos.x1() - opos.x1(),
|
|
||||||
y + pos.y1() - opos.y1(),
|
|
||||||
);
|
|
||||||
self.base.ops.push(GfxApiOpt::Sync);
|
self.base.ops.push(GfxApiOpt::Sync);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -124,10 +120,14 @@ impl Renderer<'_> {
|
||||||
} else {
|
} else {
|
||||||
render_layer!(output.layers[0]);
|
render_layer!(output.layers[0]);
|
||||||
render_layer!(output.layers[1]);
|
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();
|
let c = theme.colors.bar_background.get();
|
||||||
self.base.fill_boxes2(
|
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,
|
&c,
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
|
|
@ -189,18 +189,24 @@ impl Renderer<'_> {
|
||||||
self.render_workspace(&ws, x, y + th + 1);
|
self.render_workspace(&ws, x, y + th + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for stacked in self.state.root.stacked.iter() {
|
macro_rules! render_stacked {
|
||||||
if stacked.node_visible() {
|
($stack:expr) => {
|
||||||
self.base.ops.push(GfxApiOpt::Sync);
|
for stacked in $stack.iter() {
|
||||||
let pos = stacked.node_absolute_position();
|
if stacked.node_visible() {
|
||||||
if pos.intersects(&opos) {
|
self.base.ops.push(GfxApiOpt::Sync);
|
||||||
let (x, y) = opos.translate(pos.x1(), pos.y1());
|
let pos = stacked.node_absolute_position();
|
||||||
stacked.node_render(self, x, y, None);
|
if pos.intersects(&opos) {
|
||||||
|
let (x, y) = opos.translate(pos.x1(), pos.y1());
|
||||||
|
stacked.node_render(self, x, y, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
render_stacked!(self.state.root.stacked);
|
||||||
render_layer!(output.layers[2]);
|
render_layer!(output.layers[2]);
|
||||||
render_layer!(output.layers[3]);
|
render_layer!(output.layers[3]);
|
||||||
|
render_stacked!(self.state.root.stacked_above_layers);
|
||||||
if let Some(ws) = output.workspace.get() {
|
if let Some(ws) = output.workspace.get() {
|
||||||
if ws.render_highlight.get() > 0 {
|
if ws.render_highlight.get() > 0 {
|
||||||
let color = self.state.theme.colors.highlight.get();
|
let color = self.state.theme.colors.highlight.get();
|
||||||
|
|
@ -539,8 +545,7 @@ impl Renderer<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_layer_surface(&mut self, surface: &ZwlrLayerSurfaceV1, x: i32, y: i32) {
|
pub fn render_layer_surface(&mut self, surface: &ZwlrLayerSurfaceV1, x: i32, y: i32) {
|
||||||
let body = surface.position().at_point(x, y);
|
let (dx, dy) = surface.surface.extents.get().position();
|
||||||
let body = self.base.scale_rect(body);
|
self.render_surface(&surface.surface, x - dx, y - dy, None);
|
||||||
self.render_surface(&surface.surface, x, y, Some(&body));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use {
|
||||||
async_engine::SpawnedFuture,
|
async_engine::SpawnedFuture,
|
||||||
client::ClientCaps,
|
client::ClientCaps,
|
||||||
state::State,
|
state::State,
|
||||||
utils::{copyhashmap::CopyHashMap, errorfmt::ErrorFmt},
|
utils::{copyhashmap::CopyHashMap, errorfmt::ErrorFmt, hash_map_ext::HashMapExt},
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
cell::Cell,
|
cell::Cell,
|
||||||
|
|
@ -36,7 +36,7 @@ struct Acceptor {
|
||||||
|
|
||||||
impl SecurityContextAcceptors {
|
impl SecurityContextAcceptors {
|
||||||
pub fn clear(&self) {
|
pub fn clear(&self) {
|
||||||
for (_, acceptor) in self.acceptors.lock().drain() {
|
for acceptor in self.acceptors.lock().drain_values() {
|
||||||
acceptor.kill();
|
acceptor.kill();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
src/state.rs
10
src/state.rs
|
|
@ -68,8 +68,8 @@ use {
|
||||||
utils::{
|
utils::{
|
||||||
activation_token::ActivationToken, asyncevent::AsyncEvent, bindings::Bindings,
|
activation_token::ActivationToken, asyncevent::AsyncEvent, bindings::Bindings,
|
||||||
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, fdcloser::FdCloser,
|
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, fdcloser::FdCloser,
|
||||||
linkedlist::LinkedList, numcell::NumCell, queue::AsyncQueue, refcounted::RefCounted,
|
hash_map_ext::HashMapExt, linkedlist::LinkedList, numcell::NumCell, queue::AsyncQueue,
|
||||||
run_toplevel::RunToplevel,
|
refcounted::RefCounted, run_toplevel::RunToplevel,
|
||||||
},
|
},
|
||||||
video::{
|
video::{
|
||||||
dmabuf::DmaBufIds,
|
dmabuf::DmaBufIds,
|
||||||
|
|
@ -743,11 +743,11 @@ impl State {
|
||||||
self.xwayland.queue.clear();
|
self.xwayland.queue.clear();
|
||||||
self.idle.inhibitors.clear();
|
self.idle.inhibitors.clear();
|
||||||
self.idle.change.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.handler.take();
|
||||||
drm_dev.connectors.clear();
|
drm_dev.connectors.clear();
|
||||||
}
|
}
|
||||||
for (_, connector) in self.connectors.lock().drain() {
|
for connector in self.connectors.lock().drain_values() {
|
||||||
connector.handler.take();
|
connector.handler.take();
|
||||||
connector.async_event.clear();
|
connector.async_event.clear();
|
||||||
}
|
}
|
||||||
|
|
@ -769,7 +769,7 @@ impl State {
|
||||||
self.toplevel_lists.clear();
|
self.toplevel_lists.clear();
|
||||||
self.security_context_acceptors.clear();
|
self.security_context_acceptors.clear();
|
||||||
self.slow_clients.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();
|
h.async_event.clear();
|
||||||
}
|
}
|
||||||
self.backend_events.clear();
|
self.backend_events.clear();
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use {
|
||||||
ifs::wl_output::{OutputId, PersistentOutputState, WlOutputGlobal},
|
ifs::wl_output::{OutputId, PersistentOutputState, WlOutputGlobal},
|
||||||
state::{ConnectorData, OutputData, State},
|
state::{ConnectorData, OutputData, State},
|
||||||
tree::{move_ws_to_output, OutputNode, OutputRenderData, WsMoveConfig},
|
tree::{move_ws_to_output, OutputNode, OutputRenderData, WsMoveConfig},
|
||||||
utils::{asyncevent::AsyncEvent, clonecell::CloneCell},
|
utils::{asyncevent::AsyncEvent, clonecell::CloneCell, hash_map_ext::HashMapExt},
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
|
|
@ -147,6 +147,10 @@ impl ConnectorHandler {
|
||||||
seat_state: Default::default(),
|
seat_state: Default::default(),
|
||||||
global: global.clone(),
|
global: global.clone(),
|
||||||
layers: Default::default(),
|
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 {
|
render_data: RefCell::new(OutputRenderData {
|
||||||
active_workspace: None,
|
active_workspace: None,
|
||||||
underline: Default::default(),
|
underline: Default::default(),
|
||||||
|
|
@ -169,6 +173,7 @@ impl ConnectorHandler {
|
||||||
hardware_cursor_needs_render: Cell::new(false),
|
hardware_cursor_needs_render: Cell::new(false),
|
||||||
screencopies: Default::default(),
|
screencopies: Default::default(),
|
||||||
});
|
});
|
||||||
|
on.update_rects();
|
||||||
self.state
|
self.state
|
||||||
.add_output_scale(on.global.persistent.scale.get());
|
.add_output_scale(on.global.persistent.scale.get());
|
||||||
let output_data = Rc::new(OutputData {
|
let output_data = Rc::new(OutputData {
|
||||||
|
|
@ -244,14 +249,14 @@ impl ConnectorHandler {
|
||||||
config.connector_disconnected(self.id);
|
config.connector_disconnected(self.id);
|
||||||
}
|
}
|
||||||
global.clear();
|
global.clear();
|
||||||
for (_, jo) in on.jay_outputs.lock().drain() {
|
for jo in on.jay_outputs.lock().drain_values() {
|
||||||
jo.send_destroyed();
|
jo.send_destroyed();
|
||||||
}
|
}
|
||||||
let screencasts: Vec<_> = on.screencasts.lock().values().cloned().collect();
|
let screencasts: Vec<_> = on.screencasts.lock().values().cloned().collect();
|
||||||
for sc in screencasts {
|
for sc in screencasts {
|
||||||
sc.do_destroy();
|
sc.do_destroy();
|
||||||
}
|
}
|
||||||
for (_, sc) in on.screencopies.lock().drain() {
|
for sc in on.screencopies.lock().drain_values() {
|
||||||
sc.send_failed();
|
sc.send_failed();
|
||||||
}
|
}
|
||||||
global.destroyed.set(true);
|
global.destroyed.set(true);
|
||||||
|
|
@ -310,7 +315,7 @@ impl ConnectorHandler {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let withdraw = || {
|
let withdraw = || {
|
||||||
for (_, con) in output_data.lease_connectors.lock().drain() {
|
for con in output_data.lease_connectors.lock().drain_values() {
|
||||||
con.send_withdrawn();
|
con.send_withdrawn();
|
||||||
if !con.device.destroyed.get() {
|
if !con.device.destroyed.get() {
|
||||||
con.device.send_done();
|
con.device.send_done();
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ use {
|
||||||
clonecell::CloneCell,
|
clonecell::CloneCell,
|
||||||
double_click_state::DoubleClickState,
|
double_click_state::DoubleClickState,
|
||||||
errorfmt::ErrorFmt,
|
errorfmt::ErrorFmt,
|
||||||
|
hash_map_ext::HashMapExt,
|
||||||
linkedlist::{LinkedList, LinkedNode, NodeRef},
|
linkedlist::{LinkedList, LinkedNode, NodeRef},
|
||||||
numcell::NumCell,
|
numcell::NumCell,
|
||||||
rc_eq::rc_eq,
|
rc_eq::rc_eq,
|
||||||
|
|
@ -1613,7 +1614,7 @@ impl ToplevelNodeBase for ContainerNode {
|
||||||
fn tl_destroy_impl(&self) {
|
fn tl_destroy_impl(&self) {
|
||||||
mem::take(self.cursors.borrow_mut().deref_mut());
|
mem::take(self.cursors.borrow_mut().deref_mut());
|
||||||
let mut cn = self.child_nodes.borrow_mut();
|
let mut cn = self.child_nodes.borrow_mut();
|
||||||
for (_, n) in cn.drain() {
|
for n in cn.drain_values() {
|
||||||
n.node.tl_destroy();
|
n.node.tl_destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ pub struct DisplayNode {
|
||||||
pub id: NodeId,
|
pub id: NodeId,
|
||||||
pub extents: Cell<Rect>,
|
pub extents: Cell<Rect>,
|
||||||
pub outputs: CopyHashMap<ConnectorId, Rc<OutputNode>>,
|
pub outputs: CopyHashMap<ConnectorId, Rc<OutputNode>>,
|
||||||
pub stacked: LinkedList<Rc<dyn StackedNode>>,
|
pub stacked: Rc<LinkedList<Rc<dyn StackedNode>>>,
|
||||||
|
pub stacked_above_layers: Rc<LinkedList<Rc<dyn StackedNode>>>,
|
||||||
pub seat_state: NodeSeatState,
|
pub seat_state: NodeSeatState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,6 +32,7 @@ impl DisplayNode {
|
||||||
extents: Default::default(),
|
extents: Default::default(),
|
||||||
outputs: Default::default(),
|
outputs: Default::default(),
|
||||||
stacked: Default::default(),
|
stacked: Default::default(),
|
||||||
|
stacked_above_layers: Default::default(),
|
||||||
seat_state: Default::default(),
|
seat_state: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ use {
|
||||||
},
|
},
|
||||||
wl_surface::{
|
wl_surface::{
|
||||||
ext_session_lock_surface_v1::ExtSessionLockSurfaceV1,
|
ext_session_lock_surface_v1::ExtSessionLockSurfaceV1,
|
||||||
zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, SurfaceSendPreferredScaleVisitor,
|
zwlr_layer_surface_v1::{ExclusiveSize, ZwlrLayerSurfaceV1},
|
||||||
SurfaceSendPreferredTransformVisitor,
|
SurfaceSendPreferredScaleVisitor, SurfaceSendPreferredTransformVisitor,
|
||||||
},
|
},
|
||||||
zwlr_layer_shell_v1::{BACKGROUND, BOTTOM, OVERLAY, TOP},
|
zwlr_layer_shell_v1::{BACKGROUND, BOTTOM, OVERLAY, TOP},
|
||||||
zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1,
|
zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1,
|
||||||
|
|
@ -32,11 +32,12 @@ use {
|
||||||
time::Time,
|
time::Time,
|
||||||
tree::{
|
tree::{
|
||||||
walker::NodeVisitor, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node,
|
walker::NodeVisitor, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node,
|
||||||
NodeId, WorkspaceNode,
|
NodeId, StackedNode, WorkspaceNode,
|
||||||
},
|
},
|
||||||
utils::{
|
utils::{
|
||||||
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt,
|
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt,
|
||||||
linkedlist::LinkedList, scroller::Scroller, transform_ext::TransformExt,
|
hash_map_ext::HashMapExt, linkedlist::LinkedList, scroller::Scroller,
|
||||||
|
transform_ext::TransformExt,
|
||||||
},
|
},
|
||||||
wire::{JayOutputId, JayScreencastId, ZwlrScreencopyFrameV1Id},
|
wire::{JayOutputId, JayScreencastId, ZwlrScreencopyFrameV1Id},
|
||||||
},
|
},
|
||||||
|
|
@ -46,7 +47,7 @@ use {
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
ops::{Deref, Sub},
|
ops::Deref,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -60,6 +61,10 @@ pub struct OutputNode {
|
||||||
pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
|
pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
|
||||||
pub seat_state: NodeSeatState,
|
pub seat_state: NodeSeatState,
|
||||||
pub layers: [LinkedList<Rc<ZwlrLayerSurfaceV1>>; 4],
|
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 render_data: RefCell<OutputRenderData>,
|
||||||
pub state: Rc<State>,
|
pub state: Rc<State>,
|
||||||
pub is_dummy: bool,
|
pub is_dummy: bool,
|
||||||
|
|
@ -93,6 +98,26 @@ pub async fn output_render_data(state: Rc<State>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutputNode {
|
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>) {
|
pub fn add_screencast(&self, sc: &Rc<JayScreencast>) {
|
||||||
self.screencasts.set((sc.client.id, sc.id), sc.clone());
|
self.screencasts.set((sc.client.id, sc.id), sc.clone());
|
||||||
self.screencast_changed();
|
self.screencast_changed();
|
||||||
|
|
@ -140,7 +165,7 @@ impl OutputNode {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let now = Time::now().unwrap();
|
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() {
|
let wl_buffer = match capture.buffer.take() {
|
||||||
Some(b) => b,
|
Some(b) => b,
|
||||||
_ => {
|
_ => {
|
||||||
|
|
@ -221,9 +246,9 @@ impl OutputNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_spaces_changed(self: &Rc<Self>) {
|
pub fn on_spaces_changed(self: &Rc<Self>) {
|
||||||
self.schedule_update_render_data();
|
self.update_rects();
|
||||||
if let Some(c) = self.workspace.get() {
|
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 _;
|
texture_height = (th as f64 * scale).round() as _;
|
||||||
}
|
}
|
||||||
let active_id = self.workspace.get().map(|w| w.id);
|
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();
|
rd.underline = Rect::new_sized(0, th, output_width, 1).unwrap();
|
||||||
for ws in self.workspaces.iter() {
|
for ws in self.workspaces.iter() {
|
||||||
let old_tex = ws.title_texture.take();
|
let old_tex = ws.title_texture.take();
|
||||||
|
|
@ -429,7 +454,7 @@ impl OutputNode {
|
||||||
if let Some(fs) = ws.fullscreen.get() {
|
if let Some(fs) = ws.fullscreen.get() {
|
||||||
fs.tl_change_extents(&self.global.pos.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 {
|
for seat in seats {
|
||||||
ws.clone().node_do_focus(&seat, Direction::Unspecified);
|
ws.clone().node_do_focus(&seat, Direction::Unspecified);
|
||||||
}
|
}
|
||||||
|
|
@ -477,16 +502,29 @@ impl OutputNode {
|
||||||
ws
|
ws
|
||||||
}
|
}
|
||||||
|
|
||||||
fn workspace_rect(&self) -> Rect {
|
pub fn update_rects(self: &Rc<Self>) {
|
||||||
let rect = self.global.pos.get();
|
let rect = self.global.pos.get();
|
||||||
let th = self.state.theme.sizes.title_height.get();
|
let th = self.state.theme.sizes.title_height.get();
|
||||||
Rect::new_sized(
|
let exclusive = self.exclusive_zones.get();
|
||||||
rect.x1(),
|
let y1 = rect.y1() + exclusive.top;
|
||||||
rect.y1() + th + 1,
|
let x2 = rect.x2() - exclusive.right;
|
||||||
rect.width(),
|
let y2 = rect.y2() - exclusive.bottom;
|
||||||
rect.height().sub(th + 1).max(0),
|
let x1 = rect.x1() + exclusive.left;
|
||||||
)
|
let width = (x2 - x1).max(0);
|
||||||
.unwrap()
|
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) {
|
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.persistent.pos.set((rect.x1(), rect.y1()));
|
||||||
self.global.pos.set(*rect);
|
self.global.pos.set(*rect);
|
||||||
self.state.root.update_extents();
|
self.state.root.update_extents();
|
||||||
self.schedule_update_render_data();
|
self.update_rects();
|
||||||
if let Some(ls) = self.lock_surface.get() {
|
if let Some(ls) = self.lock_surface.get() {
|
||||||
ls.change_extents(*rect);
|
ls.change_extents(*rect);
|
||||||
}
|
}
|
||||||
|
|
@ -553,11 +591,11 @@ impl OutputNode {
|
||||||
if let Some(fs) = c.fullscreen.get() {
|
if let Some(fs) = c.fullscreen.get() {
|
||||||
fs.tl_change_extents(rect);
|
fs.tl_change_extents(rect);
|
||||||
}
|
}
|
||||||
c.change_extents(&self.workspace_rect());
|
c.change_extents(&self.workspace_rect.get());
|
||||||
}
|
}
|
||||||
for layer in &self.layers {
|
for layer in &self.layers {
|
||||||
for surface in layer.iter() {
|
for surface in layer.iter() {
|
||||||
surface.compute_position();
|
surface.output_resized();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.global.send_mode();
|
self.global.send_mode();
|
||||||
|
|
@ -567,6 +605,46 @@ impl OutputNode {
|
||||||
self.state.tree_changed();
|
self.state.tree_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_stacked_at(
|
||||||
|
&self,
|
||||||
|
stack: &LinkedList<Rc<dyn StackedNode>>,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
tree: &mut Vec<FoundNode>,
|
||||||
|
usecase: FindTreeUsecase,
|
||||||
|
) -> FindTreeResult {
|
||||||
|
if stack.is_empty() {
|
||||||
|
return FindTreeResult::Other;
|
||||||
|
}
|
||||||
|
let (x_abs, y_abs) = self.global.pos.get().translate_inv(x, y);
|
||||||
|
for stacked in stack.rev_iter() {
|
||||||
|
let ext = stacked.node_absolute_position();
|
||||||
|
if !stacked.node_visible() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if stacked.stacked_absolute_position_constrains_input() && !ext.contains(x_abs, y_abs) {
|
||||||
|
// TODO: make constrain always true
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let (x, y) = ext.translate(x_abs, y_abs);
|
||||||
|
let idx = tree.len();
|
||||||
|
tree.push(FoundNode {
|
||||||
|
node: stacked.deref().clone().stacked_into_node(),
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
});
|
||||||
|
match stacked.node_find_tree_at(x, y, tree, usecase) {
|
||||||
|
FindTreeResult::AcceptsInput => {
|
||||||
|
return FindTreeResult::AcceptsInput;
|
||||||
|
}
|
||||||
|
FindTreeResult::Other => {
|
||||||
|
tree.truncate(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FindTreeResult::Other
|
||||||
|
}
|
||||||
|
|
||||||
pub fn find_layer_surface_at(
|
pub fn find_layer_surface_at(
|
||||||
&self,
|
&self,
|
||||||
x: i32,
|
x: i32,
|
||||||
|
|
@ -581,7 +659,7 @@ impl OutputNode {
|
||||||
let len = tree.len();
|
let len = tree.len();
|
||||||
for layer in layers.iter().copied() {
|
for layer in layers.iter().copied() {
|
||||||
for surface in self.layers[layer as usize].rev_iter() {
|
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) {
|
if pos.contains(x, y) {
|
||||||
let (x, y) = pos.translate(x, y);
|
let (x, y) = pos.translate(x, y);
|
||||||
if surface.node_find_tree_at(x, y, tree, usecase)
|
if surface.node_find_tree_at(x, y, tree, usecase)
|
||||||
|
|
@ -633,7 +711,7 @@ impl OutputNode {
|
||||||
macro_rules! set_layer_visible {
|
macro_rules! set_layer_visible {
|
||||||
($layer:expr, $visible:expr) => {
|
($layer:expr, $visible:expr) => {
|
||||||
for ls in $layer.iter() {
|
for ls in $layer.iter() {
|
||||||
ls.surface.set_visible($visible);
|
ls.set_visible($visible);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -641,7 +719,7 @@ impl OutputNode {
|
||||||
if let Some(ws) = self.workspace.get() {
|
if let Some(ws) = self.workspace.get() {
|
||||||
have_fullscreen = ws.fullscreen.is_some();
|
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[0], lower_visible);
|
||||||
set_layer_visible!(self.layers[1], lower_visible);
|
set_layer_visible!(self.layers[1], lower_visible);
|
||||||
if let Some(ws) = self.workspace.get() {
|
if let Some(ws) = self.workspace.get() {
|
||||||
|
|
@ -656,6 +734,7 @@ impl OutputNode {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
let (x, y) = self.non_exclusive_rect_rel.get().translate(x, y);
|
||||||
if y >= self.state.theme.sizes.title_height.get() {
|
if y >= self.state.theme.sizes.title_height.get() {
|
||||||
return;
|
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);
|
let res = self.find_layer_surface_at(x, y, &[OVERLAY, TOP], tree, usecase);
|
||||||
if res.accepts_input() {
|
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);
|
let res = self.find_stacked_at(&self.state.root.stacked, x, y, tree, usecase);
|
||||||
for stacked in self.state.root.stacked.rev_iter() {
|
if res.accepts_input() {
|
||||||
let ext = stacked.node_absolute_position();
|
return res;
|
||||||
if !stacked.node_visible() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if stacked.stacked_absolute_position_constrains_input()
|
|
||||||
&& !ext.contains(x_abs, y_abs)
|
|
||||||
{
|
|
||||||
// TODO: make constrain always true
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let (x, y) = ext.translate(x_abs, y_abs);
|
|
||||||
let idx = tree.len();
|
|
||||||
tree.push(FoundNode {
|
|
||||||
node: stacked.deref().clone().stacked_into_node(),
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
});
|
|
||||||
match stacked.node_find_tree_at(x, y, tree, usecase) {
|
|
||||||
FindTreeResult::AcceptsInput => {
|
|
||||||
return FindTreeResult::AcceptsInput;
|
|
||||||
}
|
|
||||||
FindTreeResult::Other => {
|
|
||||||
tree.truncate(idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut fullscreen = None;
|
let mut fullscreen = None;
|
||||||
|
|
@ -842,21 +904,33 @@ impl Node for OutputNode {
|
||||||
});
|
});
|
||||||
fs.tl_as_node().node_find_tree_at(x, y, tree, usecase)
|
fs.tl_as_node().node_find_tree_at(x, y, tree, usecase)
|
||||||
} else {
|
} else {
|
||||||
if y >= bar_height {
|
let mut search_layers = true;
|
||||||
y -= bar_height;
|
let non_exclusive_rect = self.non_exclusive_rect_rel.get();
|
||||||
let len = tree.len();
|
if non_exclusive_rect.contains(x, y) {
|
||||||
if let Some(ws) = self.workspace.get() {
|
let (x, y) = non_exclusive_rect.translate(x, y);
|
||||||
tree.push(FoundNode {
|
if y < bar_height {
|
||||||
node: ws.clone(),
|
search_layers = false;
|
||||||
x,
|
} else {
|
||||||
y,
|
if let Some(ws) = self.workspace.get() {
|
||||||
});
|
let y = y - bar_height;
|
||||||
ws.node_find_tree_at(x, y, tree, usecase);
|
let len = tree.len();
|
||||||
}
|
tree.push(FoundNode {
|
||||||
if tree.len() == len {
|
node: ws.clone(),
|
||||||
self.find_layer_surface_at(x, y, &[BOTTOM, BACKGROUND], tree, usecase);
|
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
|
FindTreeResult::AcceptsInput
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ use {
|
||||||
utils::{
|
utils::{
|
||||||
clonecell::CloneCell,
|
clonecell::CloneCell,
|
||||||
copyhashmap::CopyHashMap,
|
copyhashmap::CopyHashMap,
|
||||||
|
hash_map_ext::HashMapExt,
|
||||||
numcell::NumCell,
|
numcell::NumCell,
|
||||||
smallmap::SmallMap,
|
smallmap::SmallMap,
|
||||||
threshold_counter::ThresholdCounter,
|
threshold_counter::ThresholdCounter,
|
||||||
|
|
@ -289,16 +290,16 @@ impl ToplevelData {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy_node(&self, node: &dyn Node) {
|
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();
|
jay_tl.destroy();
|
||||||
}
|
}
|
||||||
for (_, screencast) in self.jay_screencasts.lock().drain() {
|
for screencast in self.jay_screencasts.lock().drain_values() {
|
||||||
screencast.do_destroy();
|
screencast.do_destroy();
|
||||||
}
|
}
|
||||||
self.identifier.set(toplevel_identifier());
|
self.identifier.set(toplevel_identifier());
|
||||||
{
|
{
|
||||||
let mut handles = self.handles.lock();
|
let mut handles = self.handles.lock();
|
||||||
for (_, handle) in handles.drain() {
|
for handle in handles.drain_values() {
|
||||||
handle.send_closed();
|
handle.send_closed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -264,9 +264,9 @@ impl Node for WorkspaceNode {
|
||||||
x,
|
x,
|
||||||
y,
|
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>) {
|
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 errorfmt;
|
||||||
pub mod fdcloser;
|
pub mod fdcloser;
|
||||||
pub mod gfx_api_ext;
|
pub mod gfx_api_ext;
|
||||||
|
pub mod hash_map_ext;
|
||||||
pub mod hex;
|
pub mod hex;
|
||||||
pub mod line_logger;
|
pub mod line_logger;
|
||||||
pub mod linkedlist;
|
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},
|
clonecell::{CloneCell, UnsafeCellCloneSafe},
|
||||||
copyhashmap::CopyHashMap,
|
copyhashmap::CopyHashMap,
|
||||||
errorfmt::ErrorFmt,
|
errorfmt::ErrorFmt,
|
||||||
|
hash_map_ext::HashMapExt,
|
||||||
linkedlist::{LinkedList, LinkedNode},
|
linkedlist::{LinkedList, LinkedNode},
|
||||||
oserror::OsError,
|
oserror::OsError,
|
||||||
},
|
},
|
||||||
|
|
@ -230,7 +231,7 @@ impl Drop for SyncObjCtx {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.inner.links.clear();
|
self.inner.links.clear();
|
||||||
let mut map = self.inner.handles.lock();
|
let mut map = self.inner.handles.lock();
|
||||||
for (_, handle) in map.drain() {
|
for handle in map.drain_values() {
|
||||||
destroy(&self.inner.drm, handle);
|
destroy(&self.inner.drm, handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use {
|
||||||
io_uring::IoUring,
|
io_uring::IoUring,
|
||||||
utils::{
|
utils::{
|
||||||
asyncevent::AsyncEvent, buf::Buf, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
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::{
|
video::drm::{
|
||||||
sync_obj::{SyncObj, SyncObjCtx, SyncObjPoint},
|
sync_obj::{SyncObj, SyncObjCtx, SyncObjPoint},
|
||||||
|
|
@ -89,7 +89,7 @@ impl WaitForSyncObj {
|
||||||
|
|
||||||
pub fn set_ctx(&self, ctx: Option<Rc<SyncObjCtx>>) {
|
pub fn set_ctx(&self, ctx: Option<Rc<SyncObjCtx>>) {
|
||||||
self.inner.ctx.set(ctx);
|
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 {
|
for waiter in busy_waiters {
|
||||||
let res = self.submit_job(
|
let res = self.submit_job(
|
||||||
waiter.job.id,
|
waiter.job.id,
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ use {
|
||||||
io_uring::{IoUring, IoUringError},
|
io_uring::{IoUring, IoUringError},
|
||||||
time::{Time, TimeError},
|
time::{Time, TimeError},
|
||||||
utils::{
|
utils::{
|
||||||
buf::TypedBuf, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell,
|
buf::TypedBuf, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, hash_map_ext::HashMapExt,
|
||||||
oserror::OsError, stack::Stack,
|
numcell::NumCell, oserror::OsError, stack::Stack,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
|
|
@ -204,7 +204,7 @@ impl WheelData {
|
||||||
self.destroyed.set(true);
|
self.destroyed.set(true);
|
||||||
self.dispatcher.set(None);
|
self.dispatcher.set(None);
|
||||||
self.cached_futures.take();
|
self.cached_futures.take();
|
||||||
for (_, dispatcher) in self.dispatchers.lock().drain() {
|
for dispatcher in self.dispatchers.lock().drain_values() {
|
||||||
dispatcher.complete(Err(WheelError::Destroyed));
|
dispatcher.complete(Err(WheelError::Destroyed));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ use {
|
||||||
clonecell::CloneCell,
|
clonecell::CloneCell,
|
||||||
copyhashmap::CopyHashMap,
|
copyhashmap::CopyHashMap,
|
||||||
errorfmt::ErrorFmt,
|
errorfmt::ErrorFmt,
|
||||||
|
hash_map_ext::HashMapExt,
|
||||||
oserror::OsError,
|
oserror::OsError,
|
||||||
vec_ext::VecExt,
|
vec_ext::VecExt,
|
||||||
},
|
},
|
||||||
|
|
@ -159,7 +160,7 @@ impl UsrCon {
|
||||||
|
|
||||||
pub fn kill(&self) {
|
pub fn kill(&self) {
|
||||||
self.dead.set(true);
|
self.dead.set(true);
|
||||||
for (_, obj) in self.objects.lock().drain() {
|
for obj in self.objects.lock().drain_values() {
|
||||||
if let Some(obj) = obj {
|
if let Some(obj) = obj {
|
||||||
obj.break_loops();
|
obj.break_loops();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ use {
|
||||||
tree::{Node, ToplevelNode},
|
tree::{Node, ToplevelNode},
|
||||||
utils::{
|
utils::{
|
||||||
bitflags::BitflagsExt, buf::Buf, cell_ext::CellExt, clonecell::CloneCell,
|
bitflags::BitflagsExt, buf::Buf, cell_ext::CellExt, clonecell::CloneCell,
|
||||||
copyhashmap::CopyHashMap, errorfmt::ErrorFmt, linkedlist::LinkedList, numcell::NumCell,
|
copyhashmap::CopyHashMap, errorfmt::ErrorFmt, hash_map_ext::HashMapExt,
|
||||||
oserror::OsError, rc_eq::rc_eq,
|
linkedlist::LinkedList, numcell::NumCell, oserror::OsError, rc_eq::rc_eq,
|
||||||
},
|
},
|
||||||
wire::WlSurfaceId,
|
wire::WlSurfaceId,
|
||||||
wire_xcon::{
|
wire_xcon::{
|
||||||
|
|
@ -171,7 +171,7 @@ struct SelectionData<T: XIpc> {
|
||||||
|
|
||||||
impl<T: XIpc> SelectionData<T> {
|
impl<T: XIpc> SelectionData<T> {
|
||||||
fn destroy(&self) {
|
fn destroy(&self) {
|
||||||
for (_, offer) in self.offers.lock().drain() {
|
for offer in self.offers.lock().drain_values() {
|
||||||
destroy_data_offer::<T>(&offer.offer);
|
destroy_data_offer::<T>(&offer.offer);
|
||||||
}
|
}
|
||||||
self.active_offer.take();
|
self.active_offer.take();
|
||||||
|
|
@ -179,7 +179,7 @@ impl<T: XIpc> SelectionData<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroy_sources(&self) {
|
fn destroy_sources(&self) {
|
||||||
for (_, source) in self.sources.lock().drain() {
|
for source in self.sources.lock().drain_values() {
|
||||||
destroy_data_source::<T>(&source);
|
destroy_data_source::<T>(&source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -207,7 +207,7 @@ impl Drop for XwmShared {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.data.destroy();
|
self.data.destroy();
|
||||||
self.primary_selection.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::<XClipboardIpc>(&device);
|
||||||
destroy_data_device::<XPrimarySelectionIpc>(&device);
|
destroy_data_device::<XPrimarySelectionIpc>(&device);
|
||||||
device.seat.unset_x_data_device(device.id);
|
device.seat.unset_x_data_device(device.id);
|
||||||
|
|
@ -260,7 +260,7 @@ enum Initiator {
|
||||||
|
|
||||||
impl Drop for Wm {
|
impl Drop for Wm {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
for (_, window) in self.windows.drain() {
|
for window in self.windows.drain_values() {
|
||||||
if let Some(window) = window.window.take() {
|
if let Some(window) = window.window.take() {
|
||||||
window.break_loops();
|
window.break_loops();
|
||||||
}
|
}
|
||||||
|
|
@ -1985,7 +1985,7 @@ impl Wm {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let mut children = data.children.lock();
|
let mut children = data.children.lock();
|
||||||
for (_, child) in children.drain() {
|
for child in children.drain_values() {
|
||||||
child.parent.set(None);
|
child.parent.set(None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,10 @@ request set_layer (since = 2) {
|
||||||
layer: u32,
|
layer: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request set_exclusive_edge (since = 5) {
|
||||||
|
edge: u32,
|
||||||
|
}
|
||||||
|
|
||||||
# events
|
# events
|
||||||
|
|
||||||
event configure {
|
event configure {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue