wayland.seat: Pointer grabbing logic
This commit is contained in:
parent
1301fb6e62
commit
139d0f3992
|
@ -17,7 +17,7 @@ use smithay::{
|
|||
self, Event, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, PointerAxisEvent,
|
||||
PointerButtonEvent, PointerMotionAbsoluteEvent, PointerMotionEvent,
|
||||
},
|
||||
wayland::seat::{keysyms as xkb, KeyboardHandle, Keysym, ModifiersState, PointerHandle},
|
||||
wayland::seat::{keysyms as xkb, AxisFrame, KeyboardHandle, Keysym, ModifiersState, PointerHandle},
|
||||
wayland_server::protocol::wl_pointer,
|
||||
};
|
||||
|
||||
|
@ -171,11 +171,7 @@ impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
|
|||
.window_map
|
||||
.borrow()
|
||||
.get_surface_under((location.0, location.1));
|
||||
self.pointer.motion(
|
||||
under.as_ref().map(|&(ref s, (x, y))| (s, x, y)),
|
||||
serial,
|
||||
evt.time(),
|
||||
);
|
||||
self.pointer.motion(*location, under, serial, evt.time());
|
||||
}
|
||||
|
||||
fn on_pointer_move_absolute(&mut self, _: &input::Seat, evt: B::PointerMotionAbsoluteEvent) {
|
||||
|
@ -200,11 +196,7 @@ impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
|
|||
*self.pointer_location.borrow_mut() = (x, y);
|
||||
let serial = self.next_serial();
|
||||
let under = self.window_map.borrow().get_surface_under((x as f64, y as f64));
|
||||
self.pointer.motion(
|
||||
under.as_ref().map(|&(ref s, (x, y))| (s, x, y)),
|
||||
serial,
|
||||
evt.time(),
|
||||
);
|
||||
self.pointer.motion((x, y), under, serial, evt.time());
|
||||
}
|
||||
|
||||
fn on_pointer_button(&mut self, _: &input::Seat, evt: B::PointerButtonEvent) {
|
||||
|
@ -217,13 +209,15 @@ impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
|
|||
};
|
||||
let state = match evt.state() {
|
||||
input::MouseButtonState::Pressed => {
|
||||
// change the keyboard focus
|
||||
// change the keyboard focus unless the pointer is grabbed
|
||||
if !self.pointer.is_grabbed() {
|
||||
let under = self
|
||||
.window_map
|
||||
.borrow_mut()
|
||||
.get_surface_and_bring_to_top(*self.pointer_location.borrow());
|
||||
self.keyboard
|
||||
.set_focus(under.as_ref().map(|&(ref s, _)| s), serial);
|
||||
}
|
||||
wl_pointer::ButtonState::Pressed
|
||||
}
|
||||
input::MouseButtonState::Released => wl_pointer::ButtonState::Released,
|
||||
|
@ -247,25 +241,24 @@ impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
|
|||
let vertical_amount_discrete = evt.amount_discrete(&input::Axis::Vertical);
|
||||
|
||||
{
|
||||
let mut event = self.pointer.axis();
|
||||
event.source(source);
|
||||
let mut frame = AxisFrame::new(evt.time()).source(source);
|
||||
if horizontal_amount != 0.0 {
|
||||
event.value(wl_pointer::Axis::HorizontalScroll, horizontal_amount, evt.time());
|
||||
frame = frame.value(wl_pointer::Axis::HorizontalScroll, horizontal_amount);
|
||||
if let Some(discrete) = horizontal_amount_discrete {
|
||||
event.discrete(wl_pointer::Axis::HorizontalScroll, discrete as i32);
|
||||
frame = frame.discrete(wl_pointer::Axis::HorizontalScroll, discrete as i32);
|
||||
}
|
||||
} else if source == wl_pointer::AxisSource::Finger {
|
||||
event.stop(wl_pointer::Axis::HorizontalScroll, evt.time());
|
||||
frame = frame.stop(wl_pointer::Axis::HorizontalScroll);
|
||||
}
|
||||
if vertical_amount != 0.0 {
|
||||
event.value(wl_pointer::Axis::VerticalScroll, vertical_amount, evt.time());
|
||||
frame = frame.value(wl_pointer::Axis::VerticalScroll, vertical_amount);
|
||||
if let Some(discrete) = vertical_amount_discrete {
|
||||
event.discrete(wl_pointer::Axis::VerticalScroll, discrete as i32);
|
||||
frame = frame.discrete(wl_pointer::Axis::VerticalScroll, discrete as i32);
|
||||
}
|
||||
} else if source == wl_pointer::AxisSource::Finger {
|
||||
event.stop(wl_pointer::Axis::VerticalScroll, evt.time());
|
||||
frame = frame.stop(wl_pointer::Axis::VerticalScroll);
|
||||
}
|
||||
event.done();
|
||||
self.pointer.axis(frame);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ where
|
|||
SD: 'static,
|
||||
D: 'static,
|
||||
{
|
||||
// Find the topmost surface under this point if any and the location of this point in the surface
|
||||
// Find the topmost surface under this point if any and the location of this surface
|
||||
fn matching<F>(
|
||||
&self,
|
||||
point: (f64, f64),
|
||||
|
@ -81,10 +81,7 @@ where
|
|||
height: h,
|
||||
};
|
||||
if my_rect.contains((point.0 as i32, point.1 as i32)) {
|
||||
found = Some((
|
||||
wl_surface.clone(),
|
||||
(point.0 - my_rect.x as f64, point.1 - my_rect.y as f64),
|
||||
));
|
||||
found = Some((wl_surface.clone(), (my_rect.x as f64, my_rect.y as f64)));
|
||||
TraversalAction::Break
|
||||
} else {
|
||||
TraversalAction::DoChildren((x, y))
|
||||
|
|
|
@ -61,8 +61,9 @@ mod pointer;
|
|||
|
||||
pub use self::{
|
||||
keyboard::{keysyms, Error as KeyboardError, KeyboardHandle, Keysym, ModifiersState, XkbConfig},
|
||||
pointer::{PointerAxisHandle, PointerHandle},
|
||||
pointer::{AxisFrame, PointerGrab, PointerHandle, PointerInnerHandle},
|
||||
};
|
||||
|
||||
use wayland_server::{protocol::wl_seat, Display, Global, NewResource, Resource};
|
||||
|
||||
struct Inner {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::sync::{Arc, Mutex, MutexGuard};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use wayland_server::{
|
||||
protocol::{
|
||||
wl_pointer::{Axis, AxisSource, ButtonState, Event, Request, WlPointer},
|
||||
|
@ -9,9 +9,17 @@ use wayland_server::{
|
|||
|
||||
// TODO: handle pointer surface role
|
||||
|
||||
enum GrabStatus {
|
||||
None,
|
||||
Active(u32, Box<PointerGrab>),
|
||||
Borrowed,
|
||||
}
|
||||
|
||||
struct PointerInternal {
|
||||
known_pointers: Vec<Resource<WlPointer>>,
|
||||
focus: Option<Resource<WlSurface>>,
|
||||
focus: Option<(Resource<WlSurface>, (f64, f64))>,
|
||||
location: (f64, f64),
|
||||
grab: GrabStatus,
|
||||
}
|
||||
|
||||
impl PointerInternal {
|
||||
|
@ -19,6 +27,8 @@ impl PointerInternal {
|
|||
PointerInternal {
|
||||
known_pointers: Vec::new(),
|
||||
focus: None,
|
||||
location: (0.0, 0.0),
|
||||
grab: GrabStatus::None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,7 +36,7 @@ impl PointerInternal {
|
|||
where
|
||||
F: FnMut(&Resource<WlPointer>, &Resource<WlSurface>),
|
||||
{
|
||||
if let Some(ref focus) = self.focus {
|
||||
if let Some((ref focus, _)) = self.focus {
|
||||
for ptr in &self.known_pointers {
|
||||
if ptr.same_client_as(focus) {
|
||||
f(ptr, focus)
|
||||
|
@ -34,15 +44,39 @@ impl PointerInternal {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn with_grab<F>(&mut self, f: F)
|
||||
where
|
||||
F: FnOnce(PointerInnerHandle, &mut PointerGrab),
|
||||
{
|
||||
let mut grab = ::std::mem::replace(&mut self.grab, GrabStatus::Borrowed);
|
||||
match grab {
|
||||
GrabStatus::Borrowed => panic!("Accessed a pointer grab from within a pointer grab access."),
|
||||
GrabStatus::Active(_, ref mut handler) => {
|
||||
f(PointerInnerHandle { inner: self }, &mut **handler);
|
||||
}
|
||||
GrabStatus::None => {
|
||||
f(PointerInnerHandle { inner: self }, &mut DefaultGrab);
|
||||
}
|
||||
}
|
||||
|
||||
/// An handle to a keyboard handler
|
||||
if let GrabStatus::Borrowed = self.grab {
|
||||
// the grab has not been ended nor replaced, put it back in place
|
||||
self.grab = grab;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An handle to a pointer handler
|
||||
///
|
||||
/// It can be cloned and all clones manipulate the same internal state. Clones
|
||||
/// can also be sent across threads.
|
||||
///
|
||||
/// This handle gives you access to an interface to send pointer events to your
|
||||
/// clients.
|
||||
///
|
||||
/// When sending events using this handle, they will be intercepted by a pointer
|
||||
/// grab if any is active. See the `PointerGrab` trait for details.
|
||||
#[derive(Clone)]
|
||||
pub struct PointerHandle {
|
||||
inner: Arc<Mutex<PointerInternal>>,
|
||||
|
@ -54,29 +88,177 @@ impl PointerHandle {
|
|||
guard.known_pointers.push(pointer);
|
||||
}
|
||||
|
||||
/// Change the current grab on this pointer to the provided grab
|
||||
///
|
||||
/// Overwrites any current grab.
|
||||
pub fn set_grab<G: PointerGrab + 'static>(&self, grab: G, serial: u32) {
|
||||
self.inner.lock().unwrap().grab = GrabStatus::Active(serial, Box::new(grab));
|
||||
}
|
||||
|
||||
/// Remove any current grab on this pointer, reseting it to the default behavior
|
||||
pub fn unset_grab(&self) {
|
||||
self.inner.lock().unwrap().grab = GrabStatus::None;
|
||||
}
|
||||
|
||||
/// Check if this pointer is currently grabbed with this serial
|
||||
pub fn has_grab(&self, serial: u32) -> bool {
|
||||
let guard = self.inner.lock().unwrap();
|
||||
match guard.grab {
|
||||
GrabStatus::Active(s, _) => s == serial,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if this pointer is currently being grabbed
|
||||
pub fn is_grabbed(&self) -> bool {
|
||||
let guard = self.inner.lock().unwrap();
|
||||
match guard.grab {
|
||||
GrabStatus::None => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Notify that the pointer moved
|
||||
///
|
||||
/// You provide the new location of the pointer, in the form of:
|
||||
///
|
||||
/// - `None` if the pointer is not on top of a client surface
|
||||
/// - `Some(surface, x, y)` if the pointer is focusing surface `surface`,
|
||||
/// at location `(x, y)` relative to this surface
|
||||
/// - The coordinates of the pointer in the global compositor space
|
||||
/// - The surface on top of which the cursor is, and the coordinates of its
|
||||
/// origin in the global compositor space (or `None` of the pointer is not
|
||||
/// on top of a client surface).
|
||||
///
|
||||
/// This will internally take care of notifying the appropriate client objects
|
||||
/// of enter/motion/leave events.
|
||||
pub fn motion(&self, location: Option<(&Resource<WlSurface>, f64, f64)>, serial: u32, time: u32) {
|
||||
let mut guard = self.inner.lock().unwrap();
|
||||
pub fn motion(
|
||||
&self,
|
||||
location: (f64, f64),
|
||||
focus: Option<(Resource<WlSurface>, (f64, f64))>,
|
||||
serial: u32,
|
||||
time: u32,
|
||||
) {
|
||||
self.inner.lock().unwrap().with_grab(move |mut handle, grab| {
|
||||
grab.motion(&mut handle, location, focus, serial, time);
|
||||
});
|
||||
}
|
||||
|
||||
/// Notify that a button was pressed
|
||||
///
|
||||
/// This will internally send the appropriate button event to the client
|
||||
/// objects matching with the currently focused surface.
|
||||
pub fn button(&self, button: u32, state: ButtonState, serial: u32, time: u32) {
|
||||
self.inner.lock().unwrap().with_grab(|mut handle, grab| {
|
||||
grab.button(&mut handle, button, state, serial, time);
|
||||
});
|
||||
}
|
||||
|
||||
/// Start an axis frame
|
||||
///
|
||||
/// A single frame will group multiple scroll events as if they happended in the same instance.
|
||||
/// Dropping the returned `PointerAxisHandle` will group the events together.
|
||||
pub fn axis(&self, details: AxisFrame) {
|
||||
self.inner.lock().unwrap().with_grab(|mut handle, grab| {
|
||||
grab.axis(&mut handle, details);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait to implement a pointer grab
|
||||
///
|
||||
/// In some context, it is necessary to temporarily change the behavior of the pointer. This is
|
||||
/// typically known as a pointer grab. A typicall example would be, during a drag'n'drop operation,
|
||||
/// the underlying surfaces will no longer receive classic pointer event, but rather special events.
|
||||
///
|
||||
/// This trait is the interface to intercept regular pointer events and change them as needed, its
|
||||
/// interface mimicks the `PointerHandle` interface.
|
||||
///
|
||||
/// If your logic decides that the grab should end, both `PointerInnerHandle` and `PointerHandle` have
|
||||
/// a method to change it.
|
||||
///
|
||||
/// When your grab ends (either as you requested it or if it was forcefully cancelled by the server),
|
||||
/// the struct implementing this trait will be dropped. As such you should put clean-up logic in the destructor,
|
||||
/// rather than trying to guess when the grab will end.
|
||||
pub trait PointerGrab: Send + Sync {
|
||||
/// A motion was reported
|
||||
fn motion(
|
||||
&mut self,
|
||||
handle: &mut PointerInnerHandle,
|
||||
location: (f64, f64),
|
||||
focus: Option<(Resource<WlSurface>, (f64, f64))>,
|
||||
serial: u32,
|
||||
time: u32,
|
||||
);
|
||||
/// A button press was reported
|
||||
fn button(
|
||||
&mut self,
|
||||
handle: &mut PointerInnerHandle,
|
||||
button: u32,
|
||||
state: ButtonState,
|
||||
serial: u32,
|
||||
time: u32,
|
||||
);
|
||||
/// An axis scroll was reported
|
||||
fn axis(&mut self, handle: &mut PointerInnerHandle, details: AxisFrame);
|
||||
}
|
||||
|
||||
/// This inner handle is accessed from inside a pointer grab logic, and directly
|
||||
/// sends event to the client
|
||||
pub struct PointerInnerHandle<'a> {
|
||||
inner: &'a mut PointerInternal,
|
||||
}
|
||||
|
||||
impl<'a> PointerInnerHandle<'a> {
|
||||
/// Change the current grab on this pointer to the provided grab
|
||||
///
|
||||
/// Overwrites any current grab.
|
||||
pub fn set_grab<G: PointerGrab + 'static>(&mut self, serial: u32, grab: G) {
|
||||
self.inner.grab = GrabStatus::Active(serial, Box::new(grab));
|
||||
}
|
||||
|
||||
/// Remove any current grab on this pointer, reseting it to the default behavior
|
||||
pub fn unset_grab(&mut self) {
|
||||
self.inner.grab = GrabStatus::None;
|
||||
}
|
||||
|
||||
/// Access the current focus of this pointer
|
||||
pub fn current_focus(&self) -> Option<&(Resource<WlSurface>, (f64, f64))> {
|
||||
self.inner.focus.as_ref()
|
||||
}
|
||||
|
||||
/// Access the current location of this pointer in the global space
|
||||
pub fn current_location(&self) -> (f64, f64) {
|
||||
self.inner.location
|
||||
}
|
||||
|
||||
/// Notify that the pointer moved
|
||||
///
|
||||
/// You provide the new location of the pointer, in the form of:
|
||||
///
|
||||
/// - The coordinates of the pointer in the global compositor space
|
||||
/// - The surface on top of which the cursor is, and the coordinates of its
|
||||
/// origin in the global compositor space (or `None` of the pointer is not
|
||||
/// on top of a client surface).
|
||||
///
|
||||
/// This will internally take care of notifying the appropriate client objects
|
||||
/// of enter/motion/leave events.
|
||||
pub fn motion(
|
||||
&mut self,
|
||||
(x, y): (f64, f64),
|
||||
focus: Option<(Resource<WlSurface>, (f64, f64))>,
|
||||
serial: u32,
|
||||
time: u32,
|
||||
) {
|
||||
// do we leave a surface ?
|
||||
let mut leave = true;
|
||||
if let Some(ref focus) = guard.focus {
|
||||
if let Some((surface, _, _)) = location {
|
||||
if focus.equals(surface) {
|
||||
self.inner.location = (x, y);
|
||||
if let Some((ref current_focus, _)) = self.inner.focus {
|
||||
if let Some((ref surface, _)) = focus {
|
||||
if current_focus.equals(surface) {
|
||||
leave = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if leave {
|
||||
guard.with_focused_pointers(|pointer, surface| {
|
||||
self.inner.with_focused_pointers(|pointer, surface| {
|
||||
pointer.send(Event::Leave {
|
||||
serial,
|
||||
surface: surface.clone(),
|
||||
|
@ -85,19 +267,22 @@ impl PointerHandle {
|
|||
pointer.send(Event::Frame);
|
||||
}
|
||||
});
|
||||
guard.focus = None;
|
||||
self.inner.focus = None;
|
||||
}
|
||||
|
||||
// do we enter one ?
|
||||
if let Some((surface, x, y)) = location {
|
||||
if guard.focus.is_none() {
|
||||
guard.focus = Some(surface.clone());
|
||||
guard.with_focused_pointers(|pointer, surface| {
|
||||
if let Some((surface, (sx, sy))) = focus {
|
||||
let entered = self.inner.focus.is_none();
|
||||
// in all cases, update the focus, the coordinates of the surface
|
||||
// might have changed
|
||||
self.inner.focus = Some((surface.clone(), (sx, sy)));
|
||||
if entered {
|
||||
self.inner.with_focused_pointers(|pointer, surface| {
|
||||
pointer.send(Event::Enter {
|
||||
serial,
|
||||
surface: surface.clone(),
|
||||
surface_x: x,
|
||||
surface_y: y,
|
||||
surface_x: x - sx,
|
||||
surface_y: y - sy,
|
||||
});
|
||||
if pointer.version() >= 5 {
|
||||
pointer.send(Event::Frame);
|
||||
|
@ -105,11 +290,11 @@ impl PointerHandle {
|
|||
})
|
||||
} else {
|
||||
// we were on top of a surface and remained on it
|
||||
guard.with_focused_pointers(|pointer, _| {
|
||||
self.inner.with_focused_pointers(|pointer, _| {
|
||||
pointer.send(Event::Motion {
|
||||
time,
|
||||
surface_x: x,
|
||||
surface_y: y,
|
||||
surface_x: x - sx,
|
||||
surface_y: y - sy,
|
||||
});
|
||||
if pointer.version() >= 5 {
|
||||
pointer.send(Event::Frame);
|
||||
|
@ -124,8 +309,7 @@ impl PointerHandle {
|
|||
/// This will internally send the appropriate button event to the client
|
||||
/// objects matching with the currently focused surface.
|
||||
pub fn button(&self, button: u32, state: ButtonState, serial: u32, time: u32) {
|
||||
let guard = self.inner.lock().unwrap();
|
||||
guard.with_focused_pointers(|pointer, _| {
|
||||
self.inner.with_focused_pointers(|pointer, _| {
|
||||
pointer.send(Event::Button {
|
||||
serial,
|
||||
time,
|
||||
|
@ -138,14 +322,62 @@ impl PointerHandle {
|
|||
})
|
||||
}
|
||||
|
||||
/// Start an axis frame
|
||||
/// Notify that an axis was scrolled
|
||||
///
|
||||
/// A single frame will group multiple scroll events as if they happended in the same instance.
|
||||
/// Dropping the returned `PointerAxisHandle` will group the events together.
|
||||
pub fn axis(&self) -> PointerAxisHandle {
|
||||
PointerAxisHandle {
|
||||
inner: self.inner.lock().unwrap(),
|
||||
/// This will internally send the appropriate axis events to the client
|
||||
/// objects matching with the currently focused surface.
|
||||
pub fn axis(&mut self, details: AxisFrame) {
|
||||
self.inner.with_focused_pointers(|pointer, _| {
|
||||
// axis
|
||||
if details.axis.0 != 0.0 {
|
||||
pointer.send(Event::Axis {
|
||||
time: details.time,
|
||||
axis: Axis::HorizontalScroll,
|
||||
value: details.axis.0,
|
||||
});
|
||||
}
|
||||
if details.axis.1 != 0.0 {
|
||||
pointer.send(Event::Axis {
|
||||
time: details.time,
|
||||
axis: Axis::VerticalScroll,
|
||||
value: details.axis.1,
|
||||
});
|
||||
}
|
||||
if pointer.version() >= 5 {
|
||||
// axis source
|
||||
if let Some(source) = details.source {
|
||||
pointer.send(Event::AxisSource { axis_source: source });
|
||||
}
|
||||
// axis discrete
|
||||
if details.discrete.0 != 0 {
|
||||
pointer.send(Event::AxisDiscrete {
|
||||
axis: Axis::HorizontalScroll,
|
||||
discrete: details.discrete.0,
|
||||
});
|
||||
}
|
||||
if details.discrete.1 != 0 {
|
||||
pointer.send(Event::AxisDiscrete {
|
||||
axis: Axis::VerticalScroll,
|
||||
discrete: details.discrete.1,
|
||||
});
|
||||
}
|
||||
// stop
|
||||
if details.stop.0 {
|
||||
pointer.send(Event::AxisStop {
|
||||
time: details.time,
|
||||
axis: Axis::HorizontalScroll,
|
||||
});
|
||||
}
|
||||
if details.stop.1 {
|
||||
pointer.send(Event::AxisStop {
|
||||
time: details.time,
|
||||
axis: Axis::VerticalScroll,
|
||||
});
|
||||
}
|
||||
// frame
|
||||
pointer.send(Event::Frame);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,17 +386,32 @@ impl PointerHandle {
|
|||
/// Can be used with the builder pattern, e.g.:
|
||||
///
|
||||
/// ```ignore
|
||||
/// pointer.axis()
|
||||
/// AxisFrame::new()
|
||||
/// .source(AxisSource::Wheel)
|
||||
/// .discrete(Axis::Vertical, 6)
|
||||
/// .value(Axis::Vertical, 30, time)
|
||||
/// .stop(Axis::Vertical);
|
||||
/// ```
|
||||
pub struct PointerAxisHandle<'a> {
|
||||
inner: MutexGuard<'a, PointerInternal>,
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct AxisFrame {
|
||||
source: Option<AxisSource>,
|
||||
time: u32,
|
||||
axis: (f64, f64),
|
||||
discrete: (i32, i32),
|
||||
stop: (bool, bool),
|
||||
}
|
||||
|
||||
impl AxisFrame {
|
||||
pub fn new(time: u32) -> Self {
|
||||
AxisFrame {
|
||||
source: None,
|
||||
time,
|
||||
axis: (0.0, 0.0),
|
||||
discrete: (0, 0),
|
||||
stop: (false, false),
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PointerAxisHandle<'a> {
|
||||
/// Specify the source of the axis events
|
||||
///
|
||||
/// This event is optional, if no source is known, you can ignore this call.
|
||||
|
@ -172,12 +419,8 @@ impl<'a> PointerAxisHandle<'a> {
|
|||
///
|
||||
/// Using the `AxisSource::Finger` requires a stop event to be send,
|
||||
/// when the user lifts off the finger (not necessarily in the same frame).
|
||||
pub fn source(&mut self, source: AxisSource) -> &mut Self {
|
||||
self.inner.with_focused_pointers(|pointer, _| {
|
||||
if pointer.version() >= 5 {
|
||||
pointer.send(Event::AxisSource { axis_source: source });
|
||||
}
|
||||
});
|
||||
pub fn source(mut self, source: AxisSource) -> Self {
|
||||
self.source = Some(source);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -186,24 +429,29 @@ impl<'a> PointerAxisHandle<'a> {
|
|||
/// This event is optional and gives the client additional information about
|
||||
/// the nature of the axis event. E.g. a scroll wheel might issue separate steps,
|
||||
/// while a touchpad may never issue this event as it has no steps.
|
||||
pub fn discrete(&mut self, axis: Axis, steps: i32) -> &mut Self {
|
||||
self.inner.with_focused_pointers(|pointer, _| {
|
||||
if pointer.version() >= 5 {
|
||||
pointer.send(Event::AxisDiscrete {
|
||||
axis,
|
||||
discrete: steps,
|
||||
});
|
||||
pub fn discrete(mut self, axis: Axis, steps: i32) -> Self {
|
||||
match axis {
|
||||
Axis::HorizontalScroll => {
|
||||
self.discrete.0 = steps;
|
||||
}
|
||||
});
|
||||
Axis::VerticalScroll => {
|
||||
self.discrete.1 = steps;
|
||||
}
|
||||
};
|
||||
self
|
||||
}
|
||||
|
||||
/// The actual scroll value. This event is the only required one, but can also
|
||||
/// be send multiple times. The values off one frame will be accumulated by the client.
|
||||
pub fn value(&mut self, axis: Axis, value: f64, time: u32) -> &mut Self {
|
||||
self.inner.with_focused_pointers(|pointer, _| {
|
||||
pointer.send(Event::Axis { time, axis, value });
|
||||
});
|
||||
pub fn value(mut self, axis: Axis, value: f64) -> Self {
|
||||
match axis {
|
||||
Axis::HorizontalScroll => {
|
||||
self.axis.0 = value;
|
||||
}
|
||||
Axis::VerticalScroll => {
|
||||
self.axis.1 = value;
|
||||
}
|
||||
};
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -211,27 +459,17 @@ impl<'a> PointerAxisHandle<'a> {
|
|||
///
|
||||
/// This event is required for sources of the `AxisSource::Finger` type
|
||||
/// and otherwise optional.
|
||||
pub fn stop(&mut self, axis: Axis, time: u32) -> &mut Self {
|
||||
self.inner.with_focused_pointers(|pointer, _| {
|
||||
if pointer.version() >= 5 {
|
||||
pointer.send(Event::AxisStop { time, axis });
|
||||
pub fn stop(mut self, axis: Axis) -> Self {
|
||||
match axis {
|
||||
Axis::HorizontalScroll => {
|
||||
self.stop.0 = true;
|
||||
}
|
||||
});
|
||||
Axis::VerticalScroll => {
|
||||
self.stop.1 = true;
|
||||
}
|
||||
};
|
||||
self
|
||||
}
|
||||
|
||||
/// Finish this event
|
||||
///
|
||||
/// This will group all axis calls together.
|
||||
/// Note: They are already submitted to the client, obmitting this call just
|
||||
/// leaves room for additional events.
|
||||
pub fn done(&mut self) {
|
||||
self.inner.with_focused_pointers(|pointer, _| {
|
||||
if pointer.version() >= 5 {
|
||||
pointer.send(Event::Frame);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn create_pointer_handler() -> PointerHandle {
|
||||
|
@ -272,3 +510,95 @@ pub(crate) fn implement_pointer(
|
|||
(),
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
* Grabs definition
|
||||
*/
|
||||
|
||||
// The default grab, the behavior when no particular grab is in progress
|
||||
struct DefaultGrab;
|
||||
|
||||
impl PointerGrab for DefaultGrab {
|
||||
fn motion(
|
||||
&mut self,
|
||||
handle: &mut PointerInnerHandle,
|
||||
location: (f64, f64),
|
||||
focus: Option<(Resource<WlSurface>, (f64, f64))>,
|
||||
serial: u32,
|
||||
time: u32,
|
||||
) {
|
||||
handle.motion(location, focus, serial, time);
|
||||
}
|
||||
fn button(
|
||||
&mut self,
|
||||
handle: &mut PointerInnerHandle,
|
||||
button: u32,
|
||||
state: ButtonState,
|
||||
serial: u32,
|
||||
time: u32,
|
||||
) {
|
||||
handle.button(button, state, serial, time);
|
||||
let current_focus = handle.current_focus().cloned();
|
||||
handle.set_grab(
|
||||
serial,
|
||||
ClickGrab {
|
||||
buttons: vec![button],
|
||||
current_focus,
|
||||
pending_focus: None,
|
||||
},
|
||||
);
|
||||
}
|
||||
fn axis(&mut self, handle: &mut PointerInnerHandle, details: AxisFrame) {
|
||||
handle.axis(details);
|
||||
}
|
||||
}
|
||||
|
||||
// A click grab, basic grab started when an user clicks a surface
|
||||
// to maintain it focused until the user releases the click.
|
||||
//
|
||||
// In case the user maintains several simultaneous clicks, release
|
||||
// the grab once all are released.
|
||||
struct ClickGrab {
|
||||
buttons: Vec<u32>,
|
||||
current_focus: Option<(Resource<WlSurface>, (f64, f64))>,
|
||||
pending_focus: Option<(Resource<WlSurface>, (f64, f64))>,
|
||||
}
|
||||
|
||||
impl PointerGrab for ClickGrab {
|
||||
fn motion(
|
||||
&mut self,
|
||||
handle: &mut PointerInnerHandle,
|
||||
location: (f64, f64),
|
||||
focus: Option<(Resource<WlSurface>, (f64, f64))>,
|
||||
serial: u32,
|
||||
time: u32,
|
||||
) {
|
||||
// buffer the future focus, but maintain the current one
|
||||
self.pending_focus = focus;
|
||||
handle.motion(location, self.current_focus.clone(), serial, time);
|
||||
}
|
||||
fn button(
|
||||
&mut self,
|
||||
handle: &mut PointerInnerHandle,
|
||||
button: u32,
|
||||
state: ButtonState,
|
||||
serial: u32,
|
||||
time: u32,
|
||||
) {
|
||||
match state {
|
||||
ButtonState::Pressed => self.buttons.push(button),
|
||||
ButtonState::Released => self.buttons.retain(|b| *b != button),
|
||||
}
|
||||
handle.button(button, state, serial, time);
|
||||
if self.buttons.is_empty() {
|
||||
// no more buttons are pressed, release the grab
|
||||
handle.unset_grab();
|
||||
// restore the focus
|
||||
let location = handle.current_location();
|
||||
handle.motion(location, self.pending_focus.clone(), serial, time);
|
||||
}
|
||||
}
|
||||
fn axis(&mut self, handle: &mut PointerInnerHandle, details: AxisFrame) {
|
||||
handle.axis(details);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue