aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2023-09-26 20:12:04 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2023-09-26 20:12:04 +0400
commit953d1064c280cacf5c4c6bf7bcf79eece4e4235a (patch)
tree9f729fe75c1c6519e0fbab9449baf1b9c678f1d1 /src
parent4a585a3293286742d96689e52b1a314cf8c3854e (diff)
downloadniri-953d1064c280cacf5c4c6bf7bcf79eece4e4235a.tar.gz
niri-953d1064c280cacf5c4c6bf7bcf79eece4e4235a.tar.bz2
niri-953d1064c280cacf5c4c6bf7bcf79eece4e4235a.zip
Add layer shell exclusive zone support
Diffstat (limited to 'src')
-rw-r--r--src/handlers/layer_shell.rs4
-rw-r--r--src/handlers/xdg_shell.rs7
-rw-r--r--src/layout.rs143
-rw-r--r--src/niri.rs3
4 files changed, 110 insertions, 47 deletions
diff --git a/src/handlers/layer_shell.rs b/src/handlers/layer_shell.rs
index 39be2345..c426d321 100644
--- a/src/handlers/layer_shell.rs
+++ b/src/handlers/layer_shell.rs
@@ -49,7 +49,7 @@ impl WlrLayerShellHandler for State {
None
};
if let Some(output) = output {
- self.niri.queue_redraw(output);
+ self.niri.output_resized(output);
}
}
}
@@ -96,6 +96,6 @@ impl State {
}
drop(map);
- self.niri.queue_redraw(output);
+ self.niri.output_resized(output);
}
}
diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs
index 75b03add..387e4bb3 100644
--- a/src/handlers/xdg_shell.rs
+++ b/src/handlers/xdg_shell.rs
@@ -1,4 +1,4 @@
-use smithay::desktop::{find_popup_root_surface, PopupKind, Window};
+use smithay::desktop::{find_popup_root_surface, layer_map_for_output, PopupKind, Window};
use smithay::output::Output;
use smithay::reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1;
use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::{self, ResizeEdge};
@@ -14,7 +14,7 @@ use smithay::wayland::shell::xdg::{
};
use smithay::{delegate_xdg_decoration, delegate_xdg_shell};
-use crate::layout::{configure_new_window, output_size};
+use crate::layout::configure_new_window;
use crate::niri::State;
impl XdgShellHandler for State {
@@ -28,7 +28,8 @@ impl XdgShellHandler for State {
// Tell the surface the preferred size and bounds for its likely output.
let output = self.niri.monitor_set.active_output().unwrap();
- configure_new_window(output_size(output), &window);
+ let working_area = layer_map_for_output(output).non_exclusive_zone();
+ configure_new_window(working_area, &window);
// At the moment of creation, xdg toplevels must have no buffer.
let existing = self.niri.unmapped_windows.insert(wl_surface, window);
diff --git a/src/layout.rs b/src/layout.rs
index 4a82396d..47a7a4b9 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -42,7 +42,7 @@ use smithay::backend::renderer::element::{AsRenderElements, Kind};
use smithay::backend::renderer::gles::GlesRenderer;
use smithay::backend::renderer::ImportAll;
use smithay::desktop::space::SpaceElement;
-use smithay::desktop::Window;
+use smithay::desktop::{layer_map_for_output, Window};
use smithay::output::Output;
use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel;
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
@@ -143,6 +143,12 @@ pub struct Workspace<W: LayoutElement> {
/// been disconnected, preserved until a new output is connected.
view_size: Size<i32, Logical>,
+ /// Latest known working area for this workspace.
+ ///
+ /// This is similar to view size, but takes into account things like layer shell exclusive
+ /// zones.
+ working_area: Rectangle<i32, Logical>,
+
/// Columns of windows on this workspace.
columns: Vec<Column<W>>,
@@ -598,16 +604,20 @@ impl<W: LayoutElement> MonitorSet<W> {
None
}
- pub fn update_output(&mut self, output: &Output) {
+ pub fn update_output_size(&mut self, output: &Output) {
let MonitorSet::Normal { monitors, .. } = self else {
panic!()
};
for mon in monitors {
if &mon.output == output {
+ let view_size = output_size(output);
+ let working_area = layer_map_for_output(output).non_exclusive_zone();
+
for ws in &mut mon.workspaces {
- ws.set_view_size(output_size(output));
+ ws.set_view_size(view_size, working_area);
}
+
break;
}
}
@@ -1390,6 +1400,7 @@ impl<W: LayoutElement> Workspace<W> {
Self {
original_output: OutputId::new(&output),
view_size: output_size(&output),
+ working_area: Rectangle::from_loc_and_size((0, 0), output_size(&output)),
output: Some(output),
columns: vec![],
active_column_idx: 0,
@@ -1405,6 +1416,7 @@ impl<W: LayoutElement> Workspace<W> {
output: None,
original_output: OutputId(String::new()),
view_size: Size::from((1280, 720)),
+ working_area: Rectangle::from_loc_and_size((0, 0), (1280, 720)),
columns: vec![],
active_column_idx: 0,
focus_ring: FocusRing::default(),
@@ -1463,7 +1475,8 @@ impl<W: LayoutElement> Workspace<W> {
self.output = output;
if let Some(output) = &self.output {
- self.set_view_size(output_size(output));
+ let working_area = layer_map_for_output(output).non_exclusive_zone();
+ self.set_view_size(output_size(output), working_area);
for win in self.windows() {
self.enter_output_for_window(win);
@@ -1481,14 +1494,16 @@ impl<W: LayoutElement> Workspace<W> {
}
}
- fn set_view_size(&mut self, size: Size<i32, Logical>) {
- if self.view_size == size {
+ fn set_view_size(&mut self, size: Size<i32, Logical>, working_area: Rectangle<i32, Logical>) {
+ if self.view_size == size && self.working_area == working_area {
return;
}
self.view_size = size;
+ self.working_area = working_area;
+
for col in &mut self.columns {
- col.update_window_sizes(self.view_size);
+ col.update_window_sizes(self.view_size, self.working_area);
}
}
@@ -1507,7 +1522,7 @@ impl<W: LayoutElement> Workspace<W> {
let new_x = self.column_x(idx) - PADDING;
let new_view_offset = compute_new_view_offset(
current_x,
- self.view_size.w,
+ self.working_area.size.w,
new_x,
self.columns[idx].size().w,
);
@@ -1553,7 +1568,7 @@ impl<W: LayoutElement> Workspace<W> {
self.active_column_idx + 1
};
- let column = Column::new(window, self.view_size);
+ let column = Column::new(window, self.view_size, self.working_area);
self.columns.insert(idx, column);
if activate {
@@ -1606,7 +1621,7 @@ impl<W: LayoutElement> Workspace<W> {
}
column.active_window_idx = min(column.active_window_idx, column.windows.len() - 1);
- column.update_window_sizes(self.view_size);
+ column.update_window_sizes(self.view_size, self.working_area);
}
fn update_window(&mut self, window: &W) {
@@ -1616,7 +1631,7 @@ impl<W: LayoutElement> Workspace<W> {
.enumerate()
.find(|(_, col)| col.contains(window))
.unwrap();
- column.update_window_sizes(self.view_size);
+ column.update_window_sizes(self.view_size, self.working_area);
if idx == self.active_column_idx {
// We might need to move the view to ensure the resized window is still visible.
@@ -1625,7 +1640,7 @@ impl<W: LayoutElement> Workspace<W> {
let new_view_offset = compute_new_view_offset(
current_x,
- self.view_size.w,
+ self.working_area.size.w,
new_x,
self.columns[idx].size().w,
);
@@ -1714,7 +1729,7 @@ impl<W: LayoutElement> Workspace<W> {
let new_x = self.column_x(self.active_column_idx) - PADDING;
let new_view_offset = compute_new_view_offset(
current_x,
- self.view_size.w,
+ self.working_area.size.w,
new_x,
self.columns[self.active_column_idx].size().w,
);
@@ -1740,7 +1755,7 @@ impl<W: LayoutElement> Workspace<W> {
let new_x = self.column_x(self.active_column_idx) - PADDING;
let new_view_offset = compute_new_view_offset(
current_x,
- self.view_size.w,
+ self.working_area.size.w,
new_x,
self.columns[self.active_column_idx].size().w,
);
@@ -1781,7 +1796,7 @@ impl<W: LayoutElement> Workspace<W> {
self.remove_window(&window);
let target_column = &mut self.columns[self.active_column_idx];
- target_column.add_window(self.view_size, window);
+ target_column.add_window(self.view_size, self.working_area, window);
}
fn expel_from_column(&mut self) {
@@ -1842,6 +1857,8 @@ impl<W: LayoutElement> Workspace<W> {
if col.is_fullscreen {
// FIXME: fullscreen windows are missing left padding
win_pos.x -= PADDING;
+ } else {
+ win_pos += self.working_area.loc;
}
if active_win.is_in_input_region(&(pos - win_pos.to_f64())) {
let mut win_pos_within_output = win_pos;
@@ -1863,6 +1880,8 @@ impl<W: LayoutElement> Workspace<W> {
// FIXME: fullscreen windows are missing left padding
win_pos.x -= PADDING;
win_pos.y -= PADDING;
+ } else {
+ win_pos += self.working_area.loc;
}
if win.is_in_input_region(&(pos - win_pos.to_f64())) {
let mut win_pos_within_output = win_pos;
@@ -1885,7 +1904,7 @@ impl<W: LayoutElement> Workspace<W> {
return;
}
- self.columns[self.active_column_idx].toggle_width(self.view_size);
+ self.columns[self.active_column_idx].toggle_width(self.view_size, self.working_area);
}
fn toggle_full_width(&mut self) {
@@ -1893,7 +1912,7 @@ impl<W: LayoutElement> Workspace<W> {
return;
}
- self.columns[self.active_column_idx].toggle_full_width(self.view_size);
+ self.columns[self.active_column_idx].toggle_full_width(self.view_size, self.working_area);
}
pub fn set_fullscreen(&mut self, window: &W, is_fullscreen: bool) {
@@ -1917,18 +1936,20 @@ impl<W: LayoutElement> Workspace<W> {
self.active_column_idx == col_idx && col.active_window_idx == win_idx;
let window = col.windows.remove(win_idx);
col.active_window_idx = min(col.active_window_idx, col.windows.len() - 1);
- col.update_window_sizes(self.view_size);
+ col.update_window_sizes(self.view_size, self.working_area);
col_idx += 1;
- self.columns
- .insert(col_idx, Column::new(window, self.view_size));
+ self.columns.insert(
+ col_idx,
+ Column::new(window, self.view_size, self.working_area),
+ );
if self.active_column_idx >= col_idx || target_window_was_focused {
self.active_column_idx += 1;
}
col = &mut self.columns[col_idx];
}
- col.set_fullscreen(self.view_size, is_fullscreen);
+ col.set_fullscreen(self.view_size, self.working_area, is_fullscreen);
}
pub fn toggle_fullscreen(&mut self, window: &W) {
@@ -1983,6 +2004,8 @@ impl Workspace<Window> {
if col.is_fullscreen {
// FIXME: fullscreen windows are missing left padding
win_pos.x -= PADDING;
+ } else {
+ win_pos += self.working_area.loc;
}
// Draw the window itself.
@@ -2013,6 +2036,8 @@ impl Workspace<Window> {
// FIXME: fullscreen windows are missing left padding
win_pos.x -= PADDING;
win_pos.y -= PADDING;
+ } else {
+ win_pos += self.working_area.loc;
}
rv.extend(win.render_elements(
@@ -2034,7 +2059,11 @@ impl Workspace<Window> {
}
impl<W: LayoutElement> Column<W> {
- fn new(window: W, view_size: Size<i32, Logical>) -> Self {
+ fn new(
+ window: W,
+ view_size: Size<i32, Logical>,
+ working_area: Rectangle<i32, Logical>,
+ ) -> Self {
let mut rv = Self {
windows: vec![],
active_window_idx: 0,
@@ -2042,7 +2071,7 @@ impl<W: LayoutElement> Column<W> {
is_fullscreen: false,
};
- rv.add_window(view_size, window);
+ rv.add_window(view_size, working_area, window);
rv
}
@@ -2051,9 +2080,14 @@ impl<W: LayoutElement> Column<W> {
self.windows.len()
}
- fn set_width(&mut self, view_size: Size<i32, Logical>, width: ColumnWidth) {
+ fn set_width(
+ &mut self,
+ view_size: Size<i32, Logical>,
+ working_area: Rectangle<i32, Logical>,
+ width: ColumnWidth,
+ ) {
self.width = width;
- self.update_window_sizes(view_size);
+ self.update_window_sizes(view_size, working_area);
}
fn contains(&self, window: &W) -> bool {
@@ -2065,13 +2099,22 @@ impl<W: LayoutElement> Column<W> {
self.active_window_idx = idx;
}
- fn add_window(&mut self, view_size: Size<i32, Logical>, window: W) {
+ fn add_window(
+ &mut self,
+ view_size: Size<i32, Logical>,
+ working_area: Rectangle<i32, Logical>,
+ window: W,
+ ) {
self.is_fullscreen = false;
self.windows.push(window);
- self.update_window_sizes(view_size);
+ self.update_window_sizes(view_size, working_area);
}
- fn update_window_sizes(&mut self, view_size: Size<i32, Logical>) {
+ fn update_window_sizes(
+ &mut self,
+ view_size: Size<i32, Logical>,
+ working_area: Rectangle<i32, Logical>,
+ ) {
if self.is_fullscreen {
self.windows[0].request_fullscreen(view_size);
return;
@@ -2105,8 +2148,8 @@ impl<W: LayoutElement> Column<W> {
.unwrap_or(i32::MAX);
let max_width = max(max_width, min_width);
- let width = self.width.resolve(view_size.w - PADDING) - PADDING;
- let height = (view_size.h - PADDING) / self.window_count() as i32 - PADDING;
+ let width = self.width.resolve(working_area.size.w - PADDING) - PADDING;
+ let height = (working_area.size.h - PADDING) / self.window_count() as i32 - PADDING;
let size = Size::from((max(min(width, max_width), min_width), max(height, 1)));
for win in &self.windows {
@@ -2165,22 +2208,32 @@ impl<W: LayoutElement> Column<W> {
}
}
- fn toggle_width(&mut self, view_size: Size<i32, Logical>) {
+ fn toggle_width(
+ &mut self,
+ view_size: Size<i32, Logical>,
+ working_area: Rectangle<i32, Logical>,
+ ) {
let idx = match self.width {
ColumnWidth::PresetProportion(idx) => (idx + 1) % WIDTH_PROPORTIONS.len(),
_ => {
let current = self.size().w;
WIDTH_PROPORTIONS
.into_iter()
- .position(|prop| prop.resolve(view_size.w - PADDING) - PADDING > current)
+ .position(|prop| {
+ prop.resolve(working_area.size.w - PADDING) - PADDING > current
+ })
.unwrap_or(0)
}
};
let width = ColumnWidth::PresetProportion(idx);
- self.set_width(view_size, width);
+ self.set_width(view_size, working_area, width);
}
- fn toggle_full_width(&mut self, view_size: Size<i32, Logical>) {
+ fn toggle_full_width(
+ &mut self,
+ view_size: Size<i32, Logical>,
+ working_area: Rectangle<i32, Logical>,
+ ) {
let width = match self.width {
ColumnWidth::Proportion(x) if x == 1. => {
// FIXME: would be good to restore to previous width here.
@@ -2188,13 +2241,18 @@ impl<W: LayoutElement> Column<W> {
}
_ => ColumnWidth::Proportion(1.),
};
- self.set_width(view_size, width);
+ self.set_width(view_size, working_area, width);
}
- fn set_fullscreen(&mut self, view_size: Size<i32, Logical>, is_fullscreen: bool) {
+ fn set_fullscreen(
+ &mut self,
+ view_size: Size<i32, Logical>,
+ working_area: Rectangle<i32, Logical>,
+ is_fullscreen: bool,
+ ) {
assert_eq!(self.windows.len(), 1);
self.is_fullscreen = is_fullscreen;
- self.update_window_sizes(view_size);
+ self.update_window_sizes(view_size, working_area);
}
fn window_y(&self, window_idx: usize) -> i32 {
@@ -2222,12 +2280,15 @@ pub fn output_size(output: &Output) -> Size<i32, Logical> {
.to_logical(output_scale)
}
-pub fn configure_new_window(view_size: Size<i32, Logical>, window: &Window) {
- let width = ColumnWidth::default().resolve(view_size.w - PADDING) - PADDING;
- let height = view_size.h - PADDING * 2;
+pub fn configure_new_window(working_area: Rectangle<i32, Logical>, window: &Window) {
+ let width = ColumnWidth::default().resolve(working_area.size.w - PADDING) - PADDING;
+ let height = working_area.size.h - PADDING * 2;
let size = Size::from((max(width, 1), max(height, 1)));
- let bounds = Size::from((view_size.w - PADDING * 2, view_size.h - PADDING * 2));
+ let bounds = Size::from((
+ working_area.size.w - PADDING * 2,
+ working_area.size.h - PADDING * 2,
+ ));
window.toplevel().with_pending_state(|state| {
state.size = Some(size);
diff --git a/src/niri.rs b/src/niri.rs
index 41c6a41e..bf1e8838 100644
--- a/src/niri.rs
+++ b/src/niri.rs
@@ -662,8 +662,8 @@ impl Niri {
}
pub fn output_resized(&mut self, output: Output) {
- self.monitor_set.update_output(&output);
layer_map_for_output(&output).arrange();
+ self.monitor_set.update_output_size(&output);
self.queue_redraw(output);
}
@@ -916,6 +916,7 @@ impl Niri {
}
// Then the upper layer-shell elements.
+ // FIXME: hide top layer when a fullscreen surface is showing somehow.
elements.extend(
upper
.into_iter()