mirror of
https://github.com/YaLTeR/niri.git
synced 2025-10-06 00:23:14 +02:00
Make hot corners configurable, including per-output (#2108)
* Add corner selection in config * Add hot corner docs * Working per-monitor hot corners Handle defaults * run cargo fmt --all * Fix hot corners in is_sticky_obscured_under * Change default to fall back to gesture hot corners if output hot corners are unset * Add hot corner output config docs * Support fractional scaling * Trigger hot corners over widgets * Improve float handling Fixed YaLTeR/niri/pull/2108 * Refactor * Bug Fixes * Amend docs Fix styling Co-authored-by: Ivan Molodetskikh <yalterz@gmail.com> * Integrate code review Move is_inside_hot_corner * fixes --------- Co-authored-by: Aadniz <8147434+Aadniz@users.noreply.github.com> Co-authored-by: Ivan Molodetskikh <yalterz@gmail.com>
This commit is contained in:
@@ -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).
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@@ -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,
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
61
src/niri.rs
61
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
|
||||
|
Reference in New Issue
Block a user