layer-shell: implement exclusive zones
This commit is contained in:
parent
8dc31110b9
commit
8a91c070be
9 changed files with 300 additions and 90 deletions
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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