wip look into Keyboard/PointerTarget

Decided not to pursue this for now. The idea was to extract input handling from
input/mod.rs into the respective modules, plus get rid of manual cursor shape
resetting, but there are some roadblocks:

- The pointer is locked when those methods are called, meaning you can't get
  the current location (have to store from enter/motion) and, more crucially,
  can't set grabs—we need this for the Overview.
- Gesture begin/end is handled at the Wayland object level, meaning
  PointerTargets get to deal with "improper" events themselves, reducing their
  utility. cosmic-comp spawns an idle callback for this which seems awkward and
  is asking for problems.
- We're not actually removing much code at all, only adding more code for the
  blanket wrappers and such.
This commit is contained in:
Ivan Molodetskikh 2025-08-20 20:31:34 +03:00
parent 34b05e8671
commit bf4e8cd233
7 changed files with 472 additions and 56 deletions

253
src/focus.rs Normal file
View file

@ -0,0 +1,253 @@
use std::borrow::Cow;
use smithay::backend::input::KeyState;
use smithay::desktop::PopupKind;
use smithay::input::keyboard::{KeyboardTarget, KeysymHandle, ModifiersState};
use smithay::input::pointer::{self, PointerTarget};
use smithay::input::Seat;
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
use smithay::utils::{IsAlive, Serial};
use smithay::wayland::seat::WaylandFocus;
use crate::niri::State;
use crate::ui::screenshot_ui::ScreenshotUiFocusTarget;
#[derive(Debug, Clone, PartialEq)]
pub enum KeyboardFocusTarget {
Surface(WlSurface),
ScreenshotUi(ScreenshotUiFocusTarget),
Overview,
}
#[derive(Debug, Clone, PartialEq)]
pub enum PointerFocusTarget {
Surface(WlSurface),
ScreenshotUi(ScreenshotUiFocusTarget),
Overview,
}
impl KeyboardFocusTarget {
fn inner(&self) -> &dyn KeyboardTarget<State> {
match self {
Self::Surface(surface) => surface,
Self::ScreenshotUi(x) => x,
Self::Overview => todo!(),
}
}
}
impl PointerFocusTarget {
fn inner(&self) -> &dyn PointerTarget<State> {
match self {
Self::Surface(surface) => surface,
Self::ScreenshotUi(x) => x,
Self::Overview => todo!(),
}
}
pub fn surface(&self) -> Option<&WlSurface> {
match self {
PointerFocusTarget::Surface(surface) => Some(surface),
PointerFocusTarget::ScreenshotUi(_) => None,
PointerFocusTarget::Overview => None,
}
}
}
impl From<KeyboardFocusTarget> for PointerFocusTarget {
fn from(value: KeyboardFocusTarget) -> Self {
match value {
KeyboardFocusTarget::Surface(surface) => Self::Surface(surface),
KeyboardFocusTarget::ScreenshotUi(x) => Self::ScreenshotUi(x),
KeyboardFocusTarget::Overview => Self::Overview,
}
}
}
impl From<PopupKind> for KeyboardFocusTarget {
fn from(value: PopupKind) -> Self {
Self::Surface(value.wl_surface().clone())
}
}
impl WaylandFocus for KeyboardFocusTarget {
fn wl_surface(&self) -> Option<Cow<'_, WlSurface>> {
match self {
Self::Surface(surface) => Some(surface),
Self::ScreenshotUi(_) => None,
Self::Overview => None,
}
.map(Cow::Borrowed)
}
}
impl WaylandFocus for PointerFocusTarget {
fn wl_surface(&self) -> Option<Cow<'_, WlSurface>> {
self.surface().map(Cow::Borrowed)
}
}
impl IsAlive for KeyboardFocusTarget {
fn alive(&self) -> bool {
match self {
Self::Surface(surface) => surface.alive(),
Self::ScreenshotUi(_) => true,
Self::Overview => true,
}
}
}
impl IsAlive for PointerFocusTarget {
fn alive(&self) -> bool {
match self {
Self::Surface(surface) => surface.alive(),
Self::ScreenshotUi(_) => true,
Self::Overview => true,
}
}
}
impl KeyboardTarget<State> for KeyboardFocusTarget {
fn enter(
&self,
seat: &Seat<State>,
data: &mut State,
keys: Vec<KeysymHandle<'_>>,
serial: Serial,
) {
self.inner().enter(seat, data, keys, serial);
}
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial) {
self.inner().leave(seat, data, serial);
}
fn key(
&self,
seat: &Seat<State>,
data: &mut State,
key: KeysymHandle<'_>,
state: KeyState,
serial: Serial,
time: u32,
) {
self.inner().key(seat, data, key, state, serial, time);
}
fn modifiers(
&self,
seat: &Seat<State>,
data: &mut State,
modifiers: ModifiersState,
serial: Serial,
) {
self.inner().modifiers(seat, data, modifiers, serial);
}
}
impl PointerTarget<State> for PointerFocusTarget {
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &pointer::MotionEvent) {
self.inner().enter(seat, data, event);
}
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &pointer::MotionEvent) {
self.inner().motion(seat, data, event);
}
fn relative_motion(
&self,
seat: &Seat<State>,
data: &mut State,
event: &pointer::RelativeMotionEvent,
) {
self.inner().relative_motion(seat, data, event);
}
fn button(&self, seat: &Seat<State>, data: &mut State, event: &pointer::ButtonEvent) {
self.inner().button(seat, data, event);
}
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: pointer::AxisFrame) {
self.inner().axis(seat, data, frame);
}
fn frame(&self, seat: &Seat<State>, data: &mut State) {
self.inner().frame(seat, data);
}
fn gesture_swipe_begin(
&self,
seat: &Seat<State>,
data: &mut State,
event: &pointer::GestureSwipeBeginEvent,
) {
self.inner().gesture_swipe_begin(seat, data, event);
}
fn gesture_swipe_update(
&self,
seat: &Seat<State>,
data: &mut State,
event: &pointer::GestureSwipeUpdateEvent,
) {
self.inner().gesture_swipe_update(seat, data, event);
}
fn gesture_swipe_end(
&self,
seat: &Seat<State>,
data: &mut State,
event: &pointer::GestureSwipeEndEvent,
) {
self.inner().gesture_swipe_end(seat, data, event);
}
fn gesture_pinch_begin(
&self,
seat: &Seat<State>,
data: &mut State,
event: &pointer::GesturePinchBeginEvent,
) {
self.inner().gesture_pinch_begin(seat, data, event);
}
fn gesture_pinch_update(
&self,
seat: &Seat<State>,
data: &mut State,
event: &pointer::GesturePinchUpdateEvent,
) {
self.inner().gesture_pinch_update(seat, data, event);
}
fn gesture_pinch_end(
&self,
seat: &Seat<State>,
data: &mut State,
event: &pointer::GesturePinchEndEvent,
) {
self.inner().gesture_pinch_end(seat, data, event);
}
fn gesture_hold_begin(
&self,
seat: &Seat<State>,
data: &mut State,
event: &pointer::GestureHoldBeginEvent,
) {
self.inner().gesture_hold_begin(seat, data, event);
}
fn gesture_hold_end(
&self,
seat: &Seat<State>,
data: &mut State,
event: &pointer::GestureHoldEndEvent,
) {
self.inner().gesture_hold_end(seat, data, event);
}
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) {
self.inner().leave(seat, data, serial, time);
}
}

View file

@ -40,6 +40,7 @@ use smithay::wayland::keyboard_shortcuts_inhibit::{
};
use smithay::wayland::output::OutputHandler;
use smithay::wayland::pointer_constraints::{with_pointer_constraint, PointerConstraintsHandler};
use smithay::wayland::seat::WaylandFocus;
use smithay::wayland::security_context::{
SecurityContext, SecurityContextHandler, SecurityContextListenerSource,
};
@ -75,6 +76,7 @@ use smithay::{
delegate_viewporter, delegate_virtual_keyboard_manager, delegate_xdg_activation,
};
use crate::focus::{KeyboardFocusTarget, PointerFocusTarget};
pub use crate::handlers::xdg_shell::KdeDecorationsModeState;
use crate::layout::workspace::WorkspaceId;
use crate::layout::ActivateWindow;
@ -102,8 +104,8 @@ use crate::{
pub const XDG_ACTIVATION_TOKEN_TIMEOUT: Duration = Duration::from_secs(10);
impl SeatHandler for State {
type KeyboardFocus = WlSurface;
type PointerFocus = WlSurface;
type KeyboardFocus = KeyboardFocusTarget;
type PointerFocus = PointerFocusTarget;
type TouchFocus = WlSurface;
fn seat_state(&mut self) -> &mut SeatState<State> {
@ -111,19 +113,16 @@ impl SeatHandler for State {
}
fn cursor_image(&mut self, _seat: &Seat<Self>, mut image: CursorImageStatus) {
// FIXME: this hack should be removable once the screenshot UI is tracked with a
// PointerFocus properly.
if self.niri.screenshot_ui.is_open() {
image = CursorImageStatus::Named(CursorIcon::Crosshair);
}
self.niri.cursor_manager.set_cursor_image(image);
// FIXME: more granular
self.niri.queue_redraw_all();
}
fn focus_changed(&mut self, seat: &Seat<Self>, focused: Option<&WlSurface>) {
fn focus_changed(&mut self, seat: &Seat<Self>, focused: Option<&KeyboardFocusTarget>) {
let dh = &self.niri.display_handle;
let client = focused.and_then(|s| dh.get_client(s.id()).ok());
let client = focused
.and_then(|t| t.wl_surface())
.and_then(|s| dh.get_client(s.id()).ok());
set_data_device_focus(dh, seat, client.clone());
set_primary_focus(dh, seat, client);
}

View file

@ -38,6 +38,7 @@ use smithay::{
};
use tracing::field::Empty;
use crate::focus::KeyboardFocusTarget;
use crate::input::move_grab::MoveGrab;
use crate::input::resize_grab::ResizeGrab;
use crate::input::touch_move_grab::TouchMoveGrab;
@ -83,14 +84,16 @@ impl XdgShellHandler for State {
if grab_serial == serial {
let start_data = grab.start_data();
if let Some((focus, _)) = &start_data.focus {
if focus.id().same_client_as(&wl_surface.id()) {
// Deny move requests from DnD grabs to work around
// https://gitlab.gnome.org/GNOME/gtk/-/issues/7113
let is_dnd_grab = grab.as_any().is::<DnDGrab<Self>>();
if let Some(focus) = focus.surface() {
if focus.id().same_client_as(&wl_surface.id()) {
// Deny move requests from DnD grabs to work around
// https://gitlab.gnome.org/GNOME/gtk/-/issues/7113
let is_dnd_grab = grab.as_any().is::<DnDGrab<Self>>();
if !is_dnd_grab {
grab_start_data =
Some(PointerOrTouchStartData::Pointer(start_data.clone()));
if !is_dnd_grab {
grab_start_data =
Some(PointerOrTouchStartData::Pointer(start_data.clone()));
}
}
}
}
@ -182,8 +185,10 @@ impl XdgShellHandler for State {
if pointer.has_grab(serial) {
if let Some(start_data) = pointer.grab_start_data() {
if let Some((focus, _)) = &start_data.focus {
if focus.id().same_client_as(&wl_surface.id()) {
grab_start_data = Some(PointerOrTouchStartData::Pointer(start_data));
if let Some(focus) = focus.surface() {
if focus.id().same_client_as(&wl_surface.id()) {
grab_start_data = Some(PointerOrTouchStartData::Pointer(start_data));
}
}
}
}
@ -372,11 +377,12 @@ impl XdgShellHandler for State {
}
let seat = &self.niri.seat;
let mut grab = match self
.niri
.popups
.grab_popup(root.clone(), popup, seat, serial)
{
let mut grab = match self.niri.popups.grab_popup(
KeyboardFocusTarget::Surface(root.clone()),
popup,
seat,
serial,
) {
Ok(grab) => grab,
Err(err) => {
trace!("ignoring popup grab: {err:?}");

View file

@ -40,6 +40,7 @@ use touch_overview_grab::TouchOverviewGrab;
use self::move_grab::MoveGrab;
use self::resize_grab::ResizeGrab;
use self::spatial_movement_grab::SpatialMovementGrab;
use crate::focus::PointerFocusTarget;
use crate::layout::scrolling::ScrollDirection;
use crate::layout::{ActivateWindow, LayoutElement as _};
use crate::niri::{CastTarget, PointerVisibility, State};
@ -626,9 +627,6 @@ impl State {
}
self.niri.screenshot_ui.close();
self.niri
.cursor_manager
.set_cursor_image(CursorImageStatus::default_named());
self.niri.queue_redraw_all();
}
Action::ScreenshotTogglePointer => {
@ -2152,14 +2150,16 @@ impl State {
//
// FIXME: ideally this should use the pointer focus with up-to-date global location.
let mut pointer_confined = None;
if let Some(under) = &self.niri.pointer_contents.surface {
if let Some(under @ (PointerFocusTarget::Surface(surface), _)) =
&self.niri.pointer_contents.target
{
// No need to check if the pointer focus surface matches, because here we're checking
// for an already-active constraint, and the constraint is deactivated when the focused
// surface changes.
let pos_within_surface = pos - under.1;
let mut pointer_locked = false;
with_pointer_constraint(&under.0, &pointer, |constraint| {
with_pointer_constraint(surface, &pointer, |constraint| {
let Some(constraint) = constraint else { return };
if !constraint.is_active() {
return;
@ -2251,7 +2251,7 @@ impl State {
let mut prevent = false;
// Prevent the pointer from leaving the focused surface.
if Some(&focus_surface.0) != under.surface.as_ref().map(|(s, _)| s) {
if Some(&focus_surface.0) != under.target.as_ref().map(|(s, _)| s) {
prevent = true;
}
@ -2286,7 +2286,7 @@ impl State {
pointer.motion(
self,
under.surface.clone(),
under.target.clone(),
&MotionEvent {
location: new_pos,
serial,
@ -2296,7 +2296,7 @@ impl State {
pointer.relative_motion(
self,
under.surface,
under.target,
&RelativeMotionEvent {
delta: event.delta(),
delta_unaccel: event.delta_unaccel(),
@ -2385,7 +2385,7 @@ impl State {
pointer.motion(
self,
under.surface,
under.target,
&MotionEvent {
location: pos,
serial,
@ -2761,7 +2761,9 @@ impl State {
// updating the pointer contents.
pointer
.current_focus()
.map(|surface| self.niri.find_root_shell_surface(&surface))
.as_ref()
.and_then(|target| target.surface())
.map(|surface| self.niri.find_root_shell_surface(surface))
.map_or(true, |root| {
!self
.niri
@ -3102,7 +3104,9 @@ impl State {
// Get window-specific scroll factor
let window_scroll_factor = pointer
.current_focus()
.map(|focused| self.niri.find_root_shell_surface(&focused))
.as_ref()
.and_then(|target| target.surface())
.map(|focused| self.niri.find_root_shell_surface(focused))
.and_then(|root| self.niri.layout.find_window_and_output(&root).unzip().0)
.and_then(|window| window.rules().scroll_factor)
.unwrap_or(1.);

View file

@ -7,6 +7,7 @@ pub mod cli;
pub mod cursor;
#[cfg(feature = "dbus")]
pub mod dbus;
pub mod focus;
pub mod frame_clock;
pub mod handlers;
pub mod input;

View file

@ -122,6 +122,7 @@ use crate::dbus::gnome_shell_introspect::{self, IntrospectToNiri, NiriToIntrospe
use crate::dbus::gnome_shell_screenshot::{NiriToScreenshot, ScreenshotToNiri};
#[cfg(feature = "xdp-gnome-screencast")]
use crate::dbus::mutter_screen_cast::{self, ScreenCastToNiri};
use crate::focus::{KeyboardFocusTarget, PointerFocusTarget};
use crate::frame_clock::FrameClock;
use crate::handlers::{configure_lock_surface, XDG_ACTIVATION_TOKEN_TIMEOUT};
use crate::input::pick_color_grab::PickColorGrab;
@ -161,7 +162,9 @@ use crate::ui::config_error_notification::ConfigErrorNotification;
use crate::ui::exit_confirm_dialog::ExitConfirmDialog;
use crate::ui::hotkey_overlay::HotkeyOverlay;
use crate::ui::screen_transition::{self, ScreenTransition};
use crate::ui::screenshot_ui::{OutputScreenshot, ScreenshotUi, ScreenshotUiRenderElement};
use crate::ui::screenshot_ui::{
OutputScreenshot, ScreenshotUi, ScreenshotUiFocusTarget, ScreenshotUiRenderElement,
};
use crate::utils::scale::{closest_representable_scale, guess_monitor_scale};
use crate::utils::spawning::{CHILD_DISPLAY, CHILD_ENV};
use crate::utils::watcher::Watcher;
@ -524,6 +527,7 @@ pub struct PointContents {
// Can be `None` even when `window` is set, for example when the pointer is over the niri
// border around the window.
pub surface: Option<(WlSurface, Point<f64, Logical>)>,
pub target: Option<(PointerFocusTarget, Point<f64, Logical>)>,
// If surface belongs to a window, this is that window.
pub window: Option<(Window, HitType)>,
// If surface belongs to a layer surface, this is that layer surface.
@ -630,6 +634,18 @@ impl KeyboardFocus {
pub fn is_overview(&self) -> bool {
matches!(self, KeyboardFocus::Overview)
}
pub fn into_target(self) -> Option<KeyboardFocusTarget> {
match self {
KeyboardFocus::Layout { surface } => surface.map(KeyboardFocusTarget::Surface),
KeyboardFocus::LayerShell { surface } => Some(KeyboardFocusTarget::Surface(surface)),
KeyboardFocus::LockScreen { surface } => surface.map(KeyboardFocusTarget::Surface),
KeyboardFocus::ScreenshotUi => {
Some(KeyboardFocusTarget::ScreenshotUi(ScreenshotUiFocusTarget))
}
KeyboardFocus::Overview => Some(KeyboardFocusTarget::Overview),
}
}
}
pub struct State {
@ -787,7 +803,7 @@ impl State {
let pointer = &self.niri.seat.get_pointer().unwrap();
pointer.motion(
self,
under.surface,
under.target,
&MotionEvent {
location,
serial: SERIAL_COUNTER.next_serial(),
@ -998,7 +1014,7 @@ impl State {
pointer.motion(
self,
under.surface,
under.target,
&MotionEvent {
location,
serial: SERIAL_COUNTER.next_serial(),
@ -1276,7 +1292,7 @@ impl State {
}
self.niri.keyboard_focus.clone_from(&focus);
keyboard.set_focus(self, focus.into_surface(), SERIAL_COUNTER.next_serial());
keyboard.set_focus(self, focus.into_target(), SERIAL_COUNTER.next_serial());
// FIXME: can be more granular.
self.niri.queue_redraw_all();
@ -1810,9 +1826,6 @@ impl State {
.open(renderer, screenshots, default_output, show_pointer)
});
self.niri
.cursor_manager
.set_cursor_image(CursorImageStatus::Named(CursorIcon::Crosshair));
self.niri.queue_redraw_all();
}
@ -1851,9 +1864,6 @@ impl State {
});
self.niri.screenshot_ui.close();
self.niri
.cursor_manager
.set_cursor_image(CursorImageStatus::default_named());
self.niri.queue_redraw_all();
}
@ -2997,8 +3007,6 @@ impl Niri {
}
if self.screenshot_ui.close() {
self.cursor_manager
.set_cursor_image(CursorImageStatus::default_named());
self.queue_redraw_all();
}
}
@ -3044,8 +3052,6 @@ impl Niri {
// physical coordinates.
if old_size != size || old_scale != scale || old_transform != transform {
self.screenshot_ui.close();
self.cursor_manager
.set_cursor_image(CursorImageStatus::default_named());
self.queue_redraw_all();
return;
}
@ -3303,11 +3309,19 @@ impl Niri {
(pos_within_output + output_pos_in_global_space).to_f64(),
)
});
rv.target = rv
.surface
.as_ref()
.map(|(surface, pos)| (PointerFocusTarget::Surface(surface.clone()), *pos));
return rv;
}
if self.screenshot_ui.is_open() {
rv.target = Some((
PointerFocusTarget::ScreenshotUi(ScreenshotUiFocusTarget),
Point::new(0., 0.),
));
return rv;
}
@ -3417,6 +3431,10 @@ impl Niri {
.or_else(|| layer_popup_under(Layer::Top))
.or_else(|| layer_toplevel_under(Layer::Top));
if is_overview_open && under.is_none() {
rv.target = Some((PointerFocusTarget::Overview, Point::new(0., 0.)));
}
under = under.or_else(interactive_moved_window_under);
if !is_overview_open {
@ -3445,6 +3463,12 @@ impl Niri {
rv.surface = surface_and_pos;
rv.window = window;
rv.layer = layer;
if rv.target.is_none() {
rv.target = rv
.surface
.as_ref()
.map(|(surface, pos)| (PointerFocusTarget::Surface(surface.clone()), *pos));
}
rv
}
@ -5686,8 +5710,6 @@ impl Niri {
if self.output_state.is_empty() {
// There are no outputs, lock the session right away.
self.screenshot_ui.close();
self.cursor_manager
.set_cursor_image(CursorImageStatus::default_named());
let lock = confirmation.ext_session_lock().clone();
confirmation.lock();
@ -5746,8 +5768,6 @@ impl Niri {
self.event_loop.remove(deadline_token);
self.screenshot_ui.close();
self.cursor_manager
.set_cursor_image(CursorImageStatus::default_named());
if self.output_state.is_empty() {
// There are no outputs, lock the session right away.
@ -5893,7 +5913,7 @@ impl Niri {
};
let pointer = self.seat.get_pointer().unwrap();
if Some(surface) != pointer.current_focus().as_ref() {
if Some(surface) != pointer.current_focus().as_ref().and_then(|x| x.surface()) {
return;
}

View file

@ -12,17 +12,20 @@ use niri_ipc::SizeChange;
use pango::{Alignment, FontDescription};
use pangocairo::cairo::{self, ImageSurface};
use smithay::backend::allocator::Fourcc;
use smithay::backend::input::TouchSlot;
use smithay::backend::input::{KeyState, TouchSlot};
use smithay::backend::renderer::element::utils::{Relocate, RelocateRenderElement};
use smithay::backend::renderer::element::Kind;
use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture};
use smithay::backend::renderer::{ExportMem, Texture as _};
use smithay::input::keyboard::{Keysym, ModifiersState};
use smithay::input::keyboard::{KeyboardTarget, Keysym, KeysymHandle, ModifiersState};
use smithay::input::pointer::{self, CursorIcon, CursorImageStatus, PointerTarget};
use smithay::input::{Seat, SeatHandler};
use smithay::output::{Output, WeakOutput};
use smithay::utils::{Buffer, Physical, Point, Rectangle, Scale, Size, Transform};
use smithay::utils::{Buffer, IsAlive, Physical, Point, Rectangle, Scale, Serial, Size, Transform};
use crate::animation::{Animation, Clock};
use crate::layout::floating::DIRECTIONAL_MOVE_PX;
use crate::niri::State;
use crate::niri_render_elements;
use crate::render_helpers::primary_gpu_texture::PrimaryGpuTextureRenderElement;
use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement};
@ -1204,3 +1207,133 @@ fn render_panel(
Ok(buffer)
}
#[derive(Debug, Clone, PartialEq)]
pub struct ScreenshotUiFocusTarget;
impl IsAlive for ScreenshotUiFocusTarget {
fn alive(&self) -> bool {
true
}
}
impl KeyboardTarget<State> for ScreenshotUiFocusTarget {
fn enter(
&self,
seat: &Seat<State>,
data: &mut State,
keys: Vec<KeysymHandle<'_>>,
serial: Serial,
) {
}
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial) {}
fn key(
&self,
seat: &Seat<State>,
data: &mut State,
key: KeysymHandle<'_>,
state: KeyState,
serial: Serial,
time: u32,
) {
}
fn modifiers(
&self,
seat: &Seat<State>,
data: &mut State,
modifiers: ModifiersState,
serial: Serial,
) {
}
}
impl PointerTarget<State> for ScreenshotUiFocusTarget {
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &pointer::MotionEvent) {
data.cursor_image(seat, CursorImageStatus::Named(CursorIcon::Crosshair));
}
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &pointer::MotionEvent) {}
fn relative_motion(
&self,
seat: &Seat<State>,
data: &mut State,
event: &pointer::RelativeMotionEvent,
) {
}
fn button(&self, seat: &Seat<State>, data: &mut State, event: &pointer::ButtonEvent) {}
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: pointer::AxisFrame) {}
fn frame(&self, seat: &Seat<State>, data: &mut State) {}
fn gesture_swipe_begin(
&self,
seat: &Seat<State>,
data: &mut State,
event: &pointer::GestureSwipeBeginEvent,
) {
}
fn gesture_swipe_update(
&self,
seat: &Seat<State>,
data: &mut State,
event: &pointer::GestureSwipeUpdateEvent,
) {
}
fn gesture_swipe_end(
&self,
seat: &Seat<State>,
data: &mut State,
event: &pointer::GestureSwipeEndEvent,
) {
}
fn gesture_pinch_begin(
&self,
seat: &Seat<State>,
data: &mut State,
event: &pointer::GesturePinchBeginEvent,
) {
}
fn gesture_pinch_update(
&self,
seat: &Seat<State>,
data: &mut State,
event: &pointer::GesturePinchUpdateEvent,
) {
}
fn gesture_pinch_end(
&self,
seat: &Seat<State>,
data: &mut State,
event: &pointer::GesturePinchEndEvent,
) {
}
fn gesture_hold_begin(
&self,
seat: &Seat<State>,
data: &mut State,
event: &pointer::GestureHoldBeginEvent,
) {
}
fn gesture_hold_end(
&self,
seat: &Seat<State>,
data: &mut State,
event: &pointer::GestureHoldEndEvent,
) {
}
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) {}
}