aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2023-09-30 11:33:02 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2023-09-30 11:33:02 +0400
commit21737abbfdb78698e323c0a9490759b427370a74 (patch)
tree37b702f5fbdebedfef99490b1b5be92d7c7b9597 /src
parenta413f3e91d3538cc16d82880129732df7e31ec86 (diff)
downloadniri-21737abbfdb78698e323c0a9490759b427370a74.tar.gz
niri-21737abbfdb78698e323c0a9490759b427370a74.tar.bz2
niri-21737abbfdb78698e323c0a9490759b427370a74.zip
Make output position configurable
Implements https://github.com/YaLTeR/niri/issues/14
Diffstat (limited to 'src')
-rw-r--r--src/config.rs13
-rw-r--r--src/niri.rs70
2 files changed, 74 insertions, 9 deletions
diff --git a/src/config.rs b/src/config.rs
index 82ff7fb2..a261c64c 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -77,6 +77,8 @@ pub struct Output {
pub name: String,
#[knuffel(child, unwrap(argument), default = 1.)]
pub scale: f64,
+ #[knuffel(child)]
+ pub position: Option<Position>,
}
impl Default for Output {
@@ -84,11 +86,20 @@ impl Default for Output {
Self {
name: String::new(),
scale: 1.,
+ position: None,
}
}
}
#[derive(knuffel::Decode, Debug, Clone, PartialEq, Eq)]
+pub struct Position {
+ #[knuffel(property)]
+ pub x: i32,
+ #[knuffel(property)]
+ pub y: i32,
+}
+
+#[derive(knuffel::Decode, Debug, Clone, PartialEq, Eq)]
pub struct SpawnAtStartup {
#[knuffel(arguments)]
pub command: Vec<String>,
@@ -342,6 +353,7 @@ mod tests {
output "eDP-1" {
scale 2.0
+ position x=10 y=20
}
spawn-at-startup "alacritty" "-e" "fish"
@@ -387,6 +399,7 @@ mod tests {
outputs: vec![Output {
name: "eDP-1".to_owned(),
scale: 2.,
+ position: Some(Position { x: 10, y: 20 }),
}],
spawn_at_startup: vec![SpawnAtStartup {
command: vec!["alacritty".to_owned(), "-e".to_owned(), "fish".to_owned()],
diff --git a/src/niri.rs b/src/niri.rs
index 6f152a00..48761702 100644
--- a/src/niri.rs
+++ b/src/niri.rs
@@ -74,7 +74,7 @@ use crate::dbus::mutter_display_config::DisplayConfig;
use crate::dbus::mutter_screen_cast::{self, ScreenCast, ToNiriMsg};
use crate::dbus::mutter_service_channel::ServiceChannel;
use crate::frame_clock::FrameClock;
-use crate::layout::{MonitorRenderElement, MonitorSet};
+use crate::layout::{output_size, MonitorRenderElement, MonitorSet};
use crate::pw_utils::{Cast, PipeWire};
use crate::utils::{center, get_monotonic_time, load_default_cursor, make_screenshot_path};
@@ -668,15 +668,67 @@ impl Niri {
pub fn add_output(&mut self, output: Output, refresh_interval: Option<Duration>) {
let global = output.create_global::<State>(&self.display_handle);
- let x = self
- .global_space
- .outputs()
- .map(|output| self.global_space.output_geometry(output).unwrap())
- .map(|geom| geom.loc.x + geom.size.w)
- .max()
- .unwrap_or(0);
+ let name = output.name();
+ let config = self
+ .config
+ .borrow()
+ .outputs
+ .iter()
+ .find(|o| o.name == name)
+ .cloned()
+ .unwrap_or_default();
+
+ let size = output_size(&output);
+ let position = config
+ .position
+ .map(|pos| Point::from((pos.x, pos.y)))
+ .filter(|pos| {
+ // Ensure that the requested position does not overlap any existing output.
+ let target_geom = Rectangle::from_loc_and_size(*pos, size);
+
+ let overlap = self
+ .global_space
+ .outputs()
+ .map(|output| self.global_space.output_geometry(output).unwrap())
+ .find(|geom| geom.overlaps(target_geom));
+
+ if let Some(overlap) = overlap {
+ warn!(
+ "new output {name} at x={} y={} sized {}x{} \
+ overlaps an existing output at x={} y={} sized {}x{}, \
+ falling back to automatic placement",
+ pos.x,
+ pos.y,
+ size.w,
+ size.h,
+ overlap.loc.x,
+ overlap.loc.y,
+ overlap.size.w,
+ overlap.size.h,
+ );
+
+ false
+ } else {
+ true
+ }
+ })
+ .unwrap_or_else(|| {
+ let x = self
+ .global_space
+ .outputs()
+ .map(|output| self.global_space.output_geometry(output).unwrap())
+ .map(|geom| geom.loc.x + geom.size.w)
+ .max()
+ .unwrap_or(0);
+
+ Point::from((x, 0))
+ });
- self.global_space.map_output(&output, (x, 0));
+ debug!(
+ "putting new output {name} at x={} y={}",
+ position.x, position.y
+ );
+ self.global_space.map_output(&output, position);
self.monitor_set.add_output(output.clone());
let state = OutputState {