atagen

monolith

public
Star0
Watch0

Commit 509842c1b6dc

tarball

atagen <boss@atagen.co>2026-10-28 04:06 UTC

5 files changed+28-2
monolith: add hide_cursor_on_type

Hides the pointer on any non-modifier key forwarded to a client, regardless of whether the client asked for it, until the pointer next moves, clicks or scrolls.
Modified file: crates/config/default.toml+2 additions
@@ -20,6 +20,8 @@ focus_follows_mouse = false
2020 # Put the pointer in the middle of a window focused from the keyboard, a
2121 # rule or a new map. Bare metal only, a nested pointer belongs to the host.
2222 mouse_follows_focus = false
23+# Hide the pointer on any key typed into a window, until it next moves.
24+hide_cursor_on_type = false
2325 # A window landing on, or moved to, a tag or output where its tag is empty and
2426 # not in view brings the tag into view there, alongside the tags already shown.
2527 view_tag_on_first_window = true
Modified file: crates/config/src/lib.rs+2 additions
@@ -40,6 +40,7 @@ pub struct General {
4040 pub move_mode: MoveMode,
4141 pub focus_follows_mouse: bool,
4242 pub mouse_follows_focus: bool,
43+ pub hide_cursor_on_type: bool,
4344 /// The first window to land on or move to an empty tag nobody is
4445 /// viewing brings that tag into view on its output.
4546 pub view_tag_on_first_window: bool,
@@ -64,6 +65,7 @@ impl Default for General {
6465 move_mode: MoveMode::Swap,
6566 focus_follows_mouse: false,
6667 mouse_follows_focus: false,
68+ hide_cursor_on_type: false,
6769 view_tag_on_first_window: true,
6870 }
6971 }
Modified file: crates/monolith/src/frame.rs+1 additions−1 deletions
@@ -51,7 +51,7 @@ pub fn compose(
5151 let pos = ctx.input.pointer_pos;
5252 if area.contains(pos.x, pos.y) {
5353 let local = pos - Point::from((area.x, area.y));
54- if cursor {
54+ if cursor && !ctx.input.typing {
5555 let resize = ctx.input.resize_icon().map(CursorImageStatus::Named);
5656 let status = resize.as_ref().unwrap_or(&ctx.input.cursor_status);
5757 elements.extend(
Modified file: crates/monolith/src/input.rs+20 additions−1 deletions
@@ -29,6 +29,9 @@ pub enum Motion {
2929 impl State {
3030 pub fn pointer_motion(&mut self, wanted: Point<f64, Logical>, motion: Motion, time: InputTime) {
3131 let user = !matches!(motion, Motion::Warp);
32+ if user {
33+ self.show_cursor();
34+ }
3235 let (delta, unaccel) = match motion {
3336 Motion::Relative { delta, unaccel } => {
3437 self.input.absolute = None;
@@ -130,6 +133,7 @@ impl State {
130133
131134 pub fn pointer_button(&mut self, button: u32, pressed: ButtonState, time: InputTime) {
132135 self.activity();
136+ self.show_cursor();
133137 if pressed == ButtonState::Released {
134138 let ended = self.input.drag.take_if(|d| d.button == button);
135139 if let Some(d) = ended {
@@ -170,11 +174,18 @@ impl State {
170174
171175 pub fn pointer_axis(&mut self, frame: AxisFrame) {
172176 self.activity();
177+ self.show_cursor();
173178 if let Some(pointer) = self.input.seat.get_pointer() {
174179 pointer.axis(self, frame);
175180 }
176181 }
177182
183+ fn show_cursor(&mut self) {
184+ if std::mem::take(&mut self.input.typing) {
185+ self.dirty.cursor = true;
186+ }
187+ }
188+
178189 pub fn pointer_frame(&mut self) {
179190 if let Some(pointer) = self.input.seat.get_pointer() {
180191 pointer.frame(self);
@@ -210,7 +221,7 @@ impl State {
210221 let vt = (sym - xkb::keysyms::KEY_XF86Switch_VT_1 + 1) as i32;
211222 return FilterResult::Intercept(Some(Action::Vt(vt)));
212223 }
213- match state.settings.binds.find(mods, &handle.raw_syms()) {
224+ let result = match state.settings.binds.find(mods, &handle.raw_syms()) {
214225 Some(cmd) if state.services.lock.active() && !cmd.allowed_while_locked() => {
215226 FilterResult::Forward
216227 }
@@ -223,7 +234,15 @@ impl State {
223234 FilterResult::Intercept(Some(Action::Run(cmd)))
224235 }
225236 None => FilterResult::Forward,
237+ };
238+ if matches!(result, FilterResult::Forward)
239+ && !handle.modified_sym().is_modifier_key()
240+ && state.settings.config.general.hide_cursor_on_type
241+ && !std::mem::replace(&mut state.input.typing, true)
242+ {
243+ state.dirty.cursor = true;
226244 }
245+ result
227246 },
228247 );
229248 match action {
Modified file: crates/monolith/src/state.rs+3 additions
@@ -62,6 +62,8 @@ pub struct Input {
6262 pub warping: bool,
6363 pub cursor: crate::cursor::Cursor,
6464 pub cursor_status: CursorImageStatus,
65+ /// Typing hid the cursor and the pointer has not moved since.
66+ pub typing: bool,
6567 pub dnd_icon: Option<crate::cursor::DndIcon>,
6668 pub dnd: bool,
6769 /// The edges of the window border under the pointer, for the resize cursor.
@@ -209,6 +211,7 @@ impl State {
209211 warping: false,
210212 cursor: crate::cursor::Cursor::load(),
211213 cursor_status: CursorImageStatus::default_named(),
214+ typing: false,
212215 dnd_icon: None,
213216 dnd: false,
214217 hover: None,