aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/input.rs1730
1 files changed, 887 insertions, 843 deletions
diff --git a/src/input.rs b/src/input.rs
index 300577be..5b5e8b3d 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -53,952 +53,996 @@ impl State {
self.niri.activate_monitors(&self.backend);
}
- let comp_mod = self.backend.mod_key();
-
+ use InputEvent::*;
match event {
- InputEvent::Keyboard { event, .. } => {
- let serial = SERIAL_COUNTER.next_serial();
- let time = Event::time_msec(&event);
- let pressed = event.state() == KeyState::Pressed;
+ DeviceAdded { device } => self.on_device_added(device),
+ DeviceRemoved { device } => self.on_device_removed(device),
+ Keyboard { event } => self.on_keyboard::<I>(event),
+ PointerMotion { event } => self.on_pointer_motion::<I>(event),
+ PointerMotionAbsolute { event } => self.on_pointer_motion_absolute::<I>(event),
+ PointerButton { event } => self.on_pointer_button::<I>(event),
+ PointerAxis { event } => self.on_pointer_axis::<I>(event),
+ TabletToolAxis { event } => self.on_tablet_tool_axis::<I>(event),
+ TabletToolTip { event } => self.on_tablet_tool_tip::<I>(event),
+ TabletToolProximity { event } => self.on_tablet_tool_proximity::<I>(event),
+ TabletToolButton { event } => self.on_tablet_tool_button::<I>(event),
+ GestureSwipeBegin { event } => self.on_gesture_swipe_begin::<I>(event),
+ GestureSwipeUpdate { event } => self.on_gesture_swipe_update::<I>(event),
+ GestureSwipeEnd { event } => self.on_gesture_swipe_end::<I>(event),
+ GesturePinchBegin { event } => self.on_gesture_pinch_begin::<I>(event),
+ GesturePinchUpdate { event } => self.on_gesture_pinch_update::<I>(event),
+ GesturePinchEnd { event } => self.on_gesture_pinch_end::<I>(event),
+ GestureHoldBegin { event } => self.on_gesture_hold_begin::<I>(event),
+ GestureHoldEnd { event } => self.on_gesture_hold_end::<I>(event),
+ TouchDown { .. } => (),
+ TouchMotion { .. } => (),
+ TouchUp { .. } => (),
+ TouchCancel { .. } => (),
+ TouchFrame { .. } => (),
+ Special(_) => (),
+ }
+ }
- let Some(Some(action)) = self.niri.seat.get_keyboard().unwrap().input(
- self,
- event.key_code(),
- event.state(),
- serial,
- time,
- |this, mods, keysym| {
- let bindings = &this.niri.config.borrow().binds;
- let key_code = event.key_code();
- let modified = keysym.modified_sym();
- let raw = keysym.raw_latin_sym_or_raw_current_sym();
- should_intercept_key(
- &mut this.niri.suppressed_keys,
- bindings,
- comp_mod,
- key_code,
- modified,
- raw,
- pressed,
- *mods,
- &this.niri.screenshot_ui,
- )
- },
- ) else {
- return;
- };
+ pub fn process_libinput_event(&mut self, event: &mut InputEvent<LibinputInputBackend>) {
+ match event {
+ InputEvent::DeviceAdded { device } => {
+ // According to Mutter code, this setting is specific to touchpads.
+ let is_touchpad = device.config_tap_finger_count() > 0;
+ if is_touchpad {
+ let c = &self.niri.config.borrow().input.touchpad;
+ let _ = device.config_tap_set_enabled(c.tap);
+ let _ = device.config_scroll_set_natural_scroll_enabled(c.natural_scroll);
+ let _ = device.config_accel_set_speed(c.accel_speed);
+ }
- // Filter actions when the key is released or the session is locked.
- if !pressed {
- return;
+ if device.has_capability(smithay::reexports::input::DeviceCapability::TabletTool) {
+ match device.size() {
+ Some((w, h)) => {
+ self.niri.tablets.insert(
+ device.clone(),
+ TabletData {
+ aspect_ratio: w / h,
+ },
+ );
+ }
+ None => {
+ warn!("tablet tool device has no size");
+ }
+ }
}
+ }
+ InputEvent::DeviceRemoved { device } => {
+ self.niri.tablets.remove(device);
+ }
+ _ => (),
+ }
+ }
- if self.niri.is_locked()
- && !matches!(
- action,
- Action::Quit
- | Action::ChangeVt(_)
- | Action::Suspend
- | Action::PowerOffMonitors
- | Action::SwitchLayout(_)
- )
- {
- return;
+ fn on_device_added(&mut self, device: impl Device) {
+ if device.has_capability(DeviceCapability::TabletTool) {
+ self.niri
+ .seat
+ .tablet_seat()
+ .add_tablet::<Self>(&self.niri.display_handle, &TabletDescriptor::from(&device));
+ }
+ }
+
+ fn on_device_removed(&mut self, device: impl Device) {
+ if device.has_capability(DeviceCapability::TabletTool) {
+ let tablet_seat = self.niri.seat.tablet_seat();
+
+ tablet_seat.remove_tablet(&TabletDescriptor::from(&device));
+
+ // If there are no tablets in seat we can remove all tools
+ if tablet_seat.count_tablets() == 0 {
+ tablet_seat.clear_tools();
+ }
+ }
+ }
+
+ fn compute_tablet_position<I: InputBackend>(
+ &mut self,
+ event: &(impl Event<I> + TabletToolEvent<I>),
+ ) -> Option<Point<f64, Logical>>
+ where
+ I::Device: 'static,
+ {
+ let output = self.niri.output_for_tablet()?;
+ let output_geo = self.niri.global_space.output_geometry(output).unwrap();
+
+ let mut pos = event.position_transformed(output_geo.size);
+ pos.x /= output_geo.size.w as f64;
+ pos.y /= output_geo.size.h as f64;
+
+ let device = event.device();
+ if let Some(device) = (&device as &dyn Any).downcast_ref::<input::Device>() {
+ if let Some(data) = self.niri.tablets.get(device) {
+ // This code does the same thing as mutter with "keep aspect ratio" enabled.
+ let output_aspect_ratio = output_geo.size.w as f64 / output_geo.size.h as f64;
+ let ratio = data.aspect_ratio / output_aspect_ratio;
+
+ if ratio > 1. {
+ pos.x *= ratio;
+ } else {
+ pos.y /= ratio;
}
+ }
+ };
- match action {
- Action::Quit => {
- info!("quitting because quit bind was pressed");
- self.niri.stop_signal.stop()
- }
- Action::ChangeVt(vt) => {
- self.backend.change_vt(vt);
- // Changing `VT` may not deliver the key releases, so clear the state.
- self.niri.suppressed_keys.clear();
- }
- Action::Suspend => {
- self.backend.suspend();
- // Suspend may not deliver the key releases, so clear the state.
- self.niri.suppressed_keys.clear();
- }
- Action::PowerOffMonitors => {
- self.niri.deactivate_monitors(&self.backend);
- }
- Action::ToggleDebugTint => {
- self.backend.toggle_debug_tint();
- }
- Action::Spawn(command) => {
- spawn(command);
- }
- Action::ScreenshotScreen => {
- let active = self.niri.layout.active_output().cloned();
- if let Some(active) = active {
- if let Some(renderer) = self.backend.renderer() {
- if let Err(err) = self.niri.screenshot(renderer, &active) {
- warn!("error taking screenshot: {err:?}");
- }
- }
- }
- }
- Action::ConfirmScreenshot => {
- if let Some(renderer) = self.backend.renderer() {
- match self.niri.screenshot_ui.capture(renderer) {
- Ok((size, pixels)) => {
- if let Err(err) = self.niri.save_screenshot(size, pixels) {
- warn!("error saving screenshot: {err:?}");
- }
- }
- Err(err) => {
- warn!("error capturing screenshot: {err:?}");
- }
- }
- }
+ pos.x *= output_geo.size.w as f64;
+ pos.y *= output_geo.size.h as f64;
+ pos.x = pos.x.clamp(0.0, output_geo.size.w as f64 - 1.);
+ pos.y = pos.y.clamp(0.0, output_geo.size.h as f64 - 1.);
+ Some(pos + output_geo.loc.to_f64())
+ }
- self.niri.screenshot_ui.close();
- self.niri
- .cursor_manager
- .set_cursor_image(CursorImageStatus::default_named());
- self.niri.queue_redraw_all();
- }
- Action::CancelScreenshot => {
- self.niri.screenshot_ui.close();
- self.niri
- .cursor_manager
- .set_cursor_image(CursorImageStatus::default_named());
- self.niri.queue_redraw_all();
- }
- Action::Screenshot => {
- if let Some(renderer) = self.backend.renderer() {
- self.niri.open_screenshot_ui(renderer);
+ fn on_keyboard<I: InputBackend>(&mut self, event: I::KeyboardKeyEvent) {
+ let comp_mod = self.backend.mod_key();
+
+ let serial = SERIAL_COUNTER.next_serial();
+ let time = Event::time_msec(&event);
+ let pressed = event.state() == KeyState::Pressed;
+
+ let Some(Some(action)) = self.niri.seat.get_keyboard().unwrap().input(
+ self,
+ event.key_code(),
+ event.state(),
+ serial,
+ time,
+ |this, mods, keysym| {
+ let bindings = &this.niri.config.borrow().binds;
+ let key_code = event.key_code();
+ let modified = keysym.modified_sym();
+ let raw = keysym.raw_latin_sym_or_raw_current_sym();
+ should_intercept_key(
+ &mut this.niri.suppressed_keys,
+ bindings,
+ comp_mod,
+ key_code,
+ modified,
+ raw,
+ pressed,
+ *mods,
+ &this.niri.screenshot_ui,
+ )
+ },
+ ) else {
+ return;
+ };
+
+ // Filter actions when the key is released or the session is locked.
+ if !pressed {
+ return;
+ }
+
+ if self.niri.is_locked()
+ && !matches!(
+ action,
+ Action::Quit
+ | Action::ChangeVt(_)
+ | Action::Suspend
+ | Action::PowerOffMonitors
+ | Action::SwitchLayout(_)
+ )
+ {
+ return;
+ }
+
+ match action {
+ Action::Quit => {
+ info!("quitting because quit bind was pressed");
+ self.niri.stop_signal.stop()
+ }
+ Action::ChangeVt(vt) => {
+ self.backend.change_vt(vt);
+ // Changing `VT` may not deliver the key releases, so clear the state.
+ self.niri.suppressed_keys.clear();
+ }
+ Action::Suspend => {
+ self.backend.suspend();
+ // Suspend may not deliver the key releases, so clear the state.
+ self.niri.suppressed_keys.clear();
+ }
+ Action::PowerOffMonitors => {
+ self.niri.deactivate_monitors(&self.backend);
+ }
+ Action::ToggleDebugTint => {
+ self.backend.toggle_debug_tint();
+ }
+ Action::Spawn(command) => {
+ spawn(command);
+ }
+ Action::ScreenshotScreen => {
+ let active = self.niri.layout.active_output().cloned();
+ if let Some(active) = active {
+ if let Some(renderer) = self.backend.renderer() {
+ if let Err(err) = self.niri.screenshot(renderer, &active) {
+ warn!("error taking screenshot: {err:?}");
}
}
- Action::ScreenshotWindow => {
- let active = self.niri.layout.active_window();
- if let Some((window, output)) = active {
- if let Some(renderer) = self.backend.renderer() {
- if let Err(err) =
- self.niri.screenshot_window(renderer, &output, &window)
- {
- warn!("error taking screenshot: {err:?}");
- }
+ }
+ }
+ Action::ConfirmScreenshot => {
+ if let Some(renderer) = self.backend.renderer() {
+ match self.niri.screenshot_ui.capture(renderer) {
+ Ok((size, pixels)) => {
+ if let Err(err) = self.niri.save_screenshot(size, pixels) {
+ warn!("error saving screenshot: {err:?}");
}
}
- }
- Action::CloseWindow => {
- if let Some(window) = self.niri.layout.focus() {
- window.toplevel().send_close();
+ Err(err) => {
+ warn!("error capturing screenshot: {err:?}");
}
}
- Action::FullscreenWindow => {
- let focus = self.niri.layout.focus().cloned();
- if let Some(window) = focus {
- self.niri.layout.toggle_fullscreen(&window);
- }
- }
- Action::SwitchLayout(action) => {
- self.niri
- .seat
- .get_keyboard()
- .unwrap()
- .with_xkb_state(self, |mut state| match action {
- LayoutAction::Next => state.cycle_next_layout(),
- LayoutAction::Prev => state.cycle_prev_layout(),
- });
- }
- Action::MoveColumnLeft => {
- self.niri.layout.move_left();
- // FIXME: granular
- self.niri.queue_redraw_all();
- }
- Action::MoveColumnRight => {
- self.niri.layout.move_right();
- // FIXME: granular
- self.niri.queue_redraw_all();
- }
- Action::MoveWindowDown => {
- self.niri.layout.move_down();
- // FIXME: granular
- self.niri.queue_redraw_all();
- }
- Action::MoveWindowUp => {
- self.niri.layout.move_up();
- // FIXME: granular
- self.niri.queue_redraw_all();
- }
- Action::FocusColumnLeft => {
- self.niri.layout.focus_left();
- }
- Action::FocusColumnRight => {
- self.niri.layout.focus_right();
- }
- Action::FocusWindowDown => {
- self.niri.layout.focus_down();
- }
- Action::FocusWindowUp => {
- self.niri.layout.focus_up();
- }
- Action::MoveWindowToWorkspaceDown => {
- self.niri.layout.move_to_workspace_down();
- // FIXME: granular
- self.niri.queue_redraw_all();
- }
- Action::MoveWindowToWorkspaceUp => {
- self.niri.layout.move_to_workspace_up();
- // FIXME: granular
- self.niri.queue_redraw_all();
- }
- Action::MoveWindowToWorkspace(idx) => {
- let idx = idx.saturating_sub(1) as usize;
- self.niri.layout.move_to_workspace(idx);
- // FIXME: granular
- self.niri.queue_redraw_all();
- }
- Action::FocusWorkspaceDown => {
- self.niri.layout.switch_workspace_down();
- // FIXME: granular
- self.niri.queue_redraw_all();
- }
- Action::FocusWorkspaceUp => {
- self.niri.layout.switch_workspace_up();
- // FIXME: granular
- self.niri.queue_redraw_all();
- }
- Action::FocusWorkspace(idx) => {
- let idx = idx.saturating_sub(1) as usize;
- self.niri.layout.switch_workspace(idx);
- // FIXME: granular
- self.niri.queue_redraw_all();
- }
- Action::MoveWorkspaceDown => {
- self.niri.layout.move_workspace_down();
- // FIXME: granular
- self.niri.queue_redraw_all();
- }
- Action::MoveWorkspaceUp => {
- self.niri.layout.move_workspace_up();
- // FIXME: granular
- self.niri.queue_redraw_all();
- }
- Action::ConsumeWindowIntoColumn => {
- self.niri.layout.consume_into_column();
- // FIXME: granular
- self.niri.queue_redraw_all();
- }
- Action::ExpelWindowFromColumn => {
- self.niri.layout.expel_from_column();
- // FIXME: granular
- self.niri.queue_redraw_all();
- }
- Action::SwitchPresetColumnWidth => {
- self.niri.layout.toggle_width();
- }
- Action::CenterColumn => {
- self.niri.layout.center_column();
- // FIXME: granular
- self.niri.queue_redraw_all();
- }
- Action::MaximizeColumn => {
- self.niri.layout.toggle_full_width();
- }
- Action::FocusMonitorLeft => {
- if let Some(output) = self.niri.output_left() {
- self.niri.layout.focus_output(&output);
- self.move_cursor_to_output(&output);
- }
- }
- Action::FocusMonitorRight => {
- if let Some(output) = self.niri.output_right() {
- self.niri.layout.focus_output(&output);
- self.move_cursor_to_output(&output);
- }
- }
- Action::FocusMonitorDown => {
- if let Some(output) = self.niri.output_down() {
- self.niri.layout.focus_output(&output);
- self.move_cursor_to_output(&output);
- }
- }
- Action::FocusMonitorUp => {
- if let Some(output) = self.niri.output_up() {
- self.niri.layout.focus_output(&output);
- self.move_cursor_to_output(&output);
- }
- }
- Action::MoveWindowToMonitorLeft => {
- if let Some(output) = self.niri.output_left() {
- self.niri.layout.move_to_output(&output);
- self.move_cursor_to_output(&output);
- }
- }
- Action::MoveWindowToMonitorRight => {
- if let Some(output) = self.niri.output_right() {
- self.niri.layout.move_to_output(&output);
- self.move_cursor_to_output(&output);
- }
- }
- Action::MoveWindowToMonitorDown => {
- if let Some(output) = self.niri.output_down() {
- self.niri.layout.move_to_output(&output);
- self.move_cursor_to_output(&output);
- }
- }
- Action::MoveWindowToMonitorUp => {
- if let Some(output) = self.niri.output_up() {
- self.niri.layout.move_to_output(&output);
- self.move_cursor_to_output(&output);
+ }
+
+ self.niri.screenshot_ui.close();
+ self.niri
+ .cursor_manager
+ .set_cursor_image(CursorImageStatus::default_named());
+ self.niri.queue_redraw_all();
+ }
+ Action::CancelScreenshot => {
+ self.niri.screenshot_ui.close();
+ self.niri
+ .cursor_manager
+ .set_cursor_image(CursorImageStatus::default_named());
+ self.niri.queue_redraw_all();
+ }
+ Action::Screenshot => {
+ if let Some(renderer) = self.backend.renderer() {
+ self.niri.open_screenshot_ui(renderer);
+ }
+ }
+ Action::ScreenshotWindow => {
+ let active = self.niri.layout.active_window();
+ if let Some((window, output)) = active {
+ if let Some(renderer) = self.backend.renderer() {
+ if let Err(err) = self.niri.screenshot_window(renderer, &output, &window) {
+ warn!("error taking screenshot: {err:?}");
}
}
- Action::SetColumnWidth(change) => {
- self.niri.layout.set_column_width(change);
- }
- Action::SetWindowHeight(change) => {
- self.niri.layout.set_window_height(change);
- }
}
}
- InputEvent::PointerMotion { event, .. } => {
- // We need an output to be able to move the pointer.
- if self.niri.global_space.outputs().next().is_none() {
- return;
+ Action::CloseWindow => {
+ if let Some(window) = self.niri.layout.focus() {
+ window.toplevel().send_close();
}
+ }
+ Action::FullscreenWindow => {
+ let focus = self.niri.layout.focus().cloned();
+ if let Some(window) = focus {
+ self.niri.layout.toggle_fullscreen(&window);
+ }
+ }
+ Action::SwitchLayout(action) => {
+ self.niri.seat.get_keyboard().unwrap().with_xkb_state(
+ self,
+ |mut state| match action {
+ LayoutAction::Next => state.cycle_next_layout(),
+ LayoutAction::Prev => state.cycle_prev_layout(),
+ },
+ );
+ }
+ Action::MoveColumnLeft => {
+ self.niri.layout.move_left();
+ // FIXME: granular
+ self.niri.queue_redraw_all();
+ }
+ Action::MoveColumnRight => {
+ self.niri.layout.move_right();
+ // FIXME: granular
+ self.niri.queue_redraw_all();
+ }
+ Action::MoveWindowDown => {
+ self.niri.layout.move_down();
+ // FIXME: granular
+ self.niri.queue_redraw_all();
+ }
+ Action::MoveWindowUp => {
+ self.niri.layout.move_up();
+ // FIXME: granular
+ self.niri.queue_redraw_all();
+ }
+ Action::FocusColumnLeft => {
+ self.niri.layout.focus_left();
+ }
+ Action::FocusColumnRight => {
+ self.niri.layout.focus_right();
+ }
+ Action::FocusWindowDown => {
+ self.niri.layout.focus_down();
+ }
+ Action::FocusWindowUp => {
+ self.niri.layout.focus_up();
+ }
+ Action::MoveWindowToWorkspaceDown => {
+ self.niri.layout.move_to_workspace_down();
+ // FIXME: granular
+ self.niri.queue_redraw_all();
+ }
+ Action::MoveWindowToWorkspaceUp => {
+ self.niri.layout.move_to_workspace_up();
+ // FIXME: granular
+ self.niri.queue_redraw_all();
+ }
+ Action::MoveWindowToWorkspace(idx) => {
+ let idx = idx.saturating_sub(1) as usize;
+ self.niri.layout.move_to_workspace(idx);
+ // FIXME: granular
+ self.niri.queue_redraw_all();
+ }
+ Action::FocusWorkspaceDown => {
+ self.niri.layout.switch_workspace_down();
+ // FIXME: granular
+ self.niri.queue_redraw_all();
+ }
+ Action::FocusWorkspaceUp => {
+ self.niri.layout.switch_workspace_up();
+ // FIXME: granular
+ self.niri.queue_redraw_all();
+ }
+ Action::FocusWorkspace(idx) => {
+ let idx = idx.saturating_sub(1) as usize;
+ self.niri.layout.switch_workspace(idx);
+ // FIXME: granular
+ self.niri.queue_redraw_all();
+ }
+ Action::MoveWorkspaceDown => {
+ self.niri.layout.move_workspace_down();
+ // FIXME: granular
+ self.niri.queue_redraw_all();
+ }
+ Action::MoveWorkspaceUp => {
+ self.niri.layout.move_workspace_up();
+ // FIXME: granular
+ self.niri.queue_redraw_all();
+ }
+ Action::ConsumeWindowIntoColumn => {
+ self.niri.layout.consume_into_column();
+ // FIXME: granular
+ self.niri.queue_redraw_all();
+ }
+ Action::ExpelWindowFromColumn => {
+ self.niri.layout.expel_from_column();
+ // FIXME: granular
+ self.niri.queue_redraw_all();
+ }
+ Action::SwitchPresetColumnWidth => {
+ self.niri.layout.toggle_width();
+ }
+ Action::CenterColumn => {
+ self.niri.layout.center_column();
+ // FIXME: granular
+ self.niri.queue_redraw_all();
+ }
+ Action::MaximizeColumn => {
+ self.niri.layout.toggle_full_width();
+ }
+ Action::FocusMonitorLeft => {
+ if let Some(output) = self.niri.output_left() {
+ self.niri.layout.focus_output(&output);
+ self.move_cursor_to_output(&output);
+ }
+ }
+ Action::FocusMonitorRight => {
+ if let Some(output) = self.niri.output_right() {
+ self.niri.layout.focus_output(&output);
+ self.move_cursor_to_output(&output);
+ }
+ }
+ Action::FocusMonitorDown => {
+ if let Some(output) = self.niri.output_down() {
+ self.niri.layout.focus_output(&output);
+ self.move_cursor_to_output(&output);
+ }
+ }
+ Action::FocusMonitorUp => {
+ if let Some(output) = self.niri.output_up() {
+ self.niri.layout.focus_output(&output);
+ self.move_cursor_to_output(&output);
+ }
+ }
+ Action::MoveWindowToMonitorLeft => {
+ if let Some(output) = self.niri.output_left() {
+ self.niri.layout.move_to_output(&output);
+ self.move_cursor_to_output(&output);
+ }
+ }
+ Action::MoveWindowToMonitorRight => {
+ if let Some(output) = self.niri.output_right() {
+ self.niri.layout.move_to_output(&output);
+ self.move_cursor_to_output(&output);
+ }
+ }
+ Action::MoveWindowToMonitorDown => {
+ if let Some(output) = self.niri.output_down() {
+ self.niri.layout.move_to_output(&output);
+ self.move_cursor_to_output(&output);
+ }
+ }
+ Action::MoveWindowToMonitorUp => {
+ if let Some(output) = self.niri.output_up() {
+ self.niri.layout.move_to_output(&output);
+ self.move_cursor_to_output(&output);
+ }
+ }
+ Action::SetColumnWidth(change) => {
+ self.niri.layout.set_column_width(change);
+ }
+ Action::SetWindowHeight(change) => {
+ self.niri.layout.set_window_height(change);
+ }
+ }
+ }
- let serial = SERIAL_COUNTER.next_serial();
+ fn on_pointer_motion<I: InputBackend>(&mut self, event: I::PointerMotionEvent) {
+ // We need an output to be able to move the pointer.
+ if self.niri.global_space.outputs().next().is_none() {
+ return;
+ }
- let pointer = self.niri.seat.get_pointer().unwrap();
+ let serial = SERIAL_COUNTER.next_serial();
+
+ let pointer = self.niri.seat.get_pointer().unwrap();
+
+ let pos = pointer.current_location();
+
+ // We have an output, so we can compute the new location and focus.
+ let mut new_pos = pos + event.delta();
+
+ if self
+ .niri
+ .global_space
+ .output_under(new_pos)
+ .next()
+ .is_none()
+ {
+ // We ended up outside the outputs and need to clip the movement.
+ if let Some(output) = self.niri.global_space.output_under(pos).next() {
+ // The pointer was previously on some output. Clip the movement against its
+ // boundaries.
+ let geom = self.niri.global_space.output_geometry(output).unwrap();
+ new_pos.x = new_pos
+ .x
+ .clamp(geom.loc.x as f64, (geom.loc.x + geom.size.w - 1) as f64);
+ new_pos.y = new_pos
+ .y
+ .clamp(geom.loc.y as f64, (geom.loc.y + geom.size.h - 1) as f64);
+ } else {
+ // The pointer was not on any output in the first place. Find one for it.
+ // Let's do the simple thing and just put it on the first output.
+ let output = self.niri.global_space.outputs().next().unwrap();
+ let geom = self.niri.global_space.output_geometry(output).unwrap();
+ new_pos = center(geom).to_f64();
+ }
+ }
- let pos = pointer.current_location();
+ if let Some(output) = self.niri.screenshot_ui.selection_output() {
+ let geom = self.niri.global_space.output_geometry(output).unwrap();
+ let mut point = new_pos;
+ point.x = point
+ .x
+ .clamp(geom.loc.x as f64, (geom.loc.x + geom.size.w - 1) as f64);
+ point.y = point
+ .y
+ .clamp(geom.loc.y as f64, (geom.loc.y + geom.size.h - 1) as f64);
+ let point = (point - geom.loc.to_f64())
+ .to_physical(output.current_scale().fractional_scale())
+ .to_i32_round();
+ self.niri.screenshot_ui.pointer_motion(point);
+ }
- // We have an output, so we can compute the new location and focus.
- let mut new_pos = pos + event.delta();
+ let under = self.niri.surface_under_and_global_space(new_pos);
+ self.niri.pointer_focus = under.clone();
+ let under = under.map(|u| u.surface);
+
+ pointer.motion(
+ self,
+ under.clone(),
+ &MotionEvent {
+ location: new_pos,
+ serial,
+ time: event.time_msec(),
+ },
+ );
+
+ pointer.relative_motion(
+ self,
+ under,
+ &RelativeMotionEvent {
+ delta: event.delta(),
+ delta_unaccel: event.delta_unaccel(),
+ utime: event.time(),
+ },
+ );
- if self
- .niri
- .global_space
- .output_under(new_pos)
- .next()
- .is_none()
- {
- // We ended up outside the outputs and need to clip the movement.
- if let Some(output) = self.niri.global_space.output_under(pos).next() {
- // The pointer was previously on some output. Clip the movement against its
- // boundaries.
- let geom = self.niri.global_space.output_geometry(output).unwrap();
- new_pos.x = new_pos
- .x
- .clamp(geom.loc.x as f64, (geom.loc.x + geom.size.w - 1) as f64);
- new_pos.y = new_pos
- .y
- .clamp(geom.loc.y as f64, (geom.loc.y + geom.size.h - 1) as f64);
- } else {
- // The pointer was not on any output in the first place. Find one for it.
- // Let's do the simple thing and just put it on the first output.
- let output = self.niri.global_space.outputs().next().unwrap();
- let geom = self.niri.global_space.output_geometry(output).unwrap();
- new_pos = center(geom).to_f64();
- }
- }
+ pointer.frame(self);
- if let Some(output) = self.niri.screenshot_ui.selection_output() {
- let geom = self.niri.global_space.output_geometry(output).unwrap();
- let mut point = new_pos;
- point.x = point
- .x
- .clamp(geom.loc.x as f64, (geom.loc.x + geom.size.w - 1) as f64);
- point.y = point
- .y
- .clamp(geom.loc.y as f64, (geom.loc.y + geom.size.h - 1) as f64);
- let point = (point - geom.loc.to_f64())
- .to_physical(output.current_scale().fractional_scale())
- .to_i32_round();
- self.niri.screenshot_ui.pointer_motion(point);
- }
+ // We moved the regular pointer, so show it now.
+ self.niri.tablet_cursor_location = None;
- let under = self.niri.surface_under_and_global_space(new_pos);
- self.niri.pointer_focus = under.clone();
- let under = under.map(|u| u.surface);
+ // Redraw to update the cursor position.
+ // FIXME: redraw only outputs overlapping the cursor.
+ self.niri.queue_redraw_all();
+ }
- pointer.motion(
- self,
- under.clone(),
- &MotionEvent {
- location: new_pos,
- serial,
- time: event.time_msec(),
- },
- );
+ fn on_pointer_motion_absolute<I: InputBackend>(
+ &mut self,
+ event: I::PointerMotionAbsoluteEvent,
+ ) {
+ let Some(output) = self.niri.global_space.outputs().next() else {
+ return;
+ };
- pointer.relative_motion(
- self,
- under,
- &RelativeMotionEvent {
- delta: event.delta(),
- delta_unaccel: event.delta_unaccel(),
- utime: event.time(),
- },
- );
+ let output_geo = self.niri.global_space.output_geometry(output).unwrap();
- pointer.frame(self);
+ let pos = event.position_transformed(output_geo.size) + output_geo.loc.to_f64();
+
+ let serial = SERIAL_COUNTER.next_serial();
+
+ let pointer = self.niri.seat.get_pointer().unwrap();
+
+ if let Some(output) = self.niri.screenshot_ui.selection_output() {
+ let geom = self.niri.global_space.output_geometry(output).unwrap();
+ let mut point = pos;
+ point.x = point
+ .x
+ .clamp(geom.loc.x as f64, (geom.loc.x + geom.size.w - 1) as f64);
+ point.y = point
+ .y
+ .clamp(geom.loc.y as f64, (geom.loc.y +