feat: support focus follows mouse

This commit is contained in:
Samuel Onoja committed 2026-09-25 02:59:07 +01:00
1 parent 29af1bec9c
commit 95b15b6e0d
3 files changed
+29 -1

No files matched your search

+7 -1
View File
@@ -112,6 +112,7 @@ struct BindingConfig {
#[derive(Clone, Debug, PartialEq)]
pub struct InputSettings {
pub focus_follows_mouse: bool,
pub xkb_layout: String,
pub xkb_variant: String,
pub xkb_options: Vec<String>,
@@ -129,6 +130,8 @@ pub struct TouchpadSettings {
#[derive(Debug, Deserialize)]
struct InputConfig {
#[serde(default)]
focus_follows_mouse: bool,
#[serde(default = "default_xkb_layout")]
xkb_layout: String,
#[serde(default)]
@@ -146,6 +149,7 @@ struct InputConfig {
impl Default for InputConfig {
fn default() -> Self {
Self {
focus_follows_mouse: false,
xkb_layout: default_xkb_layout(),
xkb_variant: String::new(),
xkb_options: Vec::new(),
@@ -454,6 +458,7 @@ impl Config {
}
Ok(InputSettings {
focus_follows_mouse: self.input.focus_follows_mouse,
xkb_layout: self.input.xkb_layout.clone(),
xkb_variant: self.input.xkb_variant.clone(),
xkb_options: self.input.xkb_options.clone(),
@@ -1095,12 +1100,13 @@ mod tests {
#[test]
fn parses_input_and_touchpad_settings() {
let config = parse(
"[input]\nxkb_layout = \"us,de\"\nxkb_variant = \",nodeadkeys\"\nxkb_options = [\"grp:alt_shift_toggle\"]\nrepeat_rate = 30\nrepeat_delay_ms = 450\n\n[input.touchpad]\ntap = false\nnatural_scroll = false\ndisable_while_typing = true",
"[input]\nfocus_follows_mouse = true\nxkb_layout = \"us,de\"\nxkb_variant = \",nodeadkeys\"\nxkb_options = [\"grp:alt_shift_toggle\"]\nrepeat_rate = 30\nrepeat_delay_ms = 450\n\n[input.touchpad]\ntap = false\nnatural_scroll = false\ndisable_while_typing = true",
);
assert_eq!(
config.input_settings().unwrap(),
InputSettings {
focus_follows_mouse: true,
xkb_layout: "us,de".to_owned(),
xkb_variant: ",nodeadkeys".to_owned(),
xkb_options: vec!["grp:alt_shift_toggle".to_owned()],
+21
View File
@@ -121,6 +121,7 @@ impl Ferese {
},
);
pointer.frame(self);
self.focus_window_under_pointer(&pointer, position);
self.activate_focused_pointer_constraint(&pointer);
crate::backends::direct::render_all(self);
}
@@ -158,6 +159,7 @@ impl Ferese {
},
);
pointer.frame(self);
self.focus_window_under_pointer(&pointer, location);
self.activate_focused_pointer_constraint(&pointer);
crate::backends::direct::render_all(self);
}
@@ -327,6 +329,25 @@ impl Ferese {
self.relayout();
}
fn focus_window_under_pointer(
&mut self,
pointer: &PointerHandle<Self>,
position: Point<f64, Logical>,
) {
if !self.input_settings.focus_follows_mouse || pointer.is_grabbed() {
return;
}
let Some(window) = self.window_under_visual(position) else {
return;
};
if self.window_ids.get(&window).copied() == self.focused_window {
return;
}
self.focus_window_at(position, SERIAL_COUNTER.next_serial());
}
fn clamp_pointer_position(&self, requested: Point<f64, Logical>) -> Point<f64, Logical> {
self.space
.outputs()