From 8a91c070be4416b9c6b2649f8f6242b3ffe5943b Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Tue, 7 May 2024 20:19:41 +0200 Subject: [PATCH] layer-shell: implement exclusive zones --- docs/features.md | 89 +++++------ src/compositor.rs | 4 + src/ifs/wl_surface/zwlr_layer_surface_v1.rs | 169 ++++++++++++++++++-- src/ifs/zwlr_layer_shell_v1.rs | 2 +- src/rect.rs | 5 + src/renderer.rs | 6 +- src/tasks/connector.rs | 5 + src/tree/output.rs | 106 ++++++++---- wire/zwlr_layer_surface_v1.txt | 4 + 9 files changed, 300 insertions(+), 90 deletions(-) diff --git a/docs/features.md b/docs/features.md index 3d1feb0e..ff1b7d7f 100644 --- a/docs/features.md +++ b/docs/features.md @@ -126,54 +126,53 @@ Jay's supports leasing VR headsets to applications. Jay supports the following wayland protocols: -| Global | Version | Privileged | -|-----------------------------------------|:-----------------|---------------| -| ext_foreign_toplevel_list_v1 | 1 | Yes | -| ext_idle_notifier_v1 | 1 | Yes | -| ext_session_lock_manager_v1 | 1 | Yes | -| ext_transient_seat_manager_v1 | 1[^ts_rejected] | Yes | -| org_kde_kwin_server_decoration_manager | 1 | | -| wl_compositor | 6[^no_touch] | | -| wl_data_device_manager | 3 | | -| wl_drm | 2 | | -| wl_output | 4 | | -| wl_seat | 9 | | -| wl_shm | 2 | | -| wl_subcompositor | 1 | | -| wp_alpha_modifier_v1 | 1 | | -| wp_content_type_manager_v1 | 1 | | -| wp_cursor_shape_manager_v1 | 1 | | -| wp_drm_lease_device_v1 | 1 | | -| wp_fractional_scale_manager_v1 | 1 | | -| wp_linux_drm_syncobj_manager_v1 | 1 | | -| wp_presentation | 1 | | -| wp_security_context_manager_v1 | 1 | | -| wp_single_pixel_buffer_manager_v1 | 1 | | -| wp_tearing_control_manager_v1 | 1[^no_tearing] | | -| wp_viewporter | 1 | | -| xdg_activation_v1 | 1 | | -| xdg_toplevel_drag_manager_v1 | 1 | | -| xdg_wm_base | 6 | | -| xdg_wm_dialog_v1 | 1 | | -| zwlr_data_control_manager_v1 | 2 | Yes | -| zwlr_layer_shell_v1 | 4[^no_exclusive] | No[^lsaccess] | -| zwlr_screencopy_manager_v1 | 3 | Yes | -| zwp_idle_inhibit_manager_v1 | 1 | | -| zwp_input_method_manager_v2 | 1 | Yes | -| zwp_linux_dmabuf_v1 | 5 | | -| zwp_pointer_constraints_v1 | 1 | | -| zwp_pointer_gestures_v1 | 3 | | -| zwp_primary_selection_device_manager_v1 | 1 | | -| zwp_relative_pointer_manager_v1 | 1 | | -| zwp_tablet_manager_v2 | 1 | | -| zwp_text_input_manager_v3 | 1 | | -| zwp_virtual_keyboard_manager_v1 | 1 | Yes | -| zxdg_decoration_manager_v1 | 1 | | -| zxdg_output_manager_v1 | 3 | | +| Global | Version | Privileged | +|-----------------------------------------|:----------------|---------------| +| ext_foreign_toplevel_list_v1 | 1 | Yes | +| ext_idle_notifier_v1 | 1 | Yes | +| ext_session_lock_manager_v1 | 1 | Yes | +| ext_transient_seat_manager_v1 | 1[^ts_rejected] | Yes | +| org_kde_kwin_server_decoration_manager | 1 | | +| wl_compositor | 6[^no_touch] | | +| wl_data_device_manager | 3 | | +| wl_drm | 2 | | +| wl_output | 4 | | +| wl_seat | 9 | | +| wl_shm | 2 | | +| wl_subcompositor | 1 | | +| wp_alpha_modifier_v1 | 1 | | +| wp_content_type_manager_v1 | 1 | | +| wp_cursor_shape_manager_v1 | 1 | | +| wp_drm_lease_device_v1 | 1 | | +| wp_fractional_scale_manager_v1 | 1 | | +| wp_linux_drm_syncobj_manager_v1 | 1 | | +| wp_presentation | 1 | | +| wp_security_context_manager_v1 | 1 | | +| wp_single_pixel_buffer_manager_v1 | 1 | | +| wp_tearing_control_manager_v1 | 1[^no_tearing] | | +| wp_viewporter | 1 | | +| xdg_activation_v1 | 1 | | +| xdg_toplevel_drag_manager_v1 | 1 | | +| xdg_wm_base | 6 | | +| xdg_wm_dialog_v1 | 1 | | +| zwlr_data_control_manager_v1 | 2 | Yes | +| zwlr_layer_shell_v1 | 5 | No[^lsaccess] | +| zwlr_screencopy_manager_v1 | 3 | Yes | +| zwp_idle_inhibit_manager_v1 | 1 | | +| zwp_input_method_manager_v2 | 1 | Yes | +| zwp_linux_dmabuf_v1 | 5 | | +| zwp_pointer_constraints_v1 | 1 | | +| zwp_pointer_gestures_v1 | 3 | | +| zwp_primary_selection_device_manager_v1 | 1 | | +| zwp_relative_pointer_manager_v1 | 1 | | +| zwp_tablet_manager_v2 | 1 | | +| zwp_text_input_manager_v3 | 1 | | +| zwp_virtual_keyboard_manager_v1 | 1 | Yes | +| zxdg_decoration_manager_v1 | 1 | | +| zxdg_output_manager_v1 | 3 | | [^no_touch]: Touch input is 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. [^ts_rejected]: Seat creation is always rejected. diff --git a/src/compositor.rs b/src/compositor.rs index 065629a6..f8c427aa 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -449,6 +449,10 @@ fn create_dummy_output(state: &Rc) { workspace: Default::default(), seat_state: Default::default(), layers: Default::default(), + exclusive_zones: Default::default(), + workspace_rect: Default::default(), + non_exclusive_rect_rel: Default::default(), + non_exclusive_rect: Default::default(), render_data: Default::default(), state: state.clone(), is_dummy: true, diff --git a/src/ifs/wl_surface/zwlr_layer_surface_v1.rs b/src/ifs/wl_surface/zwlr_layer_surface_v1.rs index 856ce5d0..cd531698 100644 --- a/src/ifs/wl_surface/zwlr_layer_surface_v1.rs +++ b/src/ifs/wl_surface/zwlr_layer_surface_v1.rs @@ -52,22 +52,59 @@ pub struct ZwlrLayerSurfaceV1 { requested_serial: NumCell, size: Cell<(i32, i32)>, anchor: Cell, - exclusive_zone: Cell, + exclusive_zone: Cell, margin: Cell<(i32, i32, i32, i32)>, keyboard_interactivity: Cell, link: Cell>>>, seat_state: NodeSeatState, last_configure: Cell<(i32, i32)>, + exclusive_edge: Cell>, + exclusive_size: Cell, +} + +#[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), } #[derive(Default)] pub struct PendingLayerSurfaceData { size: Option<(i32, i32)>, anchor: Option, - exclusive_zone: Option, + exclusive_zone: Option, margin: Option<(i32, i32, i32, i32)>, keyboard_interactivity: Option, layer: Option, + exclusive_edge: Option, } impl PendingLayerSurfaceData { @@ -113,12 +150,14 @@ impl ZwlrLayerSurfaceV1 { requested_serial: Default::default(), size: Cell::new((0, 0)), anchor: Cell::new(0), - exclusive_zone: Cell::new(0), + exclusive_zone: Cell::new(ExclusiveZone::MoveSelf), margin: Cell::new((0, 0, 0, 0)), keyboard_interactivity: Cell::new(0), link: Cell::new(None), seat_state: Default::default(), last_configure: Default::default(), + exclusive_edge: Default::default(), + exclusive_size: Default::default(), } } @@ -181,7 +220,16 @@ impl ZwlrLayerSurfaceV1RequestHandler for ZwlrLayerSurfaceV1 { _slf: &Rc, ) -> Result<(), Self::Error> { let mut pending = self.pending(); - pending.exclusive_zone = Some(req.zone); + let zone = if req.zone < 0 { + ExclusiveZone::FixedSelf + } else if req.zone == 0 { + ExclusiveZone::MoveSelf + } else if req.zone > u16::MAX as i32 { + return Err(ZwlrLayerSurfaceV1Error::ExcessiveExclusive); + } else { + ExclusiveZone::Acquire(req.zone) + }; + pending.exclusive_zone = Some(zone); Ok(()) } @@ -234,9 +282,73 @@ impl ZwlrLayerSurfaceV1RequestHandler for ZwlrLayerSurfaceV1 { pending.layer = Some(req.layer); Ok(()) } + + fn set_exclusive_edge( + &self, + req: SetExclusiveEdge, + _slf: &Rc, + ) -> Result<(), Self::Error> { + if req.edge & !(LEFT | RIGHT | TOP | BOTTOM) != 0 { + return Err(ZwlrLayerSurfaceV1Error::UnknownAnchor(req.edge)); + } + if req.edge.count_ones() > 1 { + return Err(ZwlrLayerSurfaceV1Error::TooManyExclusiveEdges); + } + let mut pending = self.pending(); + if req.edge == 0 { + pending.exclusive_edge = None; + } else { + pending.exclusive_edge = Some(req.edge); + } + Ok(()) + } } impl ZwlrLayerSurfaceV1 { + pub fn exclusive_size(&self) -> ExclusiveSize { + self.exclusive_size.get() + } + + fn update_exclusive_size(&self) { + let exclusive_edge = { + if let Some(ee) = self.exclusive_edge.get() { + Some(ee) + } else { + let anchor = self.anchor.get(); + let edges = anchor.count_ones(); + if edges == 1 { + Some(anchor) + } else if edges == 3 { + match (!anchor) & (TOP | BOTTOM | LEFT | RIGHT) { + TOP => Some(BOTTOM), + BOTTOM => Some(TOP), + LEFT => Some(RIGHT), + RIGHT => Some(LEFT), + _ => None, + } + } else { + None + } + } + }; + let mut exclusive_size = ExclusiveSize::default(); + if let (ExclusiveZone::Acquire(s), Some(edge)) = (self.exclusive_zone.get(), exclusive_edge) + { + match edge { + TOP => exclusive_size.top = s, + RIGHT => exclusive_size.right = s, + BOTTOM => exclusive_size.bottom = s, + LEFT => exclusive_size.left = s, + _ => {} + } + } + if self.exclusive_size.replace(exclusive_size) != exclusive_size { + if let Some(output) = self.output.node.get() { + output.update_exclusive_zones(); + } + } + } + fn pre_commit(&self, pending: &mut PendingState) -> Result<(), ZwlrLayerSurfaceV1Error> { let pending = pending.layer_surface.get_or_insert_default_ext(); if let Some(size) = pending.size.take() { @@ -257,6 +369,9 @@ impl ZwlrLayerSurfaceV1 { if let Some(layer) = pending.layer.take() { self.layer.set(layer); } + if let Some(edge) = pending.exclusive_edge.take() { + self.exclusive_edge.set(Some(edge)); + } let anchor = self.anchor.get(); let (width, height) = self.size.get(); if width == 0 && !anchor.contains(LEFT | RIGHT) { @@ -265,17 +380,25 @@ impl ZwlrLayerSurfaceV1 { 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); + } + } self.configure(); Ok(()) } fn configure(&self) { - let Some(global) = self.output.get() else { + let Some(node) = self.output.node() else { return; }; let (mut width, mut height) = self.size.get(); let (mt, mr, mb, ml) = self.margin.get(); - let (mut available_width, mut available_height) = global.position().size(); + 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; @@ -308,7 +431,7 @@ impl ZwlrLayerSurfaceV1 { } fn compute_position(&self) { - let Some(global) = self.output.get() else { + let Some(output) = self.output.node() else { return; }; let extents = self.surface.extents.get(); @@ -318,8 +441,12 @@ impl ZwlrLayerSurfaceV1 { anchor = LEFT | RIGHT | TOP | BOTTOM; } let (mt, mr, mb, ml) = self.margin.get(); - let opos = global.pos.get(); - let (owidth, oheight) = opos.size(); + let opos = output.global.pos.get(); + let rect = match self.exclusive_zone.get() { + ExclusiveZone::MoveSelf => output.non_exclusive_rect.get(), + _ => opos, + }; + let (owidth, oheight) = rect.size(); let mut x1 = 0; let mut y1 = 0; if anchor.contains(LEFT | RIGHT) { @@ -336,8 +463,8 @@ impl ZwlrLayerSurfaceV1 { } else if anchor.contains(BOTTOM) { y1 = oheight - height - mb; } - let o_rect = Rect::new_sized(x1, y1, width, height).unwrap(); - let a_rect = o_rect.move_(opos.x1(), opos.y1()); + 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); self.pos.set(a_rect); let abs_x = a_rect.x1() - extents.x1(); @@ -351,6 +478,13 @@ impl ZwlrLayerSurfaceV1 { self.compute_position(); } + pub fn exclusive_zones_changed(&self) { + if self.exclusive_zone.get() != ExclusiveZone::MoveSelf { + return; + } + self.output_resized(); + } + pub fn destroy_node(&self) { self.link.set(None); self.mapped.set(false); @@ -358,6 +492,11 @@ impl ZwlrLayerSurfaceV1 { self.seat_state.destroy_node(self); self.client.state.tree_changed(); self.last_configure.take(); + if self.exclusive_size.take().is_not_empty() { + if let Some(node) = self.output.node() { + node.update_exclusive_zones(); + } + } } } @@ -383,12 +522,14 @@ impl SurfaceExt for ZwlrLayerSurfaceV1 { if self.surface.extents.get().size() != self.pos.get().size() { self.compute_position(); } + self.update_exclusive_size(); } } else if buffer_is_some { let layer = &output.layers[self.layer.get() as usize]; self.link.set(Some(layer.add_last(self.clone()))); self.mapped.set(true); self.compute_position(); + self.update_exclusive_size(); } if self.mapped.get() != was_mapped { output.update_visible(); @@ -500,6 +641,12 @@ pub enum ZwlrLayerSurfaceV1Error { UnknownAnchor(u32), #[error("Unknown keyboard interactivity {0}")] UnknownKi(u32), + #[error("Surface is not anchored at exclusive edge")] + ExclusiveEdgeNotAnchored, + #[error("Request must contain exactly one edge")] + TooManyExclusiveEdges, + #[error("Exclusive zone not be larger than 65535")] + ExcessiveExclusive, } efrom!(ZwlrLayerSurfaceV1Error, WlSurfaceError); efrom!(ZwlrLayerSurfaceV1Error, ClientError); diff --git a/src/ifs/zwlr_layer_shell_v1.rs b/src/ifs/zwlr_layer_shell_v1.rs index ec1b13b1..348af5ae 100644 --- a/src/ifs/zwlr_layer_shell_v1.rs +++ b/src/ifs/zwlr_layer_shell_v1.rs @@ -107,7 +107,7 @@ impl Global for ZwlrLayerShellV1Global { } fn version(&self) -> u32 { - 4 + 5 } fn required_caps(&self) -> ClientCaps { diff --git a/src/rect.rs b/src/rect.rs index c310632b..1426df12 100644 --- a/src/rect.rs +++ b/src/rect.rs @@ -86,6 +86,11 @@ impl Rect { Self::new(x1, y1, x1 + width, y1 + height) } + #[track_caller] + pub fn new_sized_unchecked(x1: i32, y1: i32, width: i32, height: i32) -> Self { + Self::new_sized(x1, y1, width, height).unwrap() + } + pub fn union(&self, other: Self) -> Self { Self { raw: RectRaw { diff --git a/src/renderer.rs b/src/renderer.rs index 85244e24..80bf94cc 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -120,10 +120,14 @@ impl Renderer<'_> { } else { render_layer!(output.layers[0]); render_layer!(output.layers[1]); + let non_exclusive_rect = output.non_exclusive_rect_rel.get(); + let (x, y) = non_exclusive_rect.translate_inv(x, y); { let c = theme.colors.bar_background.get(); self.base.fill_boxes2( - slice::from_ref(&Rect::new_sized(0, 0, opos.width(), th).unwrap()), + slice::from_ref( + &Rect::new_sized(0, 0, non_exclusive_rect.width(), th).unwrap(), + ), &c, x, y, diff --git a/src/tasks/connector.rs b/src/tasks/connector.rs index 901b439a..09184858 100644 --- a/src/tasks/connector.rs +++ b/src/tasks/connector.rs @@ -147,6 +147,10 @@ impl ConnectorHandler { seat_state: Default::default(), global: global.clone(), layers: Default::default(), + exclusive_zones: Default::default(), + workspace_rect: Default::default(), + non_exclusive_rect: Default::default(), + non_exclusive_rect_rel: Default::default(), render_data: RefCell::new(OutputRenderData { active_workspace: None, underline: Default::default(), @@ -169,6 +173,7 @@ impl ConnectorHandler { hardware_cursor_needs_render: Cell::new(false), screencopies: Default::default(), }); + on.update_rects(); self.state .add_output_scale(on.global.persistent.scale.get()); let output_data = Rc::new(OutputData { diff --git a/src/tree/output.rs b/src/tree/output.rs index 459046ea..cc6b76fc 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -18,8 +18,8 @@ use { }, wl_surface::{ ext_session_lock_surface_v1::ExtSessionLockSurfaceV1, - zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, SurfaceSendPreferredScaleVisitor, - SurfaceSendPreferredTransformVisitor, + zwlr_layer_surface_v1::{ExclusiveSize, ZwlrLayerSurfaceV1}, + SurfaceSendPreferredScaleVisitor, SurfaceSendPreferredTransformVisitor, }, zwlr_layer_shell_v1::{BACKGROUND, BOTTOM, OVERLAY, TOP}, zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1, @@ -47,7 +47,7 @@ use { std::{ cell::{Cell, RefCell}, fmt::{Debug, Formatter}, - ops::{Deref, Sub}, + ops::Deref, rc::Rc, }, }; @@ -61,6 +61,10 @@ pub struct OutputNode { pub workspace: CloneCell>>, pub seat_state: NodeSeatState, pub layers: [LinkedList>; 4], + pub exclusive_zones: Cell, + pub workspace_rect: Cell, + pub non_exclusive_rect: Cell, + pub non_exclusive_rect_rel: Cell, pub render_data: RefCell, pub state: Rc, pub is_dummy: bool, @@ -94,6 +98,26 @@ pub async fn output_render_data(state: Rc) { } impl OutputNode { + pub fn update_exclusive_zones(self: &Rc) { + 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) { self.screencasts.set((sc.client.id, sc.id), sc.clone()); self.screencast_changed(); @@ -222,9 +246,9 @@ impl OutputNode { } pub fn on_spaces_changed(self: &Rc) { - self.schedule_update_render_data(); + self.update_rects(); if let Some(c) = self.workspace.get() { - c.change_extents(&self.workspace_rect()); + c.change_extents(&self.workspace_rect.get()); } } @@ -281,7 +305,7 @@ impl OutputNode { texture_height = (th as f64 * scale).round() as _; } let active_id = self.workspace.get().map(|w| w.id); - let output_width = self.global.pos.get().width(); + let output_width = self.non_exclusive_rect.get().width(); rd.underline = Rect::new_sized(0, th, output_width, 1).unwrap(); for ws in self.workspaces.iter() { let old_tex = ws.title_texture.take(); @@ -430,7 +454,7 @@ impl OutputNode { if let Some(fs) = ws.fullscreen.get() { fs.tl_change_extents(&self.global.pos.get()); } - ws.change_extents(&self.workspace_rect()); + ws.change_extents(&self.workspace_rect.get()); for seat in seats { ws.clone().node_do_focus(&seat, Direction::Unspecified); } @@ -478,16 +502,29 @@ impl OutputNode { ws } - fn workspace_rect(&self) -> Rect { + pub fn update_rects(self: &Rc) { let rect = self.global.pos.get(); let th = self.state.theme.sizes.title_height.get(); - Rect::new_sized( - rect.x1(), - rect.y1() + th + 1, - rect.width(), - rect.height().sub(th + 1).max(0), - ) - .unwrap() + let exclusive = self.exclusive_zones.get(); + let y1 = rect.y1() + exclusive.top; + let x2 = rect.x2() - exclusive.right; + let y2 = rect.y2() - exclusive.bottom; + let x1 = rect.x1() + exclusive.left; + let width = (x2 - x1).max(0); + let height = (y2 - y1).max(0); + self.non_exclusive_rect + .set(Rect::new_sized_unchecked(x1, y1, width, height)); + self.non_exclusive_rect_rel.set(Rect::new_sized_unchecked( + exclusive.left, + exclusive.top, + width, + height, + )); + let y1 = y1 + th + 1; + let height = (y2 - y1).max(0); + self.workspace_rect + .set(Rect::new_sized_unchecked(x1, y1, width, height)); + self.schedule_update_render_data(); } pub fn set_position(self: &Rc, x: i32, y: i32) { @@ -546,7 +583,7 @@ impl OutputNode { self.global.persistent.pos.set((rect.x1(), rect.y1())); self.global.pos.set(*rect); self.state.root.update_extents(); - self.schedule_update_render_data(); + self.update_rects(); if let Some(ls) = self.lock_surface.get() { ls.change_extents(*rect); } @@ -554,7 +591,7 @@ impl OutputNode { if let Some(fs) = c.fullscreen.get() { fs.tl_change_extents(rect); } - c.change_extents(&self.workspace_rect()); + c.change_extents(&self.workspace_rect.get()); } for layer in &self.layers { for surface in layer.iter() { @@ -657,6 +694,7 @@ impl OutputNode { Some(p) => p, _ => return, }; + let (x, y) = self.non_exclusive_rect_rel.get().translate(x, y); if y >= self.state.theme.sizes.title_height.get() { return; } @@ -844,21 +882,25 @@ impl Node for OutputNode { fs.tl_as_node().node_find_tree_at(x, y, tree, usecase) } else { let mut search_layers = true; - if y < bar_height { - search_layers = false; - } else { - if let Some(ws) = self.workspace.get() { - let y = y - bar_height; - let len = tree.len(); - tree.push(FoundNode { - node: ws.clone(), - x, - y, - }); - match ws.node_find_tree_at(x, y, tree, usecase) { - FindTreeResult::AcceptsInput => search_layers = false, - FindTreeResult::Other => { - tree.truncate(len); + let non_exclusive_rect = self.non_exclusive_rect_rel.get(); + if non_exclusive_rect.contains(x, y) { + let (x, y) = non_exclusive_rect.translate(x, y); + if y < bar_height { + search_layers = false; + } else { + if let Some(ws) = self.workspace.get() { + let y = y - bar_height; + let len = tree.len(); + tree.push(FoundNode { + node: ws.clone(), + x, + y, + }); + match ws.node_find_tree_at(x, y, tree, usecase) { + FindTreeResult::AcceptsInput => search_layers = false, + FindTreeResult::Other => { + tree.truncate(len); + } } } } diff --git a/wire/zwlr_layer_surface_v1.txt b/wire/zwlr_layer_surface_v1.txt index 1d4680de..2d7b382b 100644 --- a/wire/zwlr_layer_surface_v1.txt +++ b/wire/zwlr_layer_surface_v1.txt @@ -38,6 +38,10 @@ request set_layer (since = 2) { layer: u32, } +request set_exclusive_edge (since = 5) { + edge: u32, +} + # events event configure {