mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-26 14:49:07 -04:00
winit-wayland: add pointer gesture hold
This commit is contained in:
@@ -269,6 +269,20 @@ pub enum WindowEvent {
|
||||
button: ButtonSource,
|
||||
},
|
||||
|
||||
/// Multi-finger hold gesture on the touchpad or touchscreen without movement.
|
||||
///
|
||||
/// The `phase` field indicates the lifecycle of the hold gesture:
|
||||
/// - `Started`: One or more fingers are in contact with the touchpad/touchscreen.
|
||||
/// - `Ended`: All fingers have been lifted from the touchpad/touchscreen.
|
||||
/// - `Cancelled`: The hold gesture was interrupted, for example when another finger touches the
|
||||
/// touchpad (causing a new `Started` event with more fingers), or when movement begins and
|
||||
/// transitions to other gestures like pinch, pan, or rotation.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - Only available on **Wayland**.
|
||||
HoldGesture { device_id: Option<DeviceId>, phase: TouchPhase },
|
||||
|
||||
/// Two-finger pinch gesture, often used for magnification.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
@@ -1006,9 +1020,17 @@ pub enum Ime {
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum TouchPhase {
|
||||
/// Initial touch contact or gesture start, for example when one or more fingers touch the
|
||||
/// screen or touchpad.
|
||||
Started,
|
||||
/// The touch contact point changed, for example without lifting the finger.
|
||||
Moved,
|
||||
/// All touch contact points have been lifted from the touchscreen or touchpad.
|
||||
///
|
||||
/// This event is important as it should clear any state or event in flight that was
|
||||
/// generated by the preceding `Started` and `Moved` events.
|
||||
Ended,
|
||||
/// The event was cancelled and should cancel any event in flight and clear state.
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ sctk = { package = "smithay-client-toolkit", version = "0.20.0", default-feature
|
||||
sctk-adwaita = { version = "0.11.0", default-features = false, optional = true }
|
||||
wayland-backend = { version = "0.3.10", default-features = false, features = ["client_system"] }
|
||||
wayland-client = "0.31.10"
|
||||
wayland-protocols = { version = "0.32.8", features = ["staging"] }
|
||||
wayland-protocols = { version = "0.32.11", features = ["staging", "unstable"] }
|
||||
wayland-protocols-plasma = { version = "0.3.8", features = ["client"] }
|
||||
winit-common = { workspace = true, features = ["xkb", "wayland"] }
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ use sctk::reexports::protocols::wp::text_input::zv3::client::zwp_text_input_v3::
|
||||
use sctk::seat::pointer::{ThemeSpec, ThemedPointer};
|
||||
use sctk::seat::{Capability as SeatCapability, SeatHandler, SeatState};
|
||||
use tracing::warn;
|
||||
use wayland_protocols::wp::pointer_gestures::zv1::client::zwp_pointer_gesture_hold_v1::ZwpPointerGestureHoldV1;
|
||||
use wayland_protocols::wp::pointer_gestures::zv1::client::zwp_pointer_gesture_pinch_v1::ZwpPointerGesturePinchV1;
|
||||
use wayland_protocols::wp::tablet::zv2::client::zwp_tablet_seat_v2::ZwpTabletSeatV2;
|
||||
use winit_core::event::WindowEvent;
|
||||
@@ -60,6 +61,9 @@ pub struct WinitSeatState {
|
||||
/// The pinch pointer gesture bound on the seat.
|
||||
pointer_gesture_pinch: Option<ZwpPointerGesturePinchV1>,
|
||||
|
||||
/// The hold pointer gesture bound on the seat.
|
||||
pointer_gesture_hold: Option<ZwpPointerGestureHoldV1>,
|
||||
|
||||
/// The keyboard bound on the seat.
|
||||
keyboard_state: Option<KeyboardState>,
|
||||
|
||||
@@ -141,6 +145,14 @@ impl SeatHandler for WinitState {
|
||||
)
|
||||
});
|
||||
|
||||
seat_state.pointer_gesture_hold = self.pointer_gestures.as_ref().map(|manager| {
|
||||
manager.get_hold_gesture(
|
||||
themed_pointer.pointer(),
|
||||
queue_handle,
|
||||
PointerGestureData::default(),
|
||||
)
|
||||
});
|
||||
|
||||
let themed_pointer = Arc::new(themed_pointer);
|
||||
|
||||
// Register cursor surface.
|
||||
@@ -209,6 +221,10 @@ impl SeatHandler for WinitState {
|
||||
pointer_gesture_pinch.destroy();
|
||||
}
|
||||
|
||||
if let Some(pointer_gesture_hold) = seat_state.pointer_gesture_hold.take() {
|
||||
pointer_gesture_hold.destroy();
|
||||
}
|
||||
|
||||
if let Some(pointer) = seat_state.pointer.take() {
|
||||
let pointer_data = pointer.pointer().winit_data();
|
||||
|
||||
|
||||
@@ -7,9 +7,12 @@ use sctk::globals::GlobalData;
|
||||
use sctk::reexports::client::globals::{BindError, GlobalList};
|
||||
use sctk::reexports::client::{Connection, Dispatch, Proxy, QueueHandle, delegate_dispatch};
|
||||
use sctk::reexports::protocols::wp::pointer_gestures::zv1::client::zwp_pointer_gesture_pinch_v1::{
|
||||
Event, ZwpPointerGesturePinchV1,
|
||||
Event as PinchEvent, ZwpPointerGesturePinchV1,
|
||||
};
|
||||
use sctk::reexports::protocols::wp::pointer_gestures::zv1::client::zwp_pointer_gestures_v1::ZwpPointerGesturesV1;
|
||||
use wayland_protocols::wp::pointer_gestures::zv1::client::zwp_pointer_gesture_hold_v1::{
|
||||
Event as HoldEvent, ZwpPointerGestureHoldV1,
|
||||
};
|
||||
use winit_core::event::{TouchPhase, WindowEvent};
|
||||
use winit_core::window::WindowId;
|
||||
|
||||
@@ -27,7 +30,7 @@ impl PointerGesturesState {
|
||||
globals: &GlobalList,
|
||||
queue_handle: &QueueHandle<WinitState>,
|
||||
) -> Result<Self, BindError> {
|
||||
let pointer_gestures = globals.bind(queue_handle, 1..=1, GlobalData)?;
|
||||
let pointer_gestures = globals.bind(queue_handle, 3..=3, GlobalData)?;
|
||||
Ok(Self { pointer_gestures })
|
||||
}
|
||||
}
|
||||
@@ -70,6 +73,49 @@ impl Dispatch<ZwpPointerGesturesV1, GlobalData, WinitState> for PointerGesturesS
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<ZwpPointerGestureHoldV1, PointerGestureData, WinitState> for PointerGesturesState {
|
||||
fn event(
|
||||
state: &mut WinitState,
|
||||
_proxy: &ZwpPointerGestureHoldV1,
|
||||
event: <ZwpPointerGestureHoldV1 as wayland_client::Proxy>::Event,
|
||||
data: &PointerGestureData,
|
||||
_conn: &Connection,
|
||||
_qhandle: &QueueHandle<WinitState>,
|
||||
) {
|
||||
let mut pointer_gesture_data = data.inner.lock().unwrap();
|
||||
let (window_id, phase) = match event {
|
||||
HoldEvent::Begin { surface, fingers, .. } => {
|
||||
if fingers < 2 {
|
||||
return;
|
||||
}
|
||||
|
||||
let window_id = crate::make_wid(&surface);
|
||||
pointer_gesture_data.window_id = Some(window_id);
|
||||
|
||||
(window_id, TouchPhase::Started)
|
||||
},
|
||||
HoldEvent::End { cancelled, .. } => {
|
||||
let window_id = match pointer_gesture_data.window_id {
|
||||
Some(window_id) => window_id,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
// Reset the state.
|
||||
*pointer_gesture_data = Default::default();
|
||||
|
||||
let phase = if cancelled == 0 { TouchPhase::Ended } else { TouchPhase::Cancelled };
|
||||
|
||||
(window_id, phase)
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
|
||||
state
|
||||
.events_sink
|
||||
.push_window_event(WindowEvent::HoldGesture { device_id: None, phase }, window_id);
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<ZwpPointerGesturePinchV1, PointerGestureData, WinitState> for PointerGesturesState {
|
||||
fn event(
|
||||
state: &mut WinitState,
|
||||
@@ -81,7 +127,7 @@ impl Dispatch<ZwpPointerGesturePinchV1, PointerGestureData, WinitState> for Poin
|
||||
) {
|
||||
let mut pointer_gesture_data = data.inner.lock().unwrap();
|
||||
let (window_id, phase, pan_delta, pinch_delta, rotation_delta) = match event {
|
||||
Event::Begin { surface, fingers, .. } => {
|
||||
PinchEvent::Begin { surface, fingers, .. } => {
|
||||
// We only support two fingers for now.
|
||||
if fingers != 2 {
|
||||
return;
|
||||
@@ -100,7 +146,7 @@ impl Dispatch<ZwpPointerGesturePinchV1, PointerGestureData, WinitState> for Poin
|
||||
|
||||
(window_id, TouchPhase::Started, PhysicalPosition::new(0., 0.), 0., 0.)
|
||||
},
|
||||
Event::Update { dx, dy, scale: pinch, rotation, .. } => {
|
||||
PinchEvent::Update { dx, dy, scale: pinch, rotation, .. } => {
|
||||
let window_id = match pointer_gesture_data.window_id {
|
||||
Some(window_id) => window_id,
|
||||
_ => return,
|
||||
@@ -121,7 +167,7 @@ impl Dispatch<ZwpPointerGesturePinchV1, PointerGestureData, WinitState> for Poin
|
||||
let rotation_delta = -rotation as f32;
|
||||
(window_id, TouchPhase::Moved, pan_delta, pinch_delta, rotation_delta)
|
||||
},
|
||||
Event::End { cancelled, .. } => {
|
||||
PinchEvent::End { cancelled, .. } => {
|
||||
let window_id = match pointer_gesture_data.window_id {
|
||||
Some(window_id) => window_id,
|
||||
_ => return,
|
||||
@@ -155,3 +201,4 @@ impl Dispatch<ZwpPointerGesturePinchV1, PointerGestureData, WinitState> for Poin
|
||||
|
||||
delegate_dispatch!(WinitState: [ZwpPointerGesturesV1: GlobalData] => PointerGesturesState);
|
||||
delegate_dispatch!(WinitState: [ZwpPointerGesturePinchV1: PointerGestureData] => PointerGesturesState);
|
||||
delegate_dispatch!(WinitState: [ZwpPointerGestureHoldV1: PointerGestureData] => PointerGesturesState);
|
||||
|
||||
@@ -541,16 +541,7 @@ impl ApplicationHandler for Application {
|
||||
WindowEvent::DoubleTapGesture { .. } => {
|
||||
info!("Smart zoom");
|
||||
},
|
||||
WindowEvent::TouchpadPressure { .. }
|
||||
| WindowEvent::DragLeft { .. }
|
||||
| WindowEvent::KeyboardInput { .. }
|
||||
| WindowEvent::PointerEntered { .. }
|
||||
| WindowEvent::DragEntered { .. }
|
||||
| WindowEvent::DragMoved { .. }
|
||||
| WindowEvent::DragDropped { .. }
|
||||
| WindowEvent::Destroyed
|
||||
| WindowEvent::Ime(_)
|
||||
| WindowEvent::Moved(_) => (),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ changelog entry.
|
||||
- Implement `Send` and `Sync` for `OwnedDisplayHandle`.
|
||||
- Use new macOS 15 cursors for resize icons.
|
||||
- On Android, added scancode conversions for more obscure key codes.
|
||||
- On Wayland, added `HoldGesture` event for multi-finger hold gestures
|
||||
- On Wayland, added ext-background-effect-v1 support.
|
||||
|
||||
### Changed
|
||||
|
||||
Reference in New Issue
Block a user