diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2025-09-02 08:07:22 +0300 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2025-10-15 09:04:16 +0300 |
| commit | e1fad994da9565b43c7fb139cb2fb7bf404cc320 (patch) | |
| tree | 305fa0714d66ad2b4346b3aee6eb785099b29fa1 /src/layout/mod.rs | |
| parent | e5d4e7c1b1a0b61770b6711a53fe41920d56452d (diff) | |
| download | niri-e1fad994da9565b43c7fb139cb2fb7bf404cc320.tar.gz niri-e1fad994da9565b43c7fb139cb2fb7bf404cc320.tar.bz2 niri-e1fad994da9565b43c7fb139cb2fb7bf404cc320.zip | |
Implement maximize-to-edges (true Wayland maximize)
Diffstat (limited to 'src/layout/mod.rs')
| -rw-r--r-- | src/layout/mod.rs | 73 |
1 files changed, 64 insertions, 9 deletions
diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 525b9eda..8761c0e3 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -118,6 +118,13 @@ niri_render_elements! { pub type LayoutElementRenderSnapshot = RenderSnapshot<BakedBuffer<TextureBuffer<GlesTexture>>, BakedBuffer<SolidColorBuffer>>; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SizingMode { + Normal, + Maximized, + Fullscreen, +} + pub trait LayoutElement { /// Type that can be used as a unique ID of this element. type Id: PartialEq + std::fmt::Debug + Clone; @@ -185,14 +192,14 @@ pub trait LayoutElement { fn request_size( &mut self, size: Size<i32, Logical>, - is_fullscreen: bool, + mode: SizingMode, animate: bool, transaction: Option<Transaction>, ); /// Requests the element to change size once, clearing the request afterwards. fn request_size_once(&mut self, size: Size<i32, Logical>, animate: bool) { - self.request_size(size, false, animate, None); + self.request_size(size, SizingMode::Normal, animate, None); } fn min_size(&self) -> Size<i32, Logical>; @@ -214,15 +221,15 @@ pub trait LayoutElement { fn configure_intent(&self) -> ConfigureIntent; fn send_pending_configure(&mut self); - /// Whether the element is currently fullscreen. + /// The element's current sizing mode. /// /// This will *not* switch immediately after a [`LayoutElement::request_size()`] call. - fn is_fullscreen(&self) -> bool; + fn sizing_mode(&self) -> SizingMode; - /// Whether we're requesting the element to be fullscreen. + /// The sizing mode that we're requesting the element to assume. /// /// This *will* switch immediately after a [`LayoutElement::request_size()`] call. - fn is_pending_fullscreen(&self) -> bool; + fn pending_sizing_mode(&self) -> SizingMode; /// Size previously requested through [`LayoutElement::request_size()`]. fn requested_size(&self) -> Option<Size<i32, Logical>>; @@ -240,7 +247,7 @@ pub trait LayoutElement { /// /// The default impl is for testing only, it will not preserve the window's own size changes. fn expected_size(&self) -> Option<Size<i32, Logical>> { - if self.is_fullscreen() { + if self.sizing_mode().is_fullscreen() { return None; } @@ -502,6 +509,23 @@ struct OverviewGesture { value: f64, } +impl SizingMode { + #[must_use] + pub fn is_normal(&self) -> bool { + matches!(self, Self::Normal) + } + + #[must_use] + pub fn is_fullscreen(&self) -> bool { + matches!(self, Self::Fullscreen) + } + + #[must_use] + pub fn is_maximized(&self) -> bool { + matches!(self, Self::Maximized) + } +} + impl<W: LayoutElement> InteractiveMoveState<W> { fn moving(&self) -> Option<&InteractiveMoveData<W>> { match self { @@ -2321,7 +2345,7 @@ impl<W: LayoutElement> Layout<W> { } InteractiveMoveState::Moving(move_) => { assert_eq!(self.clock, move_.tile.clock); - assert!(!move_.tile.window().is_pending_fullscreen()); + assert!(move_.tile.window().pending_sizing_mode().is_normal()); move_.tile.verify_invariants(); @@ -3456,7 +3480,7 @@ impl<W: LayoutElement> Layout<W> { pub fn toggle_windowed_fullscreen(&mut self, id: &W::Id) { let (_, window) = self.windows().find(|(_, win)| win.id() == id).unwrap(); - if window.is_pending_fullscreen() { + if window.pending_sizing_mode().is_fullscreen() { // Remove the real fullscreen. for ws in self.workspaces_mut() { if ws.has_window(id) { @@ -3474,6 +3498,36 @@ impl<W: LayoutElement> Layout<W> { }); } + pub fn set_maximized(&mut self, id: &W::Id, maximize: bool) { + if let Some(InteractiveMoveState::Moving(move_)) = &self.interactive_move { + if move_.tile.window().id() == id { + return; + } + } + + for ws in self.workspaces_mut() { + if ws.has_window(id) { + ws.set_maximized(id, maximize); + return; + } + } + } + + pub fn toggle_maximized(&mut self, id: &W::Id) { + if let Some(InteractiveMoveState::Moving(move_)) = &self.interactive_move { + if move_.tile.window().id() == id { + return; + } + } + + for ws in self.workspaces_mut() { + if ws.has_window(id) { + ws.toggle_maximized(id); + return; + } + } + } + pub fn workspace_switch_gesture_begin(&mut self, output: &Output, is_touchpad: bool) { let monitors = match &mut self.monitor_set { MonitorSet::Normal { monitors, .. } => monitors, @@ -3845,6 +3899,7 @@ impl<W: LayoutElement> Layout<W> { .find(|ws| ws.has_window(&window_id)) .unwrap(); ws.set_fullscreen(window, false); + ws.set_maximized(window, false); let RemovedTile { mut tile, |
