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,
|
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.
|
/// Two-finger pinch gesture, often used for magnification.
|
||||||
///
|
///
|
||||||
/// ## Platform-specific
|
/// ## Platform-specific
|
||||||
@@ -1006,9 +1020,17 @@ pub enum Ime {
|
|||||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub enum TouchPhase {
|
pub enum TouchPhase {
|
||||||
|
/// Initial touch contact or gesture start, for example when one or more fingers touch the
|
||||||
|
/// screen or touchpad.
|
||||||
Started,
|
Started,
|
||||||
|
/// The touch contact point changed, for example without lifting the finger.
|
||||||
Moved,
|
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,
|
Ended,
|
||||||
|
/// The event was cancelled and should cancel any event in flight and clear state.
|
||||||
Cancelled,
|
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 }
|
sctk-adwaita = { version = "0.11.0", default-features = false, optional = true }
|
||||||
wayland-backend = { version = "0.3.10", default-features = false, features = ["client_system"] }
|
wayland-backend = { version = "0.3.10", default-features = false, features = ["client_system"] }
|
||||||
wayland-client = "0.31.10"
|
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"] }
|
wayland-protocols-plasma = { version = "0.3.8", features = ["client"] }
|
||||||
winit-common = { workspace = true, features = ["xkb", "wayland"] }
|
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::pointer::{ThemeSpec, ThemedPointer};
|
||||||
use sctk::seat::{Capability as SeatCapability, SeatHandler, SeatState};
|
use sctk::seat::{Capability as SeatCapability, SeatHandler, SeatState};
|
||||||
use tracing::warn;
|
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::pointer_gestures::zv1::client::zwp_pointer_gesture_pinch_v1::ZwpPointerGesturePinchV1;
|
||||||
use wayland_protocols::wp::tablet::zv2::client::zwp_tablet_seat_v2::ZwpTabletSeatV2;
|
use wayland_protocols::wp::tablet::zv2::client::zwp_tablet_seat_v2::ZwpTabletSeatV2;
|
||||||
use winit_core::event::WindowEvent;
|
use winit_core::event::WindowEvent;
|
||||||
@@ -60,6 +61,9 @@ pub struct WinitSeatState {
|
|||||||
/// The pinch pointer gesture bound on the seat.
|
/// The pinch pointer gesture bound on the seat.
|
||||||
pointer_gesture_pinch: Option<ZwpPointerGesturePinchV1>,
|
pointer_gesture_pinch: Option<ZwpPointerGesturePinchV1>,
|
||||||
|
|
||||||
|
/// The hold pointer gesture bound on the seat.
|
||||||
|
pointer_gesture_hold: Option<ZwpPointerGestureHoldV1>,
|
||||||
|
|
||||||
/// The keyboard bound on the seat.
|
/// The keyboard bound on the seat.
|
||||||
keyboard_state: Option<KeyboardState>,
|
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);
|
let themed_pointer = Arc::new(themed_pointer);
|
||||||
|
|
||||||
// Register cursor surface.
|
// Register cursor surface.
|
||||||
@@ -209,6 +221,10 @@ impl SeatHandler for WinitState {
|
|||||||
pointer_gesture_pinch.destroy();
|
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() {
|
if let Some(pointer) = seat_state.pointer.take() {
|
||||||
let pointer_data = pointer.pointer().winit_data();
|
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::globals::{BindError, GlobalList};
|
||||||
use sctk::reexports::client::{Connection, Dispatch, Proxy, QueueHandle, delegate_dispatch};
|
use sctk::reexports::client::{Connection, Dispatch, Proxy, QueueHandle, delegate_dispatch};
|
||||||
use sctk::reexports::protocols::wp::pointer_gestures::zv1::client::zwp_pointer_gesture_pinch_v1::{
|
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 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::event::{TouchPhase, WindowEvent};
|
||||||
use winit_core::window::WindowId;
|
use winit_core::window::WindowId;
|
||||||
|
|
||||||
@@ -27,7 +30,7 @@ impl PointerGesturesState {
|
|||||||
globals: &GlobalList,
|
globals: &GlobalList,
|
||||||
queue_handle: &QueueHandle<WinitState>,
|
queue_handle: &QueueHandle<WinitState>,
|
||||||
) -> Result<Self, BindError> {
|
) -> 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 })
|
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 {
|
impl Dispatch<ZwpPointerGesturePinchV1, PointerGestureData, WinitState> for PointerGesturesState {
|
||||||
fn event(
|
fn event(
|
||||||
state: &mut WinitState,
|
state: &mut WinitState,
|
||||||
@@ -81,7 +127,7 @@ impl Dispatch<ZwpPointerGesturePinchV1, PointerGestureData, WinitState> for Poin
|
|||||||
) {
|
) {
|
||||||
let mut pointer_gesture_data = data.inner.lock().unwrap();
|
let mut pointer_gesture_data = data.inner.lock().unwrap();
|
||||||
let (window_id, phase, pan_delta, pinch_delta, rotation_delta) = match event {
|
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.
|
// We only support two fingers for now.
|
||||||
if fingers != 2 {
|
if fingers != 2 {
|
||||||
return;
|
return;
|
||||||
@@ -100,7 +146,7 @@ impl Dispatch<ZwpPointerGesturePinchV1, PointerGestureData, WinitState> for Poin
|
|||||||
|
|
||||||
(window_id, TouchPhase::Started, PhysicalPosition::new(0., 0.), 0., 0.)
|
(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 {
|
let window_id = match pointer_gesture_data.window_id {
|
||||||
Some(window_id) => window_id,
|
Some(window_id) => window_id,
|
||||||
_ => return,
|
_ => return,
|
||||||
@@ -121,7 +167,7 @@ impl Dispatch<ZwpPointerGesturePinchV1, PointerGestureData, WinitState> for Poin
|
|||||||
let rotation_delta = -rotation as f32;
|
let rotation_delta = -rotation as f32;
|
||||||
(window_id, TouchPhase::Moved, pan_delta, pinch_delta, rotation_delta)
|
(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 {
|
let window_id = match pointer_gesture_data.window_id {
|
||||||
Some(window_id) => window_id,
|
Some(window_id) => window_id,
|
||||||
_ => return,
|
_ => return,
|
||||||
@@ -155,3 +201,4 @@ impl Dispatch<ZwpPointerGesturePinchV1, PointerGestureData, WinitState> for Poin
|
|||||||
|
|
||||||
delegate_dispatch!(WinitState: [ZwpPointerGesturesV1: GlobalData] => PointerGesturesState);
|
delegate_dispatch!(WinitState: [ZwpPointerGesturesV1: GlobalData] => PointerGesturesState);
|
||||||
delegate_dispatch!(WinitState: [ZwpPointerGesturePinchV1: PointerGestureData] => PointerGesturesState);
|
delegate_dispatch!(WinitState: [ZwpPointerGesturePinchV1: PointerGestureData] => PointerGesturesState);
|
||||||
|
delegate_dispatch!(WinitState: [ZwpPointerGestureHoldV1: PointerGestureData] => PointerGesturesState);
|
||||||
|
|||||||
@@ -541,16 +541,7 @@ impl ApplicationHandler for Application {
|
|||||||
WindowEvent::DoubleTapGesture { .. } => {
|
WindowEvent::DoubleTapGesture { .. } => {
|
||||||
info!("Smart zoom");
|
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`.
|
- Implement `Send` and `Sync` for `OwnedDisplayHandle`.
|
||||||
- Use new macOS 15 cursors for resize icons.
|
- Use new macOS 15 cursors for resize icons.
|
||||||
- On Android, added scancode conversions for more obscure key codes.
|
- 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.
|
- On Wayland, added ext-background-effect-v1 support.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
Reference in New Issue
Block a user