diff --git a/niri-config/src/lib.rs b/niri-config/src/lib.rs index 6d1048276..56d92e7cc 100644 --- a/niri-config/src/lib.rs +++ b/niri-config/src/lib.rs @@ -710,6 +710,7 @@ pub enum Action { ChangeVt(i32), Suspend, PowerOffMonitors, + ToggleTabletMode, ToggleDebugTint, Spawn(#[knuffel(arguments)] Vec), #[knuffel(skip)] @@ -845,6 +846,7 @@ impl From for Action { niri_ipc::Action::MoveWorkspaceToMonitorDown => Self::MoveWorkspaceToMonitorDown, niri_ipc::Action::MoveWorkspaceToMonitorUp => Self::MoveWorkspaceToMonitorUp, niri_ipc::Action::ToggleDebugTint => Self::ToggleDebugTint, + niri_ipc::Action::ToggleTabletMode => Self::ToggleTabletMode, } } } diff --git a/niri-ipc/src/lib.rs b/niri-ipc/src/lib.rs index b26eb3ccd..7a7aae273 100644 --- a/niri-ipc/src/lib.rs +++ b/niri-ipc/src/lib.rs @@ -205,6 +205,8 @@ pub enum Action { MoveWorkspaceToMonitorUp, /// Toggle a debug tint on windows. ToggleDebugTint, + /// Toggle tablet mode (disable keyboard and touchpad) + ToggleTabletMode, } /// Change in window or column size. diff --git a/src/input.rs b/src/input.rs index 715d39c84..7cc7e5fc4 100644 --- a/src/input.rs +++ b/src/input.rs @@ -9,7 +9,7 @@ use smithay::backend::input::{ AbsolutePositionEvent, Axis, AxisSource, ButtonState, Device, DeviceCapability, Event, GestureBeginEvent, GestureEndEvent, GesturePinchUpdateEvent as _, GestureSwipeUpdateEvent as _, InputBackend, InputEvent, KeyState, KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent, - PointerMotionEvent, ProximityState, TabletToolButtonEvent, TabletToolEvent, + PointerMotionEvent, ProximityState, SwitchToggleEvent, TabletToolButtonEvent, TabletToolEvent, TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TouchEvent, }; use smithay::backend::libinput::LibinputInputBackend; @@ -109,7 +109,7 @@ impl State { TouchUp { event } => self.on_touch_up::(event), TouchCancel { event } => self.on_touch_cancel::(event), TouchFrame { event } => self.on_touch_frame::(event), - SwitchToggle { .. } => (), + SwitchToggle { event } => self.on_switch_toggle::(event), Special(_) => (), } @@ -278,6 +278,7 @@ impl State { *mods, &this.niri.screenshot_ui, this.niri.config.borrow().input.disable_power_key_handling, + this.niri.tablet_mode, ) }, ) else { @@ -332,6 +333,11 @@ impl State { self.backend.toggle_debug_tint(); self.niri.queue_redraw_all(); } + Action::ToggleTabletMode => { + self.niri.tablet_mode = !self.niri.tablet_mode; + // FIXME: redraw only outputs overlapping the cursor. + self.niri.queue_redraw_all(); + } Action::Spawn(command) => { spawn(command); } @@ -697,6 +703,10 @@ impl State { } fn on_pointer_motion(&mut self, event: I::PointerMotionEvent) { + if self.niri.tablet_mode { + return; + } + // We need an output to be able to move the pointer. if self.niri.global_space.outputs().next().is_none() { return; @@ -932,6 +942,10 @@ impl State { } fn on_pointer_button(&mut self, event: I::PointerButtonEvent) { + if self.niri.tablet_mode { + return; + } + let pointer = self.niri.seat.get_pointer().unwrap(); let serial = SERIAL_COUNTER.next_serial(); @@ -997,6 +1011,9 @@ impl State { } fn on_pointer_axis(&mut self, event: I::PointerAxisEvent) { + if self.niri.tablet_mode { + return; + } let source = event.source(); let horizontal_amount = event @@ -1538,6 +1555,14 @@ impl State { }; handle.cancel(self); } + + fn on_switch_toggle(&mut self, event: B::SwitchToggleEvent) { + if event.switch() == Some(smithay::backend::input::Switch::TabletMode) { + self.niri.tablet_mode = event.state() == smithay::backend::input::SwitchState::On; + // FIXME: redraw only outputs overlapping the cursor. + self.niri.queue_redraw_all(); + } + } } /// Check whether the key should be intercepted and mark intercepted @@ -1555,6 +1580,7 @@ fn should_intercept_key( mods: ModifiersState, screenshot_ui: &ScreenshotUi, disable_power_key_handling: bool, + tablet_mode: bool, ) -> FilterResult> { // Actions are only triggered on presses, release of the key // shouldn't try to intercept anything unless we have marked @@ -1572,6 +1598,13 @@ fn should_intercept_key( disable_power_key_handling, ); + if tablet_mode { + if final_action != Some(Action::ToggleTabletMode) { + suppressed_keys.insert(key_code); + return FilterResult::Intercept(None); + } + } + // Allow only a subset of compositor actions while the screenshot UI is open, since the user // cannot see the screen. if screenshot_ui.is_open() { @@ -1842,6 +1875,7 @@ mod tests { let screenshot_ui = ScreenshotUi::new(); let disable_power_key_handling = false; + let tablet_mode = false; // The key_code we pick is arbitrary, the only thing // that matters is that they are different between cases. @@ -1859,6 +1893,7 @@ mod tests { mods, &screenshot_ui, disable_power_key_handling, + tablet_mode, ) }; @@ -1875,6 +1910,7 @@ mod tests { mods, &screenshot_ui, disable_power_key_handling, + tablet_mode, ) }; diff --git a/src/niri.rs b/src/niri.rs index 01dc9eb59..6389222ca 100644 --- a/src/niri.rs +++ b/src/niri.rs @@ -208,6 +208,7 @@ pub struct Niri { pub gesture_swipe_3f_cumulative: Option<(f64, f64)>, pub lock_state: LockState, + pub tablet_mode: bool, pub screenshot_ui: ScreenshotUi, pub config_error_notification: ConfigErrorNotification, @@ -1096,6 +1097,7 @@ impl Niri { gesture_swipe_3f_cumulative: None, lock_state: LockState::Unlocked, + tablet_mode: false, screenshot_ui, config_error_notification, @@ -1736,6 +1738,10 @@ impl Niri { renderer: &mut R, output: &Output, ) -> Vec> { + if self.tablet_mode && self.tablet_cursor_location.is_none() { + return vec![]; + } + let _span = tracy_client::span!("Niri::pointer_element"); let output_scale = output.current_scale(); let output_pos = self.global_space.output_geometry(output).unwrap().loc;