mirror of
https://github.com/Smithay/smithay.git
synced 2024-09-28 03:21:14 +02:00
add pointer location hint (#1551)
Some checks failed
Continuous Integration / format (push) Has been cancelled
Continuous Integration / clippy-check (push) Has been cancelled
Continuous Integration / smithay-check-features (push) Has been cancelled
Continuous Integration / check-msrv (push) Has been cancelled
Continuous Integration / check-minimal (push) Has been cancelled
Continuous Integration / smithay-tests (push) Has been cancelled
Continuous Integration / smallvil-check (push) Has been cancelled
Continuous Integration / anvil-check-features (push) Has been cancelled
Continuous Integration / WLCS: Bad Buffer Test (push) Has been cancelled
Continuous Integration / WLCS: Core tests (push) Has been cancelled
Continuous Integration / WLCS: Output tests (push) Has been cancelled
Continuous Integration / WLCS: Pointer input tests (push) Has been cancelled
Continuous Integration / Documentation on Github Pages (push) Has been cancelled
Some checks failed
Continuous Integration / format (push) Has been cancelled
Continuous Integration / clippy-check (push) Has been cancelled
Continuous Integration / smithay-check-features (push) Has been cancelled
Continuous Integration / check-msrv (push) Has been cancelled
Continuous Integration / check-minimal (push) Has been cancelled
Continuous Integration / smithay-tests (push) Has been cancelled
Continuous Integration / smallvil-check (push) Has been cancelled
Continuous Integration / anvil-check-features (push) Has been cancelled
Continuous Integration / WLCS: Bad Buffer Test (push) Has been cancelled
Continuous Integration / WLCS: Core tests (push) Has been cancelled
Continuous Integration / WLCS: Output tests (push) Has been cancelled
Continuous Integration / WLCS: Pointer input tests (push) Has been cancelled
Continuous Integration / Documentation on Github Pages (push) Has been cancelled
* add pointer location hint * describe why `PointerConstraint::commit()` returns a point * implement pointer location hint in anvil * set_location_hint -> set_location * add note that you should frequently be using `PointerHandle::motion`
This commit is contained in:
parent
3b0ecce6c1
commit
debffed7ec
3 changed files with 84 additions and 9 deletions
|
@ -365,6 +365,29 @@ impl<BackendData: Backend> PointerConstraintsHandler for AnvilState<BackendData>
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn cursor_position_hint(
|
||||
&mut self,
|
||||
surface: &WlSurface,
|
||||
pointer: &PointerHandle<Self>,
|
||||
location: Point<f64, Logical>,
|
||||
) {
|
||||
if with_pointer_constraint(surface, pointer, |constraint| {
|
||||
constraint.map_or(false, |c| c.is_active())
|
||||
}) {
|
||||
let origin = self
|
||||
.space
|
||||
.elements()
|
||||
.find_map(|window| {
|
||||
(window.wl_surface().as_deref() == Some(surface)).then(|| window.geometry())
|
||||
})
|
||||
.unwrap_or_default()
|
||||
.loc
|
||||
.to_f64();
|
||||
|
||||
pointer.set_location(origin + location);
|
||||
}
|
||||
}
|
||||
}
|
||||
delegate_pointer_constraints!(@<BackendData: Backend + 'static> AnvilState<BackendData>);
|
||||
|
||||
|
|
|
@ -435,6 +435,26 @@ impl<D: SeatHandler + 'static> PointerHandle<D> {
|
|||
self.inner.lock().unwrap().location
|
||||
}
|
||||
|
||||
/// Update the current location of this pointer in the global space,
|
||||
/// without sending any event and without updating the focus.
|
||||
///
|
||||
/// If you want to update the location, and update the focus,
|
||||
/// and send events, use [Self::motion] instead of this.
|
||||
///
|
||||
/// This is useful when the pointer is only moved by relative events,
|
||||
/// such as when a pointer lock is held by the focused surface.
|
||||
/// The client can give us a cursor position hint, which corresponds to
|
||||
/// the actual location the client may be rendering a pointer at.
|
||||
/// This position hint should be used as the initial location
|
||||
/// when the pointer lock is deactivated.
|
||||
///
|
||||
/// The next time [Self::motion] is called, the focus will be
|
||||
/// updated accordingly as if this function was never called.
|
||||
/// Clients will never be notified of a location hint.
|
||||
pub fn set_location(&self, location: Point<f64, Logical>) {
|
||||
self.inner.lock().unwrap().location = location;
|
||||
}
|
||||
|
||||
/// Access the [`Serial`] of the last `pointer_enter` event, if that focus is still active.
|
||||
///
|
||||
/// In other words this will return `None` again, once a `pointer_leave` event occurred.
|
||||
|
|
|
@ -36,6 +36,18 @@ pub trait PointerConstraintsHandler: SeatHandler {
|
|||
///
|
||||
/// Use [`with_pointer_constraint`] to access the constraint.
|
||||
fn new_constraint(&mut self, surface: &WlSurface, pointer: &PointerHandle<Self>);
|
||||
|
||||
/// The client holding a LockedPointer has commited a cursor position hint.
|
||||
///
|
||||
/// This is emitted upon a surface commit if the cursor position hint has been updated.
|
||||
///
|
||||
/// Use [`with_pointer_constraint`] to access the constraint and check if it is active.
|
||||
fn cursor_position_hint(
|
||||
&mut self,
|
||||
surface: &WlSurface,
|
||||
pointer: &PointerHandle<Self>,
|
||||
location: Point<f64, Logical>,
|
||||
);
|
||||
}
|
||||
|
||||
/// Constraint confining pointer to a region of the surface
|
||||
|
@ -171,14 +183,19 @@ impl PointerConstraint {
|
|||
}
|
||||
}
|
||||
|
||||
fn commit(&mut self) {
|
||||
/// Commits the pending state of the constraint, and returns the cursor position hint if it has changed.
|
||||
fn commit(&mut self) -> Option<Point<f64, Logical>> {
|
||||
match self {
|
||||
Self::Confined(confined) => {
|
||||
confined.region.clone_from(&confined.pending_region);
|
||||
None
|
||||
}
|
||||
Self::Locked(locked) => {
|
||||
locked.region.clone_from(&locked.pending_region);
|
||||
locked.cursor_position_hint = locked.pending_cursor_position_hint;
|
||||
locked.pending_cursor_position_hint.take().map(|hint| {
|
||||
locked.cursor_position_hint = Some(hint);
|
||||
hint
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -243,13 +260,28 @@ pub fn with_pointer_constraint<
|
|||
})
|
||||
}
|
||||
|
||||
fn commit_hook<D: SeatHandler + 'static>(_: &mut D, _dh: &DisplayHandle, surface: &WlSurface) {
|
||||
with_constraint_data::<D, _, _>(surface, |data| {
|
||||
fn commit_hook<D: SeatHandler + PointerConstraintsHandler + 'static>(
|
||||
state: &mut D,
|
||||
_dh: &DisplayHandle,
|
||||
surface: &WlSurface,
|
||||
) {
|
||||
// `with_constraint_data` locks the pointer constraints,
|
||||
// so we collect the hints first into a Vec, then release the mutex
|
||||
// and only once the mutex is released, we call the handler method.
|
||||
//
|
||||
// This is to avoid deadlocks when the handler method might try to access the constraints again.
|
||||
// It's not a hypothetical, it bit me while implementing the position hint functionality.
|
||||
let position_hints = with_constraint_data::<D, _, _>(surface, |data| {
|
||||
let data = data.unwrap();
|
||||
for constraint in data.constraints.values_mut() {
|
||||
constraint.commit();
|
||||
}
|
||||
})
|
||||
data.constraints
|
||||
.iter_mut()
|
||||
.filter_map(|(pointer, constraint)| constraint.commit().map(|hint| (pointer.clone(), hint)))
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
for (pointer, hint) in position_hints {
|
||||
state.cursor_position_hint(surface, &pointer, hint);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get `PointerConstraintData` associated with a surface, if any.
|
||||
|
@ -272,7 +304,7 @@ fn with_constraint_data<
|
|||
}
|
||||
|
||||
/// Add constraint for surface, or raise protocol error if one exists
|
||||
fn add_constraint<D: SeatHandler + 'static>(
|
||||
fn add_constraint<D: SeatHandler + PointerConstraintsHandler + 'static>(
|
||||
pointer_constraints: &ZwpPointerConstraintsV1,
|
||||
surface: &WlSurface,
|
||||
pointer: &PointerHandle<D>,
|
||||
|
|
Loading…
Reference in a new issue