aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-12-30 13:22:02 +0300
committerIvan Molodetskikh <yalterz@gmail.com>2024-12-30 20:12:37 +0300
commit793e92e9d69f3640754d9ece40ddc7723cf49292 (patch)
tree3137096aa90fb1685becf1e78c0b97fbad10f4d8
parenta7c57f4fafabed609ef75b92715beb4e7335d823 (diff)
downloadniri-793e92e9d69f3640754d9ece40ddc7723cf49292.tar.gz
niri-793e92e9d69f3640754d9ece40ddc7723cf49292.tar.bz2
niri-793e92e9d69f3640754d9ece40ddc7723cf49292.zip
Add default-floating-position relative-to property
-rw-r--r--niri-config/src/lib.rs14
-rw-r--r--src/layout/floating.rs30
-rw-r--r--src/layout/tile.rs5
-rw-r--r--src/layout/workspace.rs13
-rw-r--r--wiki/Configuration:-Window-Rules.md13
5 files changed, 49 insertions, 26 deletions
diff --git a/niri-config/src/lib.rs b/niri-config/src/lib.rs
index e7de610c..1de7b159 100644
--- a/niri-config/src/lib.rs
+++ b/niri-config/src/lib.rs
@@ -1090,6 +1090,17 @@ pub struct FoIPosition {
pub x: FloatOrInt<-65535, 65535>,
#[knuffel(property)]
pub y: FloatOrInt<-65535, 65535>,
+ #[knuffel(property, default)]
+ pub relative_to: RelativeTo,
+}
+
+#[derive(knuffel::DecodeScalar, Debug, Default, Clone, Copy, PartialEq, Eq)]
+pub enum RelativeTo {
+ #[default]
+ TopLeft,
+ TopRight,
+ BottomLeft,
+ BottomRight,
}
#[derive(Debug, Default, PartialEq)]
@@ -3214,7 +3225,7 @@ mod tests {
open-floating false
open-focused true
default-window-height { fixed 500; }
- default-floating-position x=100 y=-200
+ default-floating-position x=100 y=-200 relative-to="bottom-left"
focus-ring {
off
@@ -3502,6 +3513,7 @@ mod tests {
default_floating_position: Some(FoIPosition {
x: FloatOrInt(100.),
y: FloatOrInt(-200.),
+ relative_to: RelativeTo::BottomLeft,
}),
focus_ring: BorderRule {
off: true,
diff --git a/src/layout/floating.rs b/src/layout/floating.rs
index 5302e158..faeca273 100644
--- a/src/layout/floating.rs
+++ b/src/layout/floating.rs
@@ -2,7 +2,7 @@ use std::cmp::max;
use std::iter::zip;
use std::rc::Rc;
-use niri_config::PresetSize;
+use niri_config::{PresetSize, RelativeTo};
use niri_ipc::{PositionChange, SizeChange};
use smithay::backend::renderer::gles::GlesRenderer;
use smithay::utils::{Logical, Point, Rectangle, Scale, Serial, Size};
@@ -415,12 +415,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
}
}
- let pos = tile.floating_pos.map(|pos| self.scale_by_working_area(pos));
- let pos = pos.or_else(|| {
- tile.default_floating_logical_pos()
- .map(|pos| pos + self.working_area.loc)
- });
- let pos = pos.unwrap_or_else(|| {
+ let pos = self.stored_or_default_tile_pos(&tile).unwrap_or_else(|| {
center_preferring_top_left_in_area(self.working_area, tile.tile_size())
});
@@ -1191,6 +1186,27 @@ impl<W: LayoutElement> FloatingSpace<W> {
Size::from((width, height))
}
+ pub fn stored_or_default_tile_pos(&self, tile: &Tile<W>) -> Option<Point<f64, Logical>> {
+ let pos = tile.floating_pos.map(|pos| self.scale_by_working_area(pos));
+ pos.or_else(|| {
+ tile.window().rules().default_floating_position.map(|pos| {
+ let relative_to = pos.relative_to;
+ let size = tile.tile_size();
+ let area = self.working_area;
+
+ let mut pos = Point::from((pos.x.0, pos.y.0));
+ if relative_to == RelativeTo::TopRight || relative_to == RelativeTo::BottomRight {
+ pos.x = area.size.w - size.w - pos.x;
+ }
+ if relative_to == RelativeTo::BottomLeft || relative_to == RelativeTo::BottomRight {
+ pos.y = area.size.h - size.h - pos.y;
+ }
+
+ pos + self.working_area.loc
+ })
+ })
+ }
+
#[cfg(test)]
pub fn view_size(&self) -> Size<f64, Logical> {
self.view_size
diff --git a/src/layout/tile.rs b/src/layout/tile.rs
index d0750d33..96936d26 100644
--- a/src/layout/tile.rs
+++ b/src/layout/tile.rs
@@ -999,11 +999,6 @@ impl<W: LayoutElement> Tile<W> {
&self.options
}
- pub fn default_floating_logical_pos(&self) -> Option<Point<f64, Logical>> {
- let pos = self.window().rules().default_floating_position?;
- Some(Point::from((pos.x.0, pos.y.0)))
- }
-
#[cfg(test)]
pub fn view_size(&self) -> Size<f64, Logical> {
self.view_size
diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs
index 113b6df0..25a03987 100644
--- a/src/layout/workspace.rs
+++ b/src/layout/workspace.rs
@@ -1143,9 +1143,8 @@ impl<W: LayoutElement> Workspace<W> {
removed.tile.stop_move_animations();
// Come up with a default floating position close to the tile position.
- if removed.tile.floating_pos.is_none()
- && removed.tile.default_floating_logical_pos().is_none()
- {
+ let stored_or_default = self.floating.stored_or_default_tile_pos(&removed.tile);
+ if stored_or_default.is_none() {
let offset = if self.options.center_focused_column == CenterFocusedColumn::Always {
Point::from((0., 0.))
} else {
@@ -1236,13 +1235,7 @@ impl<W: LayoutElement> Workspace<W> {
};
let working_area_loc = self.floating.working_area().loc;
- let pos = tile
- .floating_pos
- .map(|pos| self.floating.scale_by_working_area(pos));
- let pos = pos.or_else(|| {
- tile.default_floating_logical_pos()
- .map(|pos| pos + working_area_loc)
- });
+ let pos = self.floating.stored_or_default_tile_pos(tile);
// If there's no stored floating position, we can only set both components at once, not
// adjust.
diff --git a/wiki/Configuration:-Window-Rules.md b/wiki/Configuration:-Window-Rules.md
index 6fd5e2a8..131dfac8 100644
--- a/wiki/Configuration:-Window-Rules.md
+++ b/wiki/Configuration:-Window-Rules.md
@@ -52,7 +52,7 @@ window-rule {
block-out-from "screencast"
// block-out-from "screen-capture"
variable-refresh-rate true
- default-floating-position x=100 y=200
+ default-floating-position x=100 y=200 relative-to="bottom-left"
focus-ring {
// off
@@ -523,15 +523,22 @@ Afterward, the window will remember its last floating position.
By default, new floating windows open at the center of the screen, and windows from the tiling layout open close to their visual screen position.
The position uses logical coordinates relative to the working area.
+By default, they are relative to the top-left corner of the working area, but you can change this by setting `relative-to` to one of these values: `top-left`, `top-right`, `bottom-left`, `bottom-right`.
+
For example, if you have a bar at the top, then `x=0 y=0` will put the top-left corner of the window directly below the bar.
+If instead you write `x=0 y=0 relative-to="top-right"`, then the top-right corner of the window will align with the top-right corner of the workspace, also directly below the bar.
+
+The coordinates change direction based on `relative-to`.
+For example, by default (top-left), `x=100 y=200` will put the window 100 pixels to the right and 200 pixels down from the top-left corner.
+If you use `x=100 y=200 relative-to="bottom-left"`, it will put the window 100 pixels to the right and 200 pixels *up* from the bottom-left corner.
```kdl
-// Open the Firefox picture-in-picture window at the top-left corner of the screen
+// Open the Firefox picture-in-picture window at the bottom-left corner of the screen
// with a small gap.
window-rule {
match app-id="firefox$" title="^Picture-in-Picture$"
- default-floating-position x=32 y=32
+ default-floating-position x=32 y=32 relative-to="bottom-left"
}
```