aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/wiki/Configuration:-Gestures.md19
-rw-r--r--docs/wiki/Configuration:-Outputs.md36
-rw-r--r--niri-config/src/gestures.rs8
-rw-r--r--niri-config/src/lib.rs20
-rw-r--r--niri-config/src/output.rs4
-rw-r--r--src/niri.rs61
6 files changed, 135 insertions, 13 deletions
diff --git a/docs/wiki/Configuration:-Gestures.md b/docs/wiki/Configuration:-Gestures.md
index bdb7a407..ee8d108e 100644
--- a/docs/wiki/Configuration:-Gestures.md
+++ b/docs/wiki/Configuration:-Gestures.md
@@ -23,6 +23,10 @@ gestures {
hot-corners {
// off
+ top-left
+ // top-right
+ // bottom-left
+ // bottom-right
}
}
```
@@ -94,3 +98,18 @@ gestures {
}
}
```
+
+<sup>Since: next release</sup> You can choose specific hot corners by name: `top-left`, `top-right`, `bottom-left`, `bottom-right`.
+If no corners are explicitly set, the top-left corner will be active by default.
+
+```kdl
+// Enable the top-right and bottom-right hot corners.
+gestures {
+ hot-corners {
+ top-right
+ bottom-right
+ }
+}
+```
+
+You can also customize hot corners per-output [in the output config](./Configuration:-Outputs.md#hot-corners).
diff --git a/docs/wiki/Configuration:-Outputs.md b/docs/wiki/Configuration:-Outputs.md
index 0db7956d..a84a068f 100644
--- a/docs/wiki/Configuration:-Outputs.md
+++ b/docs/wiki/Configuration:-Outputs.md
@@ -16,6 +16,14 @@ output "eDP-1" {
focus-at-startup
background-color "#003300"
backdrop-color "#001100"
+
+ hot-corners {
+ // off
+ top-left
+ // top-right
+ // bottom-left
+ // bottom-right
+ }
}
output "HDMI-A-1" {
@@ -217,3 +225,31 @@ output "HDMI-A-1" {
backdrop-color "#001100"
}
```
+
+### `hot-corners`
+
+<sup>Since: next release</sup>
+
+Customize the hot corners for this output.
+By default, hot corners [in the gestures settings](./Configuration:-Gestures.md#hot-corners) are used for all outputs.
+
+Hot corners toggle the overview when you put your mouse at the very corner of a monitor.
+
+`off` will disable the hot corners on this output, and writing specific corners will enable only those hot corners on this output.
+
+```kdl
+// Enable the bottom-left and bottom-right hot corners on HDMI-A-1.
+output "HDMI-A-1" {
+ hot-corners {
+ bottom-left
+ bottom-right
+ }
+}
+
+// Disable the hot corners on DP-2.
+output "DP-2" {
+ hot-corners {
+ off
+ }
+}
+```
diff --git a/niri-config/src/gestures.rs b/niri-config/src/gestures.rs
index 893cc053..8c4b1363 100644
--- a/niri-config/src/gestures.rs
+++ b/niri-config/src/gestures.rs
@@ -54,4 +54,12 @@ impl Default for DndEdgeWorkspaceSwitch {
pub struct HotCorners {
#[knuffel(child)]
pub off: bool,
+ #[knuffel(child)]
+ pub top_left: bool,
+ #[knuffel(child)]
+ pub top_right: bool,
+ #[knuffel(child)]
+ pub bottom_left: bool,
+ #[knuffel(child)]
+ pub bottom_right: bool,
}
diff --git a/niri-config/src/lib.rs b/niri-config/src/lib.rs
index 8e07839e..e795b46e 100644
--- a/niri-config/src/lib.rs
+++ b/niri-config/src/lib.rs
@@ -348,6 +348,13 @@ mod tests {
mode "1920x1080@144"
variable-refresh-rate on-demand=true
background-color "rgba(25, 25, 102, 1.0)"
+ hot-corners {
+ off
+ top-left
+ top-right
+ bottom-left
+ bottom-right
+ }
}
layout {
@@ -742,6 +749,15 @@ mod tests {
},
),
backdrop_color: None,
+ hot_corners: Some(
+ HotCorners {
+ off: true,
+ top_left: true,
+ top_right: true,
+ bottom_left: true,
+ bottom_right: true,
+ },
+ ),
},
],
),
@@ -1158,6 +1174,10 @@ mod tests {
},
hot_corners: HotCorners {
off: false,
+ top_left: false,
+ top_right: false,
+ bottom_left: false,
+ bottom_right: false,
},
},
overview: Overview {
diff --git a/niri-config/src/output.rs b/niri-config/src/output.rs
index 9b12aa7b..b0e1d26c 100644
--- a/niri-config/src/output.rs
+++ b/niri-config/src/output.rs
@@ -1,5 +1,6 @@
use niri_ipc::{ConfiguredMode, Transform};
+use crate::gestures::HotCorners;
use crate::{Color, FloatOrInt};
#[derive(Debug, Default, Clone, PartialEq)]
@@ -27,6 +28,8 @@ pub struct Output {
pub background_color: Option<Color>,
#[knuffel(child)]
pub backdrop_color: Option<Color>,
+ #[knuffel(child)]
+ pub hot_corners: Option<HotCorners>,
}
impl Output {
@@ -56,6 +59,7 @@ impl Default for Output {
variable_refresh_rate: None,
background_color: None,
backdrop_color: None,
+ hot_corners: None,
}
}
}
diff --git a/src/niri.rs b/src/niri.rs
index 612d5417..cb309830 100644
--- a/src/niri.rs
+++ b/src/niri.rs
@@ -3118,6 +3118,49 @@ impl Niri {
Some((output, pos_within_output))
}
+ fn is_inside_hot_corner(&self, output: &Output, pos: Point<f64, Logical>) -> bool {
+ let config = self.config.borrow();
+ let hot_corners = output
+ .user_data()
+ .get::<OutputName>()
+ .and_then(|name| config.outputs.find(name))
+ .and_then(|c| c.hot_corners)
+ .unwrap_or(config.gestures.hot_corners);
+
+ if hot_corners.off {
+ return false;
+ }
+
+ // Use size from the ceiled output geometry, since that's what we currently use for pointer
+ // motion clamping.
+ let geom = self.global_space.output_geometry(output).unwrap();
+ let size = geom.size.to_f64();
+
+ let contains = move |corner: Point<f64, Logical>| {
+ Rectangle::new(corner, Size::new(1., 1.)).contains(pos)
+ };
+
+ if hot_corners.top_right && contains(Point::new(size.w - 1., 0.)) {
+ return true;
+ }
+ if hot_corners.bottom_left && contains(Point::new(0., size.h - 1.)) {
+ return true;
+ }
+ if hot_corners.bottom_right && contains(Point::new(size.w - 1., size.h - 1.)) {
+ return true;
+ }
+
+ // If the user didn't explicitly set any corners, we default to top-left.
+ if (hot_corners.top_left
+ || !(hot_corners.top_right || hot_corners.bottom_right || hot_corners.bottom_left))
+ && contains(Point::new(0., 0.))
+ {
+ return true;
+ }
+
+ false
+ }
+
pub fn is_sticky_obscured_under(
&self,
output: &Output,
@@ -3161,12 +3204,8 @@ impl Niri {
return false;
}
- let hot_corners = self.config.borrow().gestures.hot_corners;
- if !hot_corners.off {
- let hot_corner = Rectangle::from_size(Size::from((1., 1.)));
- if hot_corner.contains(pos_within_output) {
- return true;
- }
+ if self.is_inside_hot_corner(output, pos_within_output) {
+ return true;
}
if layer_popup_under(Layer::Top) || layer_toplevel_under(Layer::Top) {
@@ -3438,13 +3477,9 @@ impl Niri {
.or_else(|| layer_toplevel_under(Layer::Bottom))
.or_else(|| layer_toplevel_under(Layer::Background));
} else {
- let hot_corners = self.config.borrow().gestures.hot_corners;
- if !hot_corners.off {
- let hot_corner = Rectangle::from_size(Size::from((1., 1.)));
- if hot_corner.contains(pos_within_output) {
- rv.hot_corner = true;
- return rv;
- }
+ if self.is_inside_hot_corner(output, pos_within_output) {
+ rv.hot_corner = true;
+ return rv;
}
under = under