Merge pull request #83 from Smithay/feature/wl_seat_v5

Upgrade to wl_seat version 5
This commit is contained in:
Victor Brekenfeld 2018-03-23 19:20:54 +01:00 committed by GitHub
commit c36f4c43ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 259 additions and 127 deletions

View File

@ -34,8 +34,7 @@ use smithay::backend::graphics::egl::EGLGraphicsBackend;
use smithay::backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions, Format}; use smithay::backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions, Format};
use smithay::backend::input::{self, Event, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, use smithay::backend::input::{self, Event, InputBackend, InputHandler, KeyState, KeyboardKeyEvent,
PointerAxisEvent, PointerButtonEvent}; PointerAxisEvent, PointerButtonEvent};
use smithay::backend::libinput::{libinput_bind, LibinputInputBackend, LibinputSessionInterface, use smithay::backend::libinput::{libinput_bind, LibinputInputBackend, LibinputSessionInterface};
PointerAxisEvent as LibinputPointerAxisEvent};
use smithay::backend::session::{Session, SessionNotifier}; use smithay::backend::session::{Session, SessionNotifier};
use smithay::backend::session::auto::{auto_session_bind, AutoSession}; use smithay::backend::session::auto::{auto_session_bind, AutoSession};
use smithay::backend::udev::{primary_gpu, udev_backend_bind, SessionFdDrmDevice, UdevBackend, UdevHandler}; use smithay::backend::udev::{primary_gpu, udev_backend_bind, SessionFdDrmDevice, UdevBackend, UdevHandler};
@ -187,13 +186,63 @@ impl InputHandler<LibinputInputBackend> for LibinputInputHandler {
self.pointer.button(button, state, serial, evt.time()); self.pointer.button(button, state, serial, evt.time());
} }
fn on_pointer_axis( fn on_pointer_axis(
&mut self, _evlh: &mut EventLoopHandle, _: &input::Seat, evt: LibinputPointerAxisEvent &mut self, _evlh: &mut EventLoopHandle, _: &input::Seat, evt: event::pointer::PointerAxisEvent
) { ) {
let axis = match evt.axis() { let source = match evt.source() {
input::Axis::Vertical => wayland_server::protocol::wl_pointer::Axis::VerticalScroll, input::AxisSource::Continuous => wayland_server::protocol::wl_pointer::AxisSource::Continuous,
input::Axis::Horizontal => wayland_server::protocol::wl_pointer::Axis::HorizontalScroll, input::AxisSource::Finger => wayland_server::protocol::wl_pointer::AxisSource::Finger,
input::AxisSource::Wheel | input::AxisSource::WheelTilt => {
wayland_server::protocol::wl_pointer::AxisSource::Wheel
}
}; };
self.pointer.axis(axis, evt.amount(), evt.time()); let horizontal_amount = evt.amount(&input::Axis::Horizontal)
.unwrap_or_else(|| evt.amount_discrete(&input::Axis::Horizontal).unwrap() * 3.0);
let vertical_amount = evt.amount(&input::Axis::Vertical)
.unwrap_or_else(|| evt.amount_discrete(&input::Axis::Vertical).unwrap() * 3.0);
let horizontal_amount_discrete = evt.amount_discrete(&input::Axis::Horizontal);
let vertical_amount_discrete = evt.amount_discrete(&input::Axis::Vertical);
{
let mut event = self.pointer.axis();
event.source(source);
if horizontal_amount != 0.0 {
event.value(
wayland_server::protocol::wl_pointer::Axis::HorizontalScroll,
horizontal_amount,
evt.time(),
);
if let Some(discrete) = horizontal_amount_discrete {
event.discrete(
wayland_server::protocol::wl_pointer::Axis::HorizontalScroll,
discrete as i32,
);
}
} else if source == wayland_server::protocol::wl_pointer::AxisSource::Finger {
event.stop(
wayland_server::protocol::wl_pointer::Axis::HorizontalScroll,
evt.time(),
);
}
if vertical_amount != 0.0 {
event.value(
wayland_server::protocol::wl_pointer::Axis::VerticalScroll,
vertical_amount,
evt.time(),
);
if let Some(discrete) = vertical_amount_discrete {
event.discrete(
wayland_server::protocol::wl_pointer::Axis::VerticalScroll,
discrete as i32,
);
}
} else if source == wayland_server::protocol::wl_pointer::AxisSource::Finger {
event.stop(
wayland_server::protocol::wl_pointer::Axis::VerticalScroll,
evt.time(),
);
}
event.done();
}
} }
fn on_touch_down( fn on_touch_down(
&mut self, _evlh: &mut EventLoopHandle, _: &input::Seat, _: event::touch::TouchDownEvent &mut self, _evlh: &mut EventLoopHandle, _: &input::Seat, _: event::touch::TouchDownEvent

View File

@ -108,11 +108,49 @@ impl InputHandler<winit::WinitInputBackend> for WinitInputHandler {
fn on_pointer_axis( fn on_pointer_axis(
&mut self, _evlh: &mut EventLoopHandle, _: &input::Seat, evt: winit::WinitMouseWheelEvent &mut self, _evlh: &mut EventLoopHandle, _: &input::Seat, evt: winit::WinitMouseWheelEvent
) { ) {
let axis = match evt.axis() { let source = match evt.source() {
input::Axis::Vertical => wayland_server::protocol::wl_pointer::Axis::VerticalScroll, input::AxisSource::Continuous => wayland_server::protocol::wl_pointer::AxisSource::Continuous,
input::Axis::Horizontal => wayland_server::protocol::wl_pointer::Axis::HorizontalScroll, input::AxisSource::Wheel => wayland_server::protocol::wl_pointer::AxisSource::Wheel,
_ => unreachable!(), //winit does not have more specific sources
}; };
self.pointer.axis(axis, evt.amount(), evt.time()); let horizontal_amount = evt.amount(&input::Axis::Horizontal)
.unwrap_or_else(|| evt.amount_discrete(&input::Axis::Horizontal).unwrap() * 3.0);
let vertical_amount = evt.amount(&input::Axis::Vertical)
.unwrap_or_else(|| evt.amount_discrete(&input::Axis::Vertical).unwrap() * 3.0);
let horizontal_amount_discrete = evt.amount_discrete(&input::Axis::Horizontal);
let vertical_amount_discrete = evt.amount_discrete(&input::Axis::Vertical);
{
let mut event = self.pointer.axis();
event.source(source);
if horizontal_amount != 0.0 {
event.value(
wayland_server::protocol::wl_pointer::Axis::HorizontalScroll,
horizontal_amount,
evt.time(),
);
if let Some(discrete) = horizontal_amount_discrete {
event.discrete(
wayland_server::protocol::wl_pointer::Axis::HorizontalScroll,
discrete as i32,
);
}
}
if vertical_amount != 0.0 {
event.value(
wayland_server::protocol::wl_pointer::Axis::VerticalScroll,
vertical_amount,
evt.time(),
);
if let Some(discrete) = vertical_amount_discrete {
event.discrete(
wayland_server::protocol::wl_pointer::Axis::VerticalScroll,
discrete as i32,
);
}
}
event.done();
}
} }
fn on_touch_down( fn on_touch_down(
&mut self, _evlh: &mut EventLoopHandle, _: &input::Seat, _: winit::WinitTouchStartedEvent &mut self, _evlh: &mut EventLoopHandle, _: &input::Seat, _: winit::WinitTouchStartedEvent

View File

@ -214,26 +214,32 @@ pub enum AxisSource {
/// Trait for pointer events generated by scrolling on an axis. /// Trait for pointer events generated by scrolling on an axis.
pub trait PointerAxisEvent: Event { pub trait PointerAxisEvent: Event {
/// `Axis` this event was generated for. /// Amount of scrolling in pixels on the given `Axis`.
fn axis(&self) -> Axis; ///
/// Source of the scroll event. Important for interpretation of `amount`. /// Garanteed to be `Some` when source returns either `AxisSource::Finger` or `AxisSource::Continuous`.
fn amount(&self, axis: &Axis) -> Option<f64>;
/// Amount of scrolling in discrete steps on the given `Axis`.
///
/// Garanteed to be `Some` when source returns either `AxisSource::Wheel` or `AxisSource::WheelTilt`.
fn amount_discrete(&self, axis: &Axis) -> Option<f64>;
/// Source of the scroll event.
fn source(&self) -> AxisSource; fn source(&self) -> AxisSource;
/// Amount of scrolling on the given `Axis`. See `source` for interpretation.
fn amount(&self) -> f64;
} }
impl PointerAxisEvent for UnusedEvent { impl PointerAxisEvent for UnusedEvent {
fn axis(&self) -> Axis { fn amount(&self, _axis: &Axis) -> Option<f64> {
match *self {}
}
fn amount_discrete(&self, _axis: &Axis) -> Option<f64> {
match *self {} match *self {}
} }
fn source(&self) -> AxisSource { fn source(&self) -> AxisSource {
match *self {} match *self {}
} }
fn amount(&self) -> f64 {
match *self {}
}
} }
/// Trait for pointer events generated by relative device movement. /// Trait for pointer events generated by relative device movement.

View File

@ -1,6 +1,7 @@
//! Implementation of input backend trait for types provided by `libinput` //! Implementation of input backend trait for types provided by `libinput`
use backend::input as backend; use backend::input as backend;
use backend::input::Axis;
#[cfg(feature = "backend_session")] #[cfg(feature = "backend_session")]
use backend::session::{AsErrno, Session, SessionObserver}; use backend::session::{AsErrno, Session, SessionObserver};
use input as libinput; use input as libinput;
@ -10,7 +11,6 @@ use std::hash::{Hash, Hasher};
use std::io::Error as IoError; use std::io::Error as IoError;
use std::os::unix::io::RawFd; use std::os::unix::io::RawFd;
use std::path::Path; use std::path::Path;
use std::rc::Rc;
use wayland_server::EventLoopHandle; use wayland_server::EventLoopHandle;
use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest}; use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest};
@ -73,35 +73,23 @@ impl backend::KeyboardKeyEvent for event::keyboard::KeyboardKeyEvent {
} }
} }
/// Wrapper for libinput pointer axis events to implement `backend::input::PointerAxisEvent` impl<'a> backend::Event for event::pointer::PointerAxisEvent {
pub struct PointerAxisEvent {
axis: event::pointer::Axis,
event: Rc<event::pointer::PointerAxisEvent>,
}
impl<'a> backend::Event for PointerAxisEvent {
fn time(&self) -> u32 { fn time(&self) -> u32 {
use input::event::pointer::PointerEventTrait; event::pointer::PointerEventTrait::time(self)
self.event.time()
} }
} }
impl<'a> backend::PointerAxisEvent for PointerAxisEvent { impl backend::PointerAxisEvent for event::pointer::PointerAxisEvent {
fn axis(&self) -> backend::Axis { fn amount(&self, axis: &Axis) -> Option<f64> {
self.axis.into() Some(self.axis_value((*axis).into()))
}
fn amount_discrete(&self, axis: &Axis) -> Option<f64> {
self.axis_value_discrete((*axis).into())
} }
fn source(&self) -> backend::AxisSource { fn source(&self) -> backend::AxisSource {
self.event.axis_source().into() self.axis_source().into()
}
fn amount(&self) -> f64 {
match self.source() {
backend::AxisSource::Finger | backend::AxisSource::Continuous => self.event.axis_value(self.axis),
backend::AxisSource::Wheel | backend::AxisSource::WheelTilt => {
self.event.axis_value_discrete(self.axis).unwrap()
}
}
} }
} }
@ -258,7 +246,7 @@ impl backend::InputBackend for LibinputInputBackend {
type EventError = IoError; type EventError = IoError;
type KeyboardKeyEvent = event::keyboard::KeyboardKeyEvent; type KeyboardKeyEvent = event::keyboard::KeyboardKeyEvent;
type PointerAxisEvent = PointerAxisEvent; type PointerAxisEvent = event::pointer::PointerAxisEvent;
type PointerButtonEvent = event::pointer::PointerButtonEvent; type PointerButtonEvent = event::pointer::PointerButtonEvent;
type PointerMotionEvent = event::pointer::PointerMotionEvent; type PointerMotionEvent = event::pointer::PointerMotionEvent;
type PointerMotionAbsoluteEvent = event::pointer::PointerMotionAbsoluteEvent; type PointerMotionAbsoluteEvent = event::pointer::PointerMotionAbsoluteEvent;
@ -492,37 +480,8 @@ impl backend::InputBackend for LibinputInputBackend {
handler.on_pointer_move_absolute(evlh, seat, motion_abs_event); handler.on_pointer_move_absolute(evlh, seat, motion_abs_event);
} }
PointerEvent::Axis(axis_event) => { PointerEvent::Axis(axis_event) => {
let rc_axis_event = Rc::new(axis_event); trace!(self.logger, "Calling on_pointer_axis with {:?}", axis_event);
if rc_axis_event.has_axis(Axis::Vertical) { handler.on_pointer_axis(evlh, seat, axis_event);
trace!(
self.logger,
"Calling on_pointer_axis for Axis::Vertical with {:?}",
*rc_axis_event
);
handler.on_pointer_axis(
evlh,
seat,
self::PointerAxisEvent {
axis: Axis::Vertical,
event: rc_axis_event.clone(),
},
);
}
if rc_axis_event.has_axis(Axis::Horizontal) {
trace!(
self.logger,
"Calling on_pointer_axis for Axis::Horizontal with {:?}",
*rc_axis_event
);
handler.on_pointer_axis(
evlh,
seat,
self::PointerAxisEvent {
axis: Axis::Horizontal,
event: rc_axis_event.clone(),
},
);
}
} }
PointerEvent::Button(button_event) => { PointerEvent::Button(button_event) => {
trace!( trace!(
@ -564,6 +523,15 @@ impl From<event::pointer::Axis> for backend::Axis {
} }
} }
impl From<backend::Axis> for event::pointer::Axis {
fn from(axis: backend::Axis) -> Self {
match axis {
backend::Axis::Vertical => event::pointer::Axis::Vertical,
backend::Axis::Horizontal => event::pointer::Axis::Horizontal,
}
}
}
impl From<event::pointer::AxisSource> for backend::AxisSource { impl From<event::pointer::AxisSource> for backend::AxisSource {
fn from(libinput: event::pointer::AxisSource) -> Self { fn from(libinput: event::pointer::AxisSource) -> Self {
match libinput { match libinput {

View File

@ -388,7 +388,6 @@ impl PointerMotionAbsoluteEvent for WinitMouseMovedEvent {
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
/// Winit-Backend internal event wrapping winit's types into a `PointerAxisEvent` /// Winit-Backend internal event wrapping winit's types into a `PointerAxisEvent`
pub struct WinitMouseWheelEvent { pub struct WinitMouseWheelEvent {
axis: Axis,
time: u32, time: u32,
delta: MouseScrollDelta, delta: MouseScrollDelta,
} }
@ -400,10 +399,6 @@ impl BackendEvent for WinitMouseWheelEvent {
} }
impl PointerAxisEvent for WinitMouseWheelEvent { impl PointerAxisEvent for WinitMouseWheelEvent {
fn axis(&self) -> Axis {
self.axis
}
fn source(&self) -> AxisSource { fn source(&self) -> AxisSource {
match self.delta { match self.delta {
MouseScrollDelta::LineDelta(_, _) => AxisSource::Wheel, MouseScrollDelta::LineDelta(_, _) => AxisSource::Wheel,
@ -411,12 +406,19 @@ impl PointerAxisEvent for WinitMouseWheelEvent {
} }
} }
fn amount(&self) -> f64 { fn amount(&self, axis: &Axis) -> Option<f64> {
match (self.axis, self.delta) { match (axis, self.delta) {
(Axis::Horizontal, MouseScrollDelta::LineDelta(x, _)) (&Axis::Horizontal, MouseScrollDelta::PixelDelta(x, _)) => Some(x as f64),
| (Axis::Horizontal, MouseScrollDelta::PixelDelta(x, _)) => x as f64, (&Axis::Vertical, MouseScrollDelta::PixelDelta(_, y)) => Some(y as f64),
(Axis::Vertical, MouseScrollDelta::LineDelta(_, y)) (_, MouseScrollDelta::LineDelta(_, _)) => None,
| (Axis::Vertical, MouseScrollDelta::PixelDelta(_, y)) => y as f64, }
}
fn amount_discrete(&self, axis: &Axis) -> Option<f64> {
match (axis, self.delta) {
(&Axis::Horizontal, MouseScrollDelta::LineDelta(x, _)) => Some(x as f64),
(&Axis::Vertical, MouseScrollDelta::LineDelta(_, y)) => Some(y as f64),
(_, MouseScrollDelta::PixelDelta(_, _)) => None,
} }
} }
} }
@ -764,36 +766,11 @@ impl InputBackend for WinitInputBackend {
}, },
) )
} }
(WindowEvent::MouseWheel { delta, .. }, Some(handler), _) => match delta { (WindowEvent::MouseWheel { delta, .. }, Some(handler), _) => {
MouseScrollDelta::LineDelta(x, y) | MouseScrollDelta::PixelDelta(x, y) => { let event = WinitMouseWheelEvent { time, delta };
if x != 0.0 { trace!(logger, "Calling on_pointer_axis with {:?}", delta);
let event = WinitMouseWheelEvent { handler.on_pointer_axis(evlh, seat, event);
axis: Axis::Horizontal, }
time,
delta: delta,
};
trace!(
logger,
"Calling on_pointer_axis for Axis::Horizontal with {:?}",
x
);
handler.on_pointer_axis(evlh, seat, event);
}
if y != 0.0 {
let event = WinitMouseWheelEvent {
axis: Axis::Vertical,
time,
delta: delta,
};
trace!(
logger,
"Calling on_pointer_axis for Axis::Vertical with {:?}",
y
);
handler.on_pointer_axis(evlh, seat, event);
}
}
},
(WindowEvent::MouseInput { state, button, .. }, Some(handler), _) => { (WindowEvent::MouseInput { state, button, .. }, Some(handler), _) => {
trace!( trace!(
logger, logger,

View File

@ -58,7 +58,7 @@ mod keyboard;
mod pointer; mod pointer;
pub use self::keyboard::{Error as KeyboardError, KeyboardHandle, ModifiersState}; pub use self::keyboard::{Error as KeyboardError, KeyboardHandle, ModifiersState};
pub use self::pointer::PointerHandle; pub use self::pointer::{PointerAxisHandle, PointerHandle};
use wayland_server::{Client, EventLoopHandle, Global, Liveness, Resource, StateToken}; use wayland_server::{Client, EventLoopHandle, Global, Liveness, Resource, StateToken};
use wayland_server::protocol::{wl_keyboard, wl_pointer, wl_seat}; use wayland_server::protocol::{wl_keyboard, wl_pointer, wl_seat};
@ -102,8 +102,7 @@ impl Seat {
known_seats: Vec::new(), known_seats: Vec::new(),
}; };
let token = evlh.state().insert(seat); let token = evlh.state().insert(seat);
// TODO: support version 5 (axis) let global = evlh.register_global(5, seat_global_bind, token.clone());
let global = evlh.register_global(4, seat_global_bind, token.clone());
(token, global) (token, global)
} }

View File

@ -1,4 +1,4 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex, MutexGuard};
use wayland_server::{Liveness, Resource}; use wayland_server::{Liveness, Resource};
use wayland_server::protocol::{wl_pointer, wl_surface}; use wayland_server::protocol::{wl_pointer, wl_surface};
@ -73,6 +73,9 @@ impl PointerHandle {
if leave { if leave {
guard.with_focused_pointers(|pointer, surface| { guard.with_focused_pointers(|pointer, surface| {
pointer.leave(serial, surface); pointer.leave(serial, surface);
if pointer.version() >= 5 {
pointer.frame();
}
}); });
guard.focus = None; guard.focus = None;
} }
@ -83,11 +86,17 @@ impl PointerHandle {
guard.focus = surface.clone(); guard.focus = surface.clone();
guard.with_focused_pointers(|pointer, surface| { guard.with_focused_pointers(|pointer, surface| {
pointer.enter(serial, surface, x, y); pointer.enter(serial, surface, x, y);
if pointer.version() >= 5 {
pointer.frame();
}
}) })
} 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, _| { guard.with_focused_pointers(|pointer, _| {
pointer.motion(time, x, y); pointer.motion(time, x, y);
if pointer.version() >= 5 {
pointer.frame();
}
}) })
} }
} }
@ -101,15 +110,20 @@ impl PointerHandle {
let guard = self.inner.lock().unwrap(); let guard = self.inner.lock().unwrap();
guard.with_focused_pointers(|pointer, _| { guard.with_focused_pointers(|pointer, _| {
pointer.button(serial, time, button, state); pointer.button(serial, time, button, state);
if pointer.version() >= 5 {
pointer.frame();
}
}) })
} }
/// send axis events /// Start an axis frame
pub fn axis(&self, axis: wl_pointer::Axis, value: f64, time: u32) { ///
let guard = self.inner.lock().unwrap(); /// A single frame will group multiple scroll events as if they happended in the same instance.
guard.with_focused_pointers(|pointer, _| { /// Dropping the returned `PointerAxisHandle` will group the events together.
pointer.axis(time, axis, value); pub fn axis<'a>(&'a self) -> PointerAxisHandle<'a> {
}) PointerAxisHandle {
inner: self.inner.lock().unwrap(),
}
} }
pub(crate) fn cleanup_old_pointers(&self) { pub(crate) fn cleanup_old_pointers(&self) {
@ -120,6 +134,87 @@ impl PointerHandle {
} }
} }
/// A frame of pointer axis events.
///
/// Can be used with the builder pattern, e.g.:
/// ```ignore
/// pointer.axis()
/// .source(AxisSource::Wheel)
/// .discrete(Axis::Vertical, 6)
/// .value(Axis::Vertical, 30, time)
/// .stop(Axis::Vertical);
/// ```
pub struct PointerAxisHandle<'a> {
inner: MutexGuard<'a, PointerInternal>,
}
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.
/// Only one source event is allowed per frame.
///
/// 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: wl_pointer::AxisSource) -> &mut Self {
self.inner.with_focused_pointers(|pointer, _| {
if pointer.version() >= 5 {
pointer.axis_source(source);
}
});
self
}
/// Specify discrete scrolling steps additionally to the computed value.
///
/// 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: wl_pointer::Axis, steps: i32) -> &mut Self {
self.inner.with_focused_pointers(|pointer, _| {
if pointer.version() >= 5 {
pointer.axis_discrete(axis, 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: wl_pointer::Axis, value: f64, time: u32) -> &mut Self {
self.inner.with_focused_pointers(|pointer, _| {
pointer.axis(time, axis, value);
});
self
}
/// Notification of stop of scrolling on an axis.
///
/// This event is required for sources of the `AxisSource::Finger` type
/// and otherwise optional.
pub fn stop(&mut self, axis: wl_pointer::Axis, time: u32) -> &mut Self {
self.inner.with_focused_pointers(|pointer, _| {
if pointer.version() >= 5 {
pointer.axis_stop(time, axis);
}
});
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.frame();
}
})
}
}
pub(crate) fn create_pointer_handler() -> PointerHandle { pub(crate) fn create_pointer_handler() -> PointerHandle {
PointerHandle { PointerHandle {
inner: Arc::new(Mutex::new(PointerInternal::new())), inner: Arc::new(Mutex::new(PointerInternal::new())),