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,
|
self, Event, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, PointerAxisEvent,
|
||||||
PointerButtonEvent, PointerMotionAbsoluteEvent, PointerMotionEvent,
|
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,
|
wayland_server::protocol::wl_pointer,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -171,11 +171,7 @@ impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
|
||||||
.window_map
|
.window_map
|
||||||
.borrow()
|
.borrow()
|
||||||
.get_surface_under((location.0, location.1));
|
.get_surface_under((location.0, location.1));
|
||||||
self.pointer.motion(
|
self.pointer.motion(*location, under, serial, evt.time());
|
||||||
under.as_ref().map(|&(ref s, (x, y))| (s, x, y)),
|
|
||||||
serial,
|
|
||||||
evt.time(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_pointer_move_absolute(&mut self, _: &input::Seat, evt: B::PointerMotionAbsoluteEvent) {
|
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);
|
*self.pointer_location.borrow_mut() = (x, y);
|
||||||
let serial = self.next_serial();
|
let serial = self.next_serial();
|
||||||
let under = self.window_map.borrow().get_surface_under((x as f64, y as f64));
|
let under = self.window_map.borrow().get_surface_under((x as f64, y as f64));
|
||||||
self.pointer.motion(
|
self.pointer.motion((x, y), under, serial, evt.time());
|
||||||
under.as_ref().map(|&(ref s, (x, y))| (s, x, y)),
|
|
||||||
serial,
|
|
||||||
evt.time(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_pointer_button(&mut self, _: &input::Seat, evt: B::PointerButtonEvent) {
|
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() {
|
let state = match evt.state() {
|
||||||
input::MouseButtonState::Pressed => {
|
input::MouseButtonState::Pressed => {
|
||||||
// change the keyboard focus
|
// change the keyboard focus unless the pointer is grabbed
|
||||||
let under = self
|
if !self.pointer.is_grabbed() {
|
||||||
.window_map
|
let under = self
|
||||||
.borrow_mut()
|
.window_map
|
||||||
.get_surface_and_bring_to_top(*self.pointer_location.borrow());
|
.borrow_mut()
|
||||||
self.keyboard
|
.get_surface_and_bring_to_top(*self.pointer_location.borrow());
|
||||||
.set_focus(under.as_ref().map(|&(ref s, _)| s), serial);
|
self.keyboard
|
||||||
|
.set_focus(under.as_ref().map(|&(ref s, _)| s), serial);
|
||||||
|
}
|
||||||
wl_pointer::ButtonState::Pressed
|
wl_pointer::ButtonState::Pressed
|
||||||
}
|
}
|
||||||
input::MouseButtonState::Released => wl_pointer::ButtonState::Released,
|
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 vertical_amount_discrete = evt.amount_discrete(&input::Axis::Vertical);
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut event = self.pointer.axis();
|
let mut frame = AxisFrame::new(evt.time()).source(source);
|
||||||
event.source(source);
|
|
||||||
if horizontal_amount != 0.0 {
|
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 {
|
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 {
|
} 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 {
|
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 {
|
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 {
|
} 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,
|
SD: 'static,
|
||||||
D: '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>(
|
fn matching<F>(
|
||||||
&self,
|
&self,
|
||||||
point: (f64, f64),
|
point: (f64, f64),
|
||||||
|
@ -81,10 +81,7 @@ where
|
||||||
height: h,
|
height: h,
|
||||||
};
|
};
|
||||||
if my_rect.contains((point.0 as i32, point.1 as i32)) {
|
if my_rect.contains((point.0 as i32, point.1 as i32)) {
|
||||||
found = Some((
|
found = Some((wl_surface.clone(), (my_rect.x as f64, my_rect.y as f64)));
|
||||||
wl_surface.clone(),
|
|
||||||
(point.0 - my_rect.x as f64, point.1 - my_rect.y as f64),
|
|
||||||
));
|
|
||||||
TraversalAction::Break
|
TraversalAction::Break
|
||||||
} else {
|
} else {
|
||||||
TraversalAction::DoChildren((x, y))
|
TraversalAction::DoChildren((x, y))
|
||||||
|
|
|
@ -61,8 +61,9 @@ mod pointer;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
keyboard::{keysyms, Error as KeyboardError, KeyboardHandle, Keysym, ModifiersState, XkbConfig},
|
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};
|
use wayland_server::{protocol::wl_seat, Display, Global, NewResource, Resource};
|
||||||
|
|
||||||
struct Inner {
|
struct Inner {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::sync::{Arc, Mutex, MutexGuard};
|
use std::sync::{Arc, Mutex};
|
||||||
use wayland_server::{
|
use wayland_server::{
|
||||||
protocol::{
|
protocol::{
|
||||||
wl_pointer::{Axis, AxisSource, ButtonState, Event, Request, WlPointer},
|
wl_pointer::{Axis, AxisSource, ButtonState, Event, Request, WlPointer},
|
||||||
|
@ -9,9 +9,17 @@ use wayland_server::{
|
||||||
|
|
||||||
// TODO: handle pointer surface role
|
// TODO: handle pointer surface role
|
||||||
|
|
||||||
|
enum GrabStatus {
|
||||||
|
None,
|
||||||
|
Active(u32, Box<PointerGrab>),
|
||||||
|
Borrowed,
|
||||||
|
}
|
||||||
|
|
||||||
struct PointerInternal {
|
struct PointerInternal {
|
||||||
known_pointers: Vec<Resource<WlPointer>>,
|
known_pointers: Vec<Resource<WlPointer>>,
|
||||||
focus: Option<Resource<WlSurface>>,
|
focus: Option<(Resource<WlSurface>, (f64, f64))>,
|
||||||
|
location: (f64, f64),
|
||||||
|
grab: GrabStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PointerInternal {
|
impl PointerInternal {
|
||||||
|
@ -19,6 +27,8 @@ impl PointerInternal {
|
||||||
PointerInternal {
|
PointerInternal {
|
||||||
known_pointers: Vec::new(),
|
known_pointers: Vec::new(),
|
||||||
focus: None,
|
focus: None,
|
||||||
|
location: (0.0, 0.0),
|
||||||
|
grab: GrabStatus::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +36,7 @@ impl PointerInternal {
|
||||||
where
|
where
|
||||||
F: FnMut(&Resource<WlPointer>, &Resource<WlSurface>),
|
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 {
|
for ptr in &self.known_pointers {
|
||||||
if ptr.same_client_as(focus) {
|
if ptr.same_client_as(focus) {
|
||||||
f(ptr, 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 keyboard handler
|
/// An handle to a pointer handler
|
||||||
///
|
///
|
||||||
/// It can be cloned and all clones manipulate the same internal state. Clones
|
/// It can be cloned and all clones manipulate the same internal state. Clones
|
||||||
/// can also be sent across threads.
|
/// can also be sent across threads.
|
||||||
///
|
///
|
||||||
/// This handle gives you access to an interface to send pointer events to your
|
/// This handle gives you access to an interface to send pointer events to your
|
||||||
/// clients.
|
/// 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)]
|
#[derive(Clone)]
|
||||||
pub struct PointerHandle {
|
pub struct PointerHandle {
|
||||||
inner: Arc<Mutex<PointerInternal>>,
|
inner: Arc<Mutex<PointerInternal>>,
|
||||||
|
@ -54,29 +88,177 @@ impl PointerHandle {
|
||||||
guard.known_pointers.push(pointer);
|
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
|
/// Notify that the pointer moved
|
||||||
///
|
///
|
||||||
/// You provide the new location of the pointer, in the form of:
|
/// You provide the new location of the pointer, in the form of:
|
||||||
///
|
///
|
||||||
/// - `None` if the pointer is not on top of a client surface
|
/// - The coordinates of the pointer in the global compositor space
|
||||||
/// - `Some(surface, x, y)` if the pointer is focusing surface `surface`,
|
/// - The surface on top of which the cursor is, and the coordinates of its
|
||||||
/// at location `(x, y)` relative to this surface
|
/// 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
|
/// This will internally take care of notifying the appropriate client objects
|
||||||
/// of enter/motion/leave events.
|
/// of enter/motion/leave events.
|
||||||
pub fn motion(&self, location: Option<(&Resource<WlSurface>, f64, f64)>, serial: u32, time: u32) {
|
pub fn motion(
|
||||||
let mut guard = self.inner.lock().unwrap();
|
&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 ?
|
// do we leave a surface ?
|
||||||
let mut leave = true;
|
let mut leave = true;
|
||||||
if let Some(ref focus) = guard.focus {
|
self.inner.location = (x, y);
|
||||||
if let Some((surface, _, _)) = location {
|
if let Some((ref current_focus, _)) = self.inner.focus {
|
||||||
if focus.equals(surface) {
|
if let Some((ref surface, _)) = focus {
|
||||||
|
if current_focus.equals(surface) {
|
||||||
leave = false;
|
leave = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if leave {
|
if leave {
|
||||||
guard.with_focused_pointers(|pointer, surface| {
|
self.inner.with_focused_pointers(|pointer, surface| {
|
||||||
pointer.send(Event::Leave {
|
pointer.send(Event::Leave {
|
||||||
serial,
|
serial,
|
||||||
surface: surface.clone(),
|
surface: surface.clone(),
|
||||||
|
@ -85,19 +267,22 @@ impl PointerHandle {
|
||||||
pointer.send(Event::Frame);
|
pointer.send(Event::Frame);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
guard.focus = None;
|
self.inner.focus = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// do we enter one ?
|
// do we enter one ?
|
||||||
if let Some((surface, x, y)) = location {
|
if let Some((surface, (sx, sy))) = focus {
|
||||||
if guard.focus.is_none() {
|
let entered = self.inner.focus.is_none();
|
||||||
guard.focus = Some(surface.clone());
|
// in all cases, update the focus, the coordinates of the surface
|
||||||
guard.with_focused_pointers(|pointer, 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 {
|
pointer.send(Event::Enter {
|
||||||
serial,
|
serial,
|
||||||
surface: surface.clone(),
|
surface: surface.clone(),
|
||||||
surface_x: x,
|
surface_x: x - sx,
|
||||||
surface_y: y,
|
surface_y: y - sy,
|
||||||
});
|
});
|
||||||
if pointer.version() >= 5 {
|
if pointer.version() >= 5 {
|
||||||
pointer.send(Event::Frame);
|
pointer.send(Event::Frame);
|
||||||
|
@ -105,11 +290,11 @@ impl PointerHandle {
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// we were on top of a surface and remained on it
|
// 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 {
|
pointer.send(Event::Motion {
|
||||||
time,
|
time,
|
||||||
surface_x: x,
|
surface_x: x - sx,
|
||||||
surface_y: y,
|
surface_y: y - sy,
|
||||||
});
|
});
|
||||||
if pointer.version() >= 5 {
|
if pointer.version() >= 5 {
|
||||||
pointer.send(Event::Frame);
|
pointer.send(Event::Frame);
|
||||||
|
@ -124,8 +309,7 @@ impl PointerHandle {
|
||||||
/// This will internally send the appropriate button event to the client
|
/// This will internally send the appropriate button event to the client
|
||||||
/// objects matching with the currently focused surface.
|
/// objects matching with the currently focused surface.
|
||||||
pub fn button(&self, button: u32, state: ButtonState, serial: u32, time: u32) {
|
pub fn button(&self, button: u32, state: ButtonState, serial: u32, time: u32) {
|
||||||
let guard = self.inner.lock().unwrap();
|
self.inner.with_focused_pointers(|pointer, _| {
|
||||||
guard.with_focused_pointers(|pointer, _| {
|
|
||||||
pointer.send(Event::Button {
|
pointer.send(Event::Button {
|
||||||
serial,
|
serial,
|
||||||
time,
|
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.
|
/// This will internally send the appropriate axis events to the client
|
||||||
/// Dropping the returned `PointerAxisHandle` will group the events together.
|
/// objects matching with the currently focused surface.
|
||||||
pub fn axis(&self) -> PointerAxisHandle {
|
pub fn axis(&mut self, details: AxisFrame) {
|
||||||
PointerAxisHandle {
|
self.inner.with_focused_pointers(|pointer, _| {
|
||||||
inner: self.inner.lock().unwrap(),
|
// 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.:
|
/// Can be used with the builder pattern, e.g.:
|
||||||
///
|
///
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// pointer.axis()
|
/// AxisFrame::new()
|
||||||
/// .source(AxisSource::Wheel)
|
/// .source(AxisSource::Wheel)
|
||||||
/// .discrete(Axis::Vertical, 6)
|
/// .discrete(Axis::Vertical, 6)
|
||||||
/// .value(Axis::Vertical, 30, time)
|
/// .value(Axis::Vertical, 30, time)
|
||||||
/// .stop(Axis::Vertical);
|
/// .stop(Axis::Vertical);
|
||||||
/// ```
|
/// ```
|
||||||
pub struct PointerAxisHandle<'a> {
|
#[derive(Copy, Clone, Debug)]
|
||||||
inner: MutexGuard<'a, PointerInternal>,
|
pub struct AxisFrame {
|
||||||
|
source: Option<AxisSource>,
|
||||||
|
time: u32,
|
||||||
|
axis: (f64, f64),
|
||||||
|
discrete: (i32, i32),
|
||||||
|
stop: (bool, bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PointerAxisHandle<'a> {
|
impl AxisFrame {
|
||||||
|
pub fn new(time: u32) -> Self {
|
||||||
|
AxisFrame {
|
||||||
|
source: None,
|
||||||
|
time,
|
||||||
|
axis: (0.0, 0.0),
|
||||||
|
discrete: (0, 0),
|
||||||
|
stop: (false, false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Specify the source of the axis events
|
/// Specify the source of the axis events
|
||||||
///
|
///
|
||||||
/// This event is optional, if no source is known, you can ignore this call.
|
/// 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,
|
/// Using the `AxisSource::Finger` requires a stop event to be send,
|
||||||
/// when the user lifts off the finger (not necessarily in the same frame).
|
/// when the user lifts off the finger (not necessarily in the same frame).
|
||||||
pub fn source(&mut self, source: AxisSource) -> &mut Self {
|
pub fn source(mut self, source: AxisSource) -> Self {
|
||||||
self.inner.with_focused_pointers(|pointer, _| {
|
self.source = Some(source);
|
||||||
if pointer.version() >= 5 {
|
|
||||||
pointer.send(Event::AxisSource { axis_source: source });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,24 +429,29 @@ impl<'a> PointerAxisHandle<'a> {
|
||||||
/// This event is optional and gives the client additional information about
|
/// 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,
|
/// 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.
|
/// while a touchpad may never issue this event as it has no steps.
|
||||||
pub fn discrete(&mut self, axis: Axis, steps: i32) -> &mut Self {
|
pub fn discrete(mut self, axis: Axis, steps: i32) -> Self {
|
||||||
self.inner.with_focused_pointers(|pointer, _| {
|
match axis {
|
||||||
if pointer.version() >= 5 {
|
Axis::HorizontalScroll => {
|
||||||
pointer.send(Event::AxisDiscrete {
|
self.discrete.0 = steps;
|
||||||
axis,
|
|
||||||
discrete: steps,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
Axis::VerticalScroll => {
|
||||||
|
self.discrete.1 = steps;
|
||||||
|
}
|
||||||
|
};
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The actual scroll value. This event is the only required one, but can also
|
/// 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.
|
/// 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 {
|
pub fn value(mut self, axis: Axis, value: f64) -> Self {
|
||||||
self.inner.with_focused_pointers(|pointer, _| {
|
match axis {
|
||||||
pointer.send(Event::Axis { time, axis, value });
|
Axis::HorizontalScroll => {
|
||||||
});
|
self.axis.0 = value;
|
||||||
|
}
|
||||||
|
Axis::VerticalScroll => {
|
||||||
|
self.axis.1 = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,27 +459,17 @@ impl<'a> PointerAxisHandle<'a> {
|
||||||
///
|
///
|
||||||
/// This event is required for sources of the `AxisSource::Finger` type
|
/// This event is required for sources of the `AxisSource::Finger` type
|
||||||
/// and otherwise optional.
|
/// and otherwise optional.
|
||||||
pub fn stop(&mut self, axis: Axis, time: u32) -> &mut Self {
|
pub fn stop(mut self, axis: Axis) -> Self {
|
||||||
self.inner.with_focused_pointers(|pointer, _| {
|
match axis {
|
||||||
if pointer.version() >= 5 {
|
Axis::HorizontalScroll => {
|
||||||
pointer.send(Event::AxisStop { time, axis });
|
self.stop.0 = true;
|
||||||
}
|
}
|
||||||
});
|
Axis::VerticalScroll => {
|
||||||
|
self.stop.1 = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
self
|
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 {
|
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