Add option to warp-mouse-to-focus to always center

This commit is contained in:
Florian Finkernagel
2025-03-13 14:55:16 +01:00
committed by Ivan Molodetskikh
parent 0d4f0f00c0
commit 7f72c358d5
3 changed files with 71 additions and 15 deletions
+32 -2
View File
@@ -95,7 +95,7 @@ pub struct Input {
#[knuffel(child)] #[knuffel(child)]
pub disable_power_key_handling: bool, pub disable_power_key_handling: bool,
#[knuffel(child)] #[knuffel(child)]
pub warp_mouse_to_focus: bool, pub warp_mouse_to_focus: Option<WarpMouseToFocus>,
#[knuffel(child)] #[knuffel(child)]
pub focus_follows_mouse: Option<FocusFollowsMouse>, pub focus_follows_mouse: Option<FocusFollowsMouse>,
#[knuffel(child)] #[knuffel(child)]
@@ -369,6 +369,32 @@ pub struct FocusFollowsMouse {
pub max_scroll_amount: Option<Percent>, pub max_scroll_amount: Option<Percent>,
} }
#[derive(knuffel::Decode, Debug, PartialEq, Eq, Clone, Copy)]
pub struct WarpMouseToFocus {
#[knuffel(property, str)]
pub mode: Option<WarpMouseToFocusMode>,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum WarpMouseToFocusMode {
CenterXy,
CenterXyAlways,
}
impl FromStr for WarpMouseToFocusMode {
type Err = miette::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"center-xy" => Ok(Self::CenterXy),
"center-xy-always" => Ok(Self::CenterXyAlways),
_ => Err(miette!(
r#"invalid mode for warp-mouse-to-focus, can be "center-xy" or "center-xy-always" (or leave unset for separate centering)"#
)),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct Percent(pub f64); pub struct Percent(pub f64);
@@ -4023,7 +4049,11 @@ mod tests {
), ),
}, },
disable_power_key_handling: true, disable_power_key_handling: true,
warp_mouse_to_focus: true, warp_mouse_to_focus: Some(
WarpMouseToFocus {
mode: None,
},
),
focus_follows_mouse: Some( focus_follows_mouse: Some(
FocusFollowsMouse { FocusFollowsMouse {
max_scroll_amount: None, max_scroll_amount: None,
+23 -12
View File
@@ -14,8 +14,8 @@ use _server_decoration::server::org_kde_kwin_server_decoration_manager::Mode as
use anyhow::{bail, ensure, Context}; use anyhow::{bail, ensure, Context};
use calloop::futures::Scheduler; use calloop::futures::Scheduler;
use niri_config::{ use niri_config::{
Config, FloatOrInt, Key, Modifiers, OutputName, PreviewRender, TrackLayout, WorkspaceReference, Config, FloatOrInt, Key, Modifiers, OutputName, PreviewRender, TrackLayout,
DEFAULT_BACKGROUND_COLOR, WarpMouseToFocusMode, WorkspaceReference, DEFAULT_BACKGROUND_COLOR,
}; };
use smithay::backend::allocator::Fourcc; use smithay::backend::allocator::Fourcc;
use smithay::backend::input::Keycode; use smithay::backend::input::Keycode;
@@ -510,6 +510,8 @@ struct SurfaceFrameThrottlingState {
pub enum CenterCoords { pub enum CenterCoords {
Separately, Separately,
Both, Both,
// Force centering even if the cursor is already in the rectangle.
BothAlways,
} }
#[derive(Clone, PartialEq, Eq)] #[derive(Clone, PartialEq, Eq)]
@@ -753,6 +755,7 @@ impl State {
center_f64(rect) center_f64(rect)
} }
} }
CenterCoords::BothAlways => center_f64(rect),
}; };
self.move_cursor(p); self.move_cursor(p);
@@ -808,19 +811,27 @@ impl State {
} }
pub fn maybe_warp_cursor_to_focus(&mut self) -> bool { pub fn maybe_warp_cursor_to_focus(&mut self) -> bool {
if !self.niri.config.borrow().input.warp_mouse_to_focus { let focused = match self.niri.config.borrow().input.warp_mouse_to_focus {
return false; None => return false,
} Some(inner) => match inner.mode {
None => CenterCoords::Separately,
self.move_cursor_to_focused_tile(CenterCoords::Separately) Some(WarpMouseToFocusMode::CenterXy) => CenterCoords::Both,
Some(WarpMouseToFocusMode::CenterXyAlways) => CenterCoords::BothAlways,
},
};
self.move_cursor_to_focused_tile(focused)
} }
pub fn maybe_warp_cursor_to_focus_centered(&mut self) -> bool { pub fn maybe_warp_cursor_to_focus_centered(&mut self) -> bool {
if !self.niri.config.borrow().input.warp_mouse_to_focus { let focused = match self.niri.config.borrow().input.warp_mouse_to_focus {
return false; None => return false,
} Some(inner) => match inner.mode {
None => CenterCoords::Both,
self.move_cursor_to_focused_tile(CenterCoords::Both) Some(WarpMouseToFocusMode::CenterXy) => CenterCoords::Both,
Some(WarpMouseToFocusMode::CenterXyAlways) => CenterCoords::BothAlways,
},
};
self.move_cursor_to_focused_tile(focused)
} }
pub fn refresh_pointer_contents(&mut self) { pub fn refresh_pointer_contents(&mut self) {
+16 -1
View File
@@ -243,7 +243,7 @@ input {
Makes the mouse warp to newly focused windows. Makes the mouse warp to newly focused windows.
X and Y coordinates are computed separately, i.e. if moving the mouse only horizontally is enough to put it inside the newly focused window, then it will move only horizontally. Does not make the cursor visible if it had been hidden.
```kdl ```kdl
input { input {
@@ -251,6 +251,21 @@ input {
} }
``` ```
By default, the cursor warps *separately* horizontally and vertically.
I.e. if moving the mouse only horizontally is enough to put it inside the newly focused window, then the mouse will move only horizontally, and not vertically.
<sup>Since: next release</sup> You can customize this with the `mode` property.
- `mode="center-xy"`: warps by both X and Y coordinates together.
So if the mouse was anywhere outside the newly focused window, it will warp to the center of the window.
- `mode="center-xy-always"`: warps by both X and Y coordinates together, even if the mouse was already somewhere inside the newly focused window.
```kdl
input {
warp-mouse-to-focus mode="center-xy"
}
```
#### `focus-follows-mouse` #### `focus-follows-mouse`
Focuses windows and outputs automatically when moving the mouse over them. Focuses windows and outputs automatically when moving the mouse over them.