diff options
| author | yzy-1 <50034950+yzy-1@users.noreply.github.com> | 2024-10-02 08:22:50 +0800 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2024-10-06 22:09:19 -0700 |
| commit | 42a9daec9db57e16541b6ef236b695b71bfb1199 (patch) | |
| tree | 0268b893aa75df533076287cdfac232870f00deb | |
| parent | 1ba2be392857b95ba346ee4770f824c42afe0681 (diff) | |
| download | niri-42a9daec9db57e16541b6ef236b695b71bfb1199.tar.gz niri-42a9daec9db57e16541b6ef236b695b71bfb1199.tar.bz2 niri-42a9daec9db57e16541b6ef236b695b71bfb1199.zip | |
Implement hide cursor on key press and on timeout
| -rw-r--r-- | niri-config/src/lib.rs | 10 | ||||
| -rw-r--r-- | src/input/mod.rs | 45 | ||||
| -rw-r--r-- | src/niri.rs | 21 |
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; } |
