diff options
| -rw-r--r-- | docs/wiki/Configuration:-Gestures.md | 19 | ||||
| -rw-r--r-- | docs/wiki/Configuration:-Outputs.md | 36 | ||||
| -rw-r--r-- | niri-config/src/gestures.rs | 8 | ||||
| -rw-r--r-- | niri-config/src/lib.rs | 20 | ||||
| -rw-r--r-- | niri-config/src/output.rs | 4 | ||||
| -rw-r--r-- | src/niri.rs | 61 |
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 |
