aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--niri-config/src/lib.rs10
-rw-r--r--src/input/mod.rs45
-rw-r--r--src/niri.rs21
3 files changed, 74 insertions, 2 deletions
diff --git a/niri-config/src/lib.rs b/niri-config/src/lib.rs
index cf55ecf1..bf08e1ba 100644
--- a/niri-config/src/lib.rs
+++ b/niri-config/src/lib.rs
@@ -615,6 +615,10 @@ pub struct Cursor {
pub xcursor_theme: String,
#[knuffel(child, unwrap(argument), default = 24)]
pub xcursor_size: u8,
+ #[knuffel(child)]
+ pub hide_on_key_press: bool,
+ #[knuffel(child, unwrap(argument))]
+ pub hide_after_inactive_ms: Option<u32>,
}
impl Default for Cursor {
@@ -622,6 +626,8 @@ impl Default for Cursor {
Self {
xcursor_theme: String::from("default"),
xcursor_size: 24,
+ hide_on_key_press: false,
+ hide_after_inactive_ms: None,
}
}
}
@@ -2953,6 +2959,8 @@ mod tests {
cursor {
xcursor-theme "breeze_cursors"
xcursor-size 16
+ hide-on-key-press
+ hide-after-inactive-ms 3000
}
screenshot-path "~/Screenshots/screenshot.png"
@@ -3154,6 +3162,8 @@ mod tests {
cursor: Cursor {
xcursor_theme: String::from("breeze_cursors"),
xcursor_size: 16,
+ hide_on_key_press: true,
+ hide_after_inactive_ms: Some(3000),
},
screenshot_path: Some(String::from("~/Screenshots/screenshot.png")),
hotkey_overlay: HotkeyOverlay {
diff --git a/src/input/mod.rs b/src/input/mod.rs
index 53781047..440fcb36 100644
--- a/src/input/mod.rs
+++ b/src/input/mod.rs
@@ -2,7 +2,7 @@ use std::any::Any;
use std::cmp::min;
use std::collections::hash_map::Entry;
use std::collections::HashSet;
-use std::time::Duration;
+use std::time::{Duration, Instant};
use calloop::timer::{TimeoutAction, Timer};
use input::event::gesture::GestureEventCoordinates as _;
@@ -87,6 +87,10 @@ impl State {
}
}
+ if should_update_cursor_timeout(&event) {
+ self.niri.last_cursor_movement = Instant::now();
+ }
+
let hide_hotkey_overlay =
self.niri.hotkey_overlay.is_open() && should_hide_hotkey_overlay(&event);
@@ -307,6 +311,10 @@ impl State {
}
}
+ if pressed {
+ self.hide_cursor_if_needed();
+ }
+
let Some(Some(bind)) = self.niri.seat.get_keyboard().unwrap().input(
self,
event.key_code(),
@@ -349,7 +357,10 @@ impl State {
self.handle_bind(bind.clone());
- // Start the key repeat timer if necessary.
+ self.start_key_repeat(bind);
+ }
+
+ fn start_key_repeat(&mut self, bind: Bind) {
if !bind.repeat {
return;
}
@@ -383,6 +394,22 @@ impl State {
self.niri.bind_repeat_timer = Some(token);
}
+ fn hide_cursor_if_needed(&mut self) {
+ if !self.niri.config.borrow().cursor.hide_on_key_press {
+ return;
+ }
+
+ // niri keeps this set only while actively using a tablet, which means the cursor position
+ // is likely to change almost immediately, causing pointer_hidden to just flicker back and
+ // forth.
+ if self.niri.tablet_cursor_location.is_some() {
+ return;
+ }
+
+ self.niri.pointer_hidden = true;
+ self.niri.queue_redraw_all();
+ }
+
pub fn handle_bind(&mut self, bind: Bind) {
let Some(cooldown) = bind.cooldown else {
self.do_action(bind.action, bind.allow_when_locked);
@@ -2534,6 +2561,20 @@ fn should_notify_activity<I: InputBackend>(event: &InputEvent<I>) -> bool {
)
}
+fn should_update_cursor_timeout<I: InputBackend>(event: &InputEvent<I>) -> bool {
+ matches!(
+ event,
+ InputEvent::PointerAxis { .. }
+ | InputEvent::PointerButton { .. }
+ | InputEvent::PointerMotion { .. }
+ | InputEvent::PointerMotionAbsolute { .. }
+ | InputEvent::TabletToolAxis { .. }
+ | InputEvent::TabletToolButton { .. }
+ | InputEvent::TabletToolProximity { .. }
+ | InputEvent::TabletToolTip { .. }
+ )
+}
+
fn allowed_when_locked(action: &Action) -> bool {
matches!(
action,
diff --git a/src/niri.rs b/src/niri.rs
index 396852bf..6119c4d6 100644
--- a/src/niri.rs
+++ b/src/niri.rs
@@ -267,6 +267,7 @@ pub struct Niri {
/// When this happens, the pointer also loses any focus. This is so that touch can prevent
/// various tooltips from sticking around.
pub pointer_hidden: bool,
+ pub last_cursor_movement: Instant,
// FIXME: this should be able to be removed once PointerFocus takes grabs into account.
pub pointer_grab_ongoing: bool,
pub tablet_cursor_location: Option<Point<f64, Logical>>,
@@ -1860,6 +1861,7 @@ impl Niri {
dnd_icon: None,
pointer_focus: PointerFocus::default(),
pointer_hidden: false,
+ last_cursor_movement: Instant::now(),
pointer_grab_ongoing: false,
tablet_cursor_location: None,
gesture_swipe_3f_cumulative: None,
@@ -2663,7 +2665,26 @@ impl Niri {
pointer_elements
}
+ fn hide_cursor_after_timeout_if_needed(&mut self) {
+ if self.pointer_hidden {
+ return;
+ }
+
+ let config = self.config.borrow();
+ let timeout = &config.cursor.hide_after_inactive_ms;
+
+ if let Some(duration_ms) = timeout {
+ let timeout = Duration::from_millis(*duration_ms as u64);
+
+ if self.last_cursor_movement.elapsed() >= timeout {
+ self.pointer_hidden = true;
+ }
+ }
+ }
+
pub fn refresh_pointer_outputs(&mut self) {
+ self.hide_cursor_after_timeout_if_needed();
+
if self.pointer_hidden {
return;
}