1
0
Fork 0
forked from wry/wry

layer-shell: implement exclusive zones

This commit is contained in:
Julian Orth 2024-05-07 20:19:41 +02:00
parent 8dc31110b9
commit 8a91c070be
9 changed files with 300 additions and 90 deletions

View file

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

View file

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

View file

@ -52,22 +52,59 @@ pub struct ZwlrLayerSurfaceV1 {
requested_serial: NumCell<u32>, requested_serial: NumCell<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)>, last_configure: Cell<(i32, i32)>,
exclusive_edge: Cell<Option<u32>>,
exclusive_size: Cell<ExclusiveSize>,
}
#[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)] #[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>,
exclusive_edge: Option<u32>,
} }
impl PendingLayerSurfaceData { impl PendingLayerSurfaceData {
@ -113,12 +150,14 @@ impl ZwlrLayerSurfaceV1 {
requested_serial: Default::default(), requested_serial: Default::default(),
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(), last_configure: Default::default(),
exclusive_edge: Default::default(),
exclusive_size: Default::default(),
} }
} }
@ -181,7 +220,16 @@ 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 {
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(())
} }
@ -234,9 +282,73 @@ impl ZwlrLayerSurfaceV1RequestHandler for ZwlrLayerSurfaceV1 {
pending.layer = Some(req.layer); pending.layer = Some(req.layer);
Ok(()) Ok(())
} }
fn set_exclusive_edge(
&self,
req: SetExclusiveEdge,
_slf: &Rc<Self>,
) -> Result<(), Self::Error> {
if req.edge & !(LEFT | RIGHT | TOP | BOTTOM) != 0 {
return Err(ZwlrLayerSurfaceV1Error::UnknownAnchor(req.edge));
}
if req.edge.count_ones() > 1 {
return Err(ZwlrLayerSurfaceV1Error::TooManyExclusiveEdges);
}
let mut pending = self.pending();
if req.edge == 0 {
pending.exclusive_edge = None;
} else {
pending.exclusive_edge = Some(req.edge);
}
Ok(())
}
} }
impl ZwlrLayerSurfaceV1 { 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> { 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();
if let Some(size) = pending.size.take() { if let Some(size) = pending.size.take() {
@ -257,6 +369,9 @@ 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() {
self.exclusive_edge.set(Some(edge));
}
let anchor = self.anchor.get(); let anchor = self.anchor.get();
let (width, height) = self.size.get(); let (width, height) = self.size.get();
if width == 0 && !anchor.contains(LEFT | RIGHT) { if width == 0 && !anchor.contains(LEFT | RIGHT) {
@ -265,17 +380,25 @@ impl ZwlrLayerSurfaceV1 {
if height == 0 && !anchor.contains(TOP | BOTTOM) { if height == 0 && !anchor.contains(TOP | BOTTOM) {
return Err(ZwlrLayerSurfaceV1Error::HeightZero); return Err(ZwlrLayerSurfaceV1Error::HeightZero);
} }
if let Some(ee) = self.exclusive_edge.get() {
if !self.anchor.get().contains(ee) {
return Err(ZwlrLayerSurfaceV1Error::ExclusiveEdgeNotAnchored);
}
}
self.configure(); self.configure();
Ok(()) Ok(())
} }
fn configure(&self) { fn configure(&self) {
let Some(global) = self.output.get() else { let Some(node) = self.output.node() else {
return; return;
}; };
let (mut width, mut height) = self.size.get(); let (mut width, mut height) = self.size.get();
let (mt, mr, mb, ml) = self.margin.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(); let anchor = self.anchor.get();
if anchor.contains(LEFT) { if anchor.contains(LEFT) {
available_width -= ml; available_width -= ml;
@ -308,7 +431,7 @@ impl ZwlrLayerSurfaceV1 {
} }
fn compute_position(&self) { fn compute_position(&self) {
let Some(global) = self.output.get() else { let Some(output) = self.output.node() else {
return; return;
}; };
let extents = self.surface.extents.get(); let extents = self.surface.extents.get();
@ -318,8 +441,12 @@ impl ZwlrLayerSurfaceV1 {
anchor = LEFT | RIGHT | TOP | BOTTOM; anchor = LEFT | RIGHT | TOP | BOTTOM;
} }
let (mt, mr, mb, ml) = self.margin.get(); let (mt, mr, mb, ml) = self.margin.get();
let opos = global.pos.get(); let opos = output.global.pos.get();
let (owidth, oheight) = opos.size(); 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 | RIGHT) { if anchor.contains(LEFT | RIGHT) {
@ -336,8 +463,8 @@ impl ZwlrLayerSurfaceV1 {
} else if anchor.contains(BOTTOM) { } else if anchor.contains(BOTTOM) {
y1 = oheight - height - mb; y1 = oheight - height - mb;
} }
let o_rect = Rect::new_sized(x1, y1, width, height).unwrap(); let a_rect = Rect::new_sized(x1 + rect.x1(), y1 + rect.y1(), width, height).unwrap();
let a_rect = o_rect.move_(opos.x1(), opos.y1()); let o_rect = a_rect.move_(-opos.x1(), -opos.y1());
self.output_extents.set(o_rect); self.output_extents.set(o_rect);
self.pos.set(a_rect); self.pos.set(a_rect);
let abs_x = a_rect.x1() - extents.x1(); let abs_x = a_rect.x1() - extents.x1();
@ -351,6 +478,13 @@ impl ZwlrLayerSurfaceV1 {
self.compute_position(); 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);
@ -358,6 +492,11 @@ impl ZwlrLayerSurfaceV1 {
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(); 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() { if self.surface.extents.get().size() != self.pos.get().size() {
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();
@ -500,6 +641,12 @@ pub enum ZwlrLayerSurfaceV1Error {
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,
} }
efrom!(ZwlrLayerSurfaceV1Error, WlSurfaceError); efrom!(ZwlrLayerSurfaceV1Error, WlSurfaceError);
efrom!(ZwlrLayerSurfaceV1Error, ClientError); efrom!(ZwlrLayerSurfaceV1Error, ClientError);

View file

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

View file

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

View file

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

View file

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

View file

@ -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,
@ -47,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,
}, },
}; };
@ -61,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,
@ -94,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();
@ -222,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());
} }
} }
@ -281,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();
@ -430,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);
} }
@ -478,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) {
@ -546,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);
} }
@ -554,7 +591,7 @@ 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() {
@ -657,6 +694,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;
} }
@ -844,21 +882,25 @@ 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 {
let mut search_layers = true; let mut search_layers = true;
if y < bar_height { let non_exclusive_rect = self.non_exclusive_rect_rel.get();
search_layers = false; if non_exclusive_rect.contains(x, y) {
} else { let (x, y) = non_exclusive_rect.translate(x, y);
if let Some(ws) = self.workspace.get() { if y < bar_height {
let y = y - bar_height; search_layers = false;
let len = tree.len(); } else {
tree.push(FoundNode { if let Some(ws) = self.workspace.get() {
node: ws.clone(), let y = y - bar_height;
x, let len = tree.len();
y, tree.push(FoundNode {
}); node: ws.clone(),
match ws.node_find_tree_at(x, y, tree, usecase) { x,
FindTreeResult::AcceptsInput => search_layers = false, y,
FindTreeResult::Other => { });
tree.truncate(len); match ws.node_find_tree_at(x, y, tree, usecase) {
FindTreeResult::AcceptsInput => search_layers = false,
FindTreeResult::Other => {
tree.truncate(len);
}
} }
} }
} }

View file

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