wayland.seat: Fix pointer grab API
The pointer grab mecanism had a few inconsistencies in its behavior when a grab is set or unset. THis commit uniformizes the behavior, and also introduces a synthetic motion event when the grab is set, allowing the newly set grab to change the focus or the pointer location if needed. Also adjust the DnDGrab, as well as the resize and move grabs from anvil to unset the focus while they are active, matching weston's behavior.
This commit is contained in:
parent
d04a999bf8
commit
d797cdcdcb
|
@ -48,12 +48,15 @@ struct MoveSurfaceGrab {
|
||||||
impl PointerGrab for MoveSurfaceGrab {
|
impl PointerGrab for MoveSurfaceGrab {
|
||||||
fn motion(
|
fn motion(
|
||||||
&mut self,
|
&mut self,
|
||||||
_handle: &mut PointerInnerHandle<'_>,
|
handle: &mut PointerInnerHandle<'_>,
|
||||||
location: Point<f64, Logical>,
|
location: Point<f64, Logical>,
|
||||||
_focus: Option<(wl_surface::WlSurface, Point<i32, Logical>)>,
|
_focus: Option<(wl_surface::WlSurface, Point<i32, Logical>)>,
|
||||||
_serial: Serial,
|
serial: Serial,
|
||||||
_time: u32,
|
time: u32,
|
||||||
) {
|
) {
|
||||||
|
// While the grab is active, no client has pointer focus
|
||||||
|
handle.motion(location, None, serial, time);
|
||||||
|
|
||||||
let delta = location - self.start_data.location;
|
let delta = location - self.start_data.location;
|
||||||
let new_location = self.initial_window_location.to_f64() + delta;
|
let new_location = self.initial_window_location.to_f64() + delta;
|
||||||
|
|
||||||
|
@ -152,6 +155,9 @@ impl PointerGrab for ResizeSurfaceGrab {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// While the grab is active, no client has pointer focus
|
||||||
|
handle.motion(location, None, serial, time);
|
||||||
|
|
||||||
let (mut dx, mut dy) = (location - self.start_data.location).into();
|
let (mut dx, mut dy) = (location - self.start_data.location).into();
|
||||||
|
|
||||||
let mut new_window_width = self.initial_window_size.w;
|
let mut new_window_width = self.initial_window_size.w;
|
||||||
|
@ -479,7 +485,7 @@ pub fn init_shell<BackendData: 'static>(display: Rc<RefCell<Display>>, log: ::sl
|
||||||
initial_window_location,
|
initial_window_location,
|
||||||
};
|
};
|
||||||
|
|
||||||
pointer.set_grab(grab, serial);
|
pointer.set_grab(grab, serial, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
XdgRequest::Resize {
|
XdgRequest::Resize {
|
||||||
|
@ -539,7 +545,7 @@ pub fn init_shell<BackendData: 'static>(display: Rc<RefCell<Display>>, log: ::sl
|
||||||
last_window_size: initial_window_size,
|
last_window_size: initial_window_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
pointer.set_grab(grab, serial);
|
pointer.set_grab(grab, serial, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
XdgRequest::AckConfigure {
|
XdgRequest::AckConfigure {
|
||||||
|
@ -806,7 +812,7 @@ pub fn init_shell<BackendData: 'static>(display: Rc<RefCell<Display>>, log: ::sl
|
||||||
initial_window_location,
|
initial_window_location,
|
||||||
};
|
};
|
||||||
|
|
||||||
pointer.set_grab(grab, serial);
|
pointer.set_grab(grab, serial, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShellRequest::Resize {
|
ShellRequest::Resize {
|
||||||
|
@ -866,7 +872,7 @@ pub fn init_shell<BackendData: 'static>(display: Rc<RefCell<Display>>, log: ::sl
|
||||||
last_window_size: initial_window_size,
|
last_window_size: initial_window_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
pointer.set_grab(grab, serial);
|
pointer.set_grab(grab, serial, 0);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,12 +53,15 @@ impl DnDGrab {
|
||||||
impl PointerGrab for DnDGrab {
|
impl PointerGrab for DnDGrab {
|
||||||
fn motion(
|
fn motion(
|
||||||
&mut self,
|
&mut self,
|
||||||
_handle: &mut PointerInnerHandle<'_>,
|
handle: &mut PointerInnerHandle<'_>,
|
||||||
location: Point<f64, Logical>,
|
location: Point<f64, Logical>,
|
||||||
focus: Option<(wl_surface::WlSurface, Point<i32, Logical>)>,
|
focus: Option<(wl_surface::WlSurface, Point<i32, Logical>)>,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
time: u32,
|
time: u32,
|
||||||
) {
|
) {
|
||||||
|
// While the grab is active, no client has pointer focus
|
||||||
|
handle.motion(location, None, serial, time);
|
||||||
|
|
||||||
let seat_data = self
|
let seat_data = self
|
||||||
.seat
|
.seat
|
||||||
.user_data()
|
.user_data()
|
||||||
|
|
|
@ -356,6 +356,7 @@ pub fn start_dnd<C>(
|
||||||
Rc::new(RefCell::new(callback)),
|
Rc::new(RefCell::new(callback)),
|
||||||
),
|
),
|
||||||
serial,
|
serial,
|
||||||
|
0,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -457,6 +458,7 @@ where
|
||||||
callback.clone(),
|
callback.clone(),
|
||||||
),
|
),
|
||||||
serial,
|
serial,
|
||||||
|
0,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,76 @@ impl PointerInternal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_grab<G: PointerGrab + 'static>(&mut self, serial: Serial, grab: G, time: u32) {
|
||||||
|
self.grab = GrabStatus::Active(serial, Box::new(grab));
|
||||||
|
// generate a move to let the grab change the focus or move the pointer as result of its initialization
|
||||||
|
let location = self.location;
|
||||||
|
let focus = self.focus.clone();
|
||||||
|
self.motion(location, focus, serial, time);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unset_grab(&mut self, serial: Serial, time: u32) {
|
||||||
|
self.grab = GrabStatus::None;
|
||||||
|
// restore the focus
|
||||||
|
let location = self.location;
|
||||||
|
let focus = self.pending_focus.clone();
|
||||||
|
self.motion(location, focus, serial, time);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motion(
|
||||||
|
&mut self,
|
||||||
|
location: Point<f64, Logical>,
|
||||||
|
focus: Option<(WlSurface, Point<i32, Logical>)>,
|
||||||
|
serial: Serial,
|
||||||
|
time: u32,
|
||||||
|
) {
|
||||||
|
// do we leave a surface ?
|
||||||
|
let mut leave = true;
|
||||||
|
self.location = location;
|
||||||
|
if let Some((ref current_focus, _)) = self.focus {
|
||||||
|
if let Some((ref surface, _)) = focus {
|
||||||
|
if current_focus.as_ref().equals(surface.as_ref()) {
|
||||||
|
leave = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if leave {
|
||||||
|
self.with_focused_pointers(|pointer, surface| {
|
||||||
|
pointer.leave(serial.into(), surface);
|
||||||
|
if pointer.as_ref().version() >= 5 {
|
||||||
|
pointer.frame();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.focus = None;
|
||||||
|
(self.image_callback)(CursorImageStatus::Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
// do we enter one ?
|
||||||
|
if let Some((surface, surface_location)) = focus {
|
||||||
|
let entered = self.focus.is_none();
|
||||||
|
// in all cases, update the focus, the coordinates of the surface
|
||||||
|
// might have changed
|
||||||
|
self.focus = Some((surface, surface_location));
|
||||||
|
let (x, y) = (location - surface_location.to_f64()).into();
|
||||||
|
if entered {
|
||||||
|
self.with_focused_pointers(|pointer, surface| {
|
||||||
|
pointer.enter(serial.into(), surface, x, y);
|
||||||
|
if pointer.as_ref().version() >= 5 {
|
||||||
|
pointer.frame();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// we were on top of a surface and remained on it
|
||||||
|
self.with_focused_pointers(|pointer, _| {
|
||||||
|
pointer.motion(time, x, y);
|
||||||
|
if pointer.as_ref().version() >= 5 {
|
||||||
|
pointer.frame();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn with_focused_pointers<F>(&self, mut f: F)
|
fn with_focused_pointers<F>(&self, mut f: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&WlPointer, &WlSurface),
|
F: FnMut(&WlPointer, &WlSurface),
|
||||||
|
@ -160,13 +230,13 @@ impl PointerHandle {
|
||||||
/// Change the current grab on this pointer to the provided grab
|
/// Change the current grab on this pointer to the provided grab
|
||||||
///
|
///
|
||||||
/// Overwrites any current grab.
|
/// Overwrites any current grab.
|
||||||
pub fn set_grab<G: PointerGrab + 'static>(&self, grab: G, serial: Serial) {
|
pub fn set_grab<G: PointerGrab + 'static>(&self, grab: G, serial: Serial, time: u32) {
|
||||||
self.inner.borrow_mut().grab = GrabStatus::Active(serial, Box::new(grab));
|
self.inner.borrow_mut().set_grab(serial, grab, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove any current grab on this pointer, resetting it to the default behavior
|
/// Remove any current grab on this pointer, resetting it to the default behavior
|
||||||
pub fn unset_grab(&self) {
|
pub fn unset_grab(&self, serial: Serial, time: u32) {
|
||||||
self.inner.borrow_mut().grab = GrabStatus::None;
|
self.inner.borrow_mut().unset_grab(serial, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if this pointer is currently grabbed with this serial
|
/// Check if this pointer is currently grabbed with this serial
|
||||||
|
@ -283,6 +353,13 @@ pub struct GrabStartData {
|
||||||
/// rather than trying to guess when the grab will end.
|
/// rather than trying to guess when the grab will end.
|
||||||
pub trait PointerGrab {
|
pub trait PointerGrab {
|
||||||
/// A motion was reported
|
/// A motion was reported
|
||||||
|
///
|
||||||
|
/// This method allows you attach additional behavior to a motion event, possibly altering it.
|
||||||
|
/// You generally will want to invoke `PointerInnerHandle::motion()` as part of your processing. If you
|
||||||
|
/// don't, the rest of the compositor will behave as if the motion event never occurred.
|
||||||
|
///
|
||||||
|
/// Some grabs (such as drag'n'drop, shell resize and motion) unset the focus while they are active,
|
||||||
|
/// this is achieved by just setting the focus to `None` when invoking `PointerInnerHandle::motion()`.
|
||||||
fn motion(
|
fn motion(
|
||||||
&mut self,
|
&mut self,
|
||||||
handle: &mut PointerInnerHandle<'_>,
|
handle: &mut PointerInnerHandle<'_>,
|
||||||
|
@ -292,6 +369,10 @@ pub trait PointerGrab {
|
||||||
time: u32,
|
time: u32,
|
||||||
);
|
);
|
||||||
/// A button press was reported
|
/// A button press was reported
|
||||||
|
///
|
||||||
|
/// This method allows you attach additional behavior to a button event, possibly altering it.
|
||||||
|
/// You generally will want to invoke `PointerInnerHandle::button()` as part of your processing. If you
|
||||||
|
/// don't, the rest of the compositor will behave as if the button event never occurred.
|
||||||
fn button(
|
fn button(
|
||||||
&mut self,
|
&mut self,
|
||||||
handle: &mut PointerInnerHandle<'_>,
|
handle: &mut PointerInnerHandle<'_>,
|
||||||
|
@ -301,6 +382,10 @@ pub trait PointerGrab {
|
||||||
time: u32,
|
time: u32,
|
||||||
);
|
);
|
||||||
/// An axis scroll was reported
|
/// An axis scroll was reported
|
||||||
|
///
|
||||||
|
/// This method allows you attach additional behavior to an axis event, possibly altering it.
|
||||||
|
/// You generally will want to invoke `PointerInnerHandle::axis()` as part of your processing. If you
|
||||||
|
/// don't, the rest of the compositor will behave as if the axis event never occurred.
|
||||||
fn axis(&mut self, handle: &mut PointerInnerHandle<'_>, details: AxisFrame);
|
fn axis(&mut self, handle: &mut PointerInnerHandle<'_>, details: AxisFrame);
|
||||||
/// The data about the event that started the grab.
|
/// The data about the event that started the grab.
|
||||||
fn start_data(&self) -> &GrabStartData;
|
fn start_data(&self) -> &GrabStartData;
|
||||||
|
@ -317,19 +402,15 @@ impl<'a> PointerInnerHandle<'a> {
|
||||||
/// Change the current grab on this pointer to the provided grab
|
/// Change the current grab on this pointer to the provided grab
|
||||||
///
|
///
|
||||||
/// Overwrites any current grab.
|
/// Overwrites any current grab.
|
||||||
pub fn set_grab<G: PointerGrab + 'static>(&mut self, serial: Serial, grab: G) {
|
pub fn set_grab<G: PointerGrab + 'static>(&mut self, serial: Serial, grab: G, time: u32) {
|
||||||
self.inner.grab = GrabStatus::Active(serial, Box::new(grab));
|
self.inner.set_grab(serial, grab, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove any current grab on this pointer, resetting it to the default behavior
|
/// Remove any current grab on this pointer, resetting it to the default behavior
|
||||||
///
|
///
|
||||||
/// This will also restore the focus of the underlying pointer
|
/// This will also restore the focus of the underlying pointer
|
||||||
pub fn unset_grab(&mut self, serial: Serial, time: u32) {
|
pub fn unset_grab(&mut self, serial: Serial, time: u32) {
|
||||||
self.inner.grab = GrabStatus::None;
|
self.inner.unset_grab(serial, time);
|
||||||
// restore the focus
|
|
||||||
let location = self.current_location();
|
|
||||||
let focus = self.inner.pending_focus.clone();
|
|
||||||
self.motion(location, focus, serial, time);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the current focus of this pointer
|
/// Access the current focus of this pointer
|
||||||
|
@ -368,51 +449,7 @@ impl<'a> PointerInnerHandle<'a> {
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
time: u32,
|
time: u32,
|
||||||
) {
|
) {
|
||||||
// do we leave a surface ?
|
self.inner.motion(location, focus, serial, time);
|
||||||
let mut leave = true;
|
|
||||||
self.inner.location = location;
|
|
||||||
if let Some((ref current_focus, _)) = self.inner.focus {
|
|
||||||
if let Some((ref surface, _)) = focus {
|
|
||||||
if current_focus.as_ref().equals(surface.as_ref()) {
|
|
||||||
leave = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if leave {
|
|
||||||
self.inner.with_focused_pointers(|pointer, surface| {
|
|
||||||
pointer.leave(serial.into(), surface);
|
|
||||||
if pointer.as_ref().version() >= 5 {
|
|
||||||
pointer.frame();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
self.inner.focus = None;
|
|
||||||
(self.inner.image_callback)(CursorImageStatus::Default);
|
|
||||||
}
|
|
||||||
|
|
||||||
// do we enter one ?
|
|
||||||
if let Some((surface, surface_location)) = 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, surface_location));
|
|
||||||
let (x, y) = (location - surface_location.to_f64()).into();
|
|
||||||
if entered {
|
|
||||||
self.inner.with_focused_pointers(|pointer, surface| {
|
|
||||||
pointer.enter(serial.into(), surface, x, y);
|
|
||||||
if pointer.as_ref().version() >= 5 {
|
|
||||||
pointer.frame();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// we were on top of a surface and remained on it
|
|
||||||
self.inner.with_focused_pointers(|pointer, _| {
|
|
||||||
pointer.motion(time, x, y);
|
|
||||||
if pointer.as_ref().version() >= 5 {
|
|
||||||
pointer.frame();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Notify that a button was pressed
|
/// Notify that a button was pressed
|
||||||
|
@ -687,6 +724,7 @@ impl PointerGrab for DefaultGrab {
|
||||||
location: handle.current_location(),
|
location: handle.current_location(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
time,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue