Perform wlcs interactions using an InputBackend

This commit is contained in:
Leon Vack 2024-04-17 20:59:19 +02:00
parent fb8b6e166c
commit abb21d9924
5 changed files with 449 additions and 102 deletions

View file

@ -43,10 +43,10 @@ use self::{udev::Udev, winit::Winit};
#[cfg(feature = "testing")] #[cfg(feature = "testing")]
pub mod dummy; pub mod dummy;
#[cfg(feature = "wlcs")]
pub mod wlcs;
pub mod udev; pub mod udev;
pub mod winit; pub mod winit;
#[cfg(feature = "wlcs")]
pub mod wlcs;
pub enum Backend { pub enum Backend {
/// The compositor is running in a Winit window /// The compositor is running in a Winit window

View file

@ -563,14 +563,14 @@ impl State {
error!("gRPC server error: {err}"); error!("gRPC server error: {err}");
} }
})); }));
}, }
None => { None => {
self.grpc_server_join_handle = Some(tokio::spawn(async move { self.grpc_server_join_handle = Some(tokio::spawn(async move {
if let Err(err) = grpc_server.serve_with_incoming(uds_stream).await { if let Err(err) = grpc_server.serve_with_incoming(uds_stream).await {
error!("gRPC server error: {err}"); error!("gRPC server error: {err}");
} }
})); }));
}, }
// FIXME: Not really high priority but if you somehow reload the config really, REALLY // FIXME: Not really high priority but if you somehow reload the config really, REALLY
// | fast at startup then I think there's a chance that the gRPC server // | fast at startup then I think there's a chance that the gRPC server
// | could get started twice. // | could get started twice.

View file

@ -0,0 +1,332 @@
use core::hash::Hash;
use smithay::{
backend::input::{
AbsolutePositionEvent, ButtonState, Device, DeviceCapability, Event, InputBackend,
InputEvent, PointerButtonEvent, PointerMotionAbsoluteEvent, PointerMotionEvent,
TouchDownEvent, TouchEvent, TouchMotionEvent, TouchSlot, TouchUpEvent, UnusedEvent,
},
utils::{Logical, Point},
};
pub struct WlcsInputBackend {}
impl InputBackend for WlcsInputBackend {
type Device = WlcsDevice;
type KeyboardKeyEvent = UnusedEvent;
type PointerAxisEvent = UnusedEvent;
type PointerButtonEvent = WlcsPointerButtonEvent;
type PointerMotionEvent = WlcsPointerMotionEvent;
type PointerMotionAbsoluteEvent = WlcsPointerMotionAbsoluteEvent;
type GestureSwipeBeginEvent = UnusedEvent;
type GestureSwipeUpdateEvent = UnusedEvent;
type GestureSwipeEndEvent = UnusedEvent;
type GesturePinchBeginEvent = UnusedEvent;
type GesturePinchUpdateEvent = UnusedEvent;
type GesturePinchEndEvent = UnusedEvent;
type GestureHoldBeginEvent = UnusedEvent;
type GestureHoldEndEvent = UnusedEvent;
type TouchDownEvent = WlcsTouchDownEvent;
type TouchUpEvent = WlcsTouchUpEvent;
type TouchMotionEvent = WlcsTouchMotionEvent;
type TouchCancelEvent = UnusedEvent;
type TouchFrameEvent = UnusedEvent;
type TabletToolAxisEvent = UnusedEvent;
type TabletToolProximityEvent = UnusedEvent;
type TabletToolTipEvent = UnusedEvent;
type TabletToolButtonEvent = UnusedEvent;
type SwitchToggleEvent = UnusedEvent;
type SpecialEvent = ();
}
#[derive(PartialEq, Eq)]
pub struct WlcsDevice {
pub device_id: u32,
pub capability: DeviceCapability,
}
impl Hash for WlcsDevice {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.device_id.hash(state);
}
}
impl Device for WlcsDevice {
fn id(&self) -> String {
format!("{}", self.device_id).into()
}
fn name(&self) -> String {
format!("wlcs-device-{}", self.device_id).into()
}
fn has_capability(&self, capability: DeviceCapability) -> bool {
self.capability == capability
}
fn usb_id(&self) -> Option<(u32, u32)> {
None
}
fn syspath(&self) -> Option<std::path::PathBuf> {
None
}
}
pub struct WlcsPointerButtonEvent {
pub device_id: u32,
pub time: u64,
pub button_code: u32,
pub state: ButtonState,
}
impl Into<InputEvent<WlcsInputBackend>> for WlcsPointerButtonEvent {
fn into(self) -> InputEvent<WlcsInputBackend> {
InputEvent::<WlcsInputBackend>::PointerButton { event: self }
}
}
impl Event<WlcsInputBackend> for WlcsPointerButtonEvent {
fn time(&self) -> u64 {
self.time
}
fn device(&self) -> <WlcsInputBackend as InputBackend>::Device {
WlcsDevice {
device_id: self.device_id,
capability: DeviceCapability::Pointer,
}
}
}
impl PointerButtonEvent<WlcsInputBackend> for WlcsPointerButtonEvent {
fn button_code(&self) -> u32 {
self.button_code
}
fn state(&self) -> ButtonState {
self.state
}
}
pub struct WlcsPointerMotionEvent {
pub device_id: u32,
pub time: u64,
pub delta: Point<f64, Logical>,
}
impl Into<InputEvent<WlcsInputBackend>> for WlcsPointerMotionEvent {
fn into(self) -> InputEvent<WlcsInputBackend> {
InputEvent::<WlcsInputBackend>::PointerMotion { event: self }
}
}
impl Event<WlcsInputBackend> for WlcsPointerMotionEvent {
fn time(&self) -> u64 {
self.time
}
fn device(&self) -> <WlcsInputBackend as InputBackend>::Device {
WlcsDevice {
device_id: self.device_id,
capability: DeviceCapability::Pointer,
}
}
}
impl PointerMotionEvent<WlcsInputBackend> for WlcsPointerMotionEvent {
fn delta_x(&self) -> f64 {
self.delta.x
}
fn delta_y(&self) -> f64 {
self.delta.y
}
fn delta_x_unaccel(&self) -> f64 {
self.delta_x()
}
fn delta_y_unaccel(&self) -> f64 {
self.delta_y()
}
}
pub struct WlcsPointerMotionAbsoluteEvent {
pub device_id: u32,
pub time: u64,
pub position: Point<f64, Logical>,
}
impl Into<InputEvent<WlcsInputBackend>> for WlcsPointerMotionAbsoluteEvent {
fn into(self) -> InputEvent<WlcsInputBackend> {
InputEvent::<WlcsInputBackend>::PointerMotionAbsolute { event: self }
}
}
impl Event<WlcsInputBackend> for WlcsPointerMotionAbsoluteEvent {
fn time(&self) -> u64 {
self.time
}
fn device(&self) -> <WlcsInputBackend as InputBackend>::Device {
WlcsDevice {
device_id: self.device_id,
capability: DeviceCapability::Pointer,
}
}
}
impl AbsolutePositionEvent<WlcsInputBackend> for WlcsPointerMotionAbsoluteEvent {
fn x(&self) -> f64 {
self.position.x
}
fn y(&self) -> f64 {
self.position.y
}
fn x_transformed(&self, _width: i32) -> f64 {
self.x()
}
fn y_transformed(&self, _height: i32) -> f64 {
self.y()
}
}
impl PointerMotionAbsoluteEvent<WlcsInputBackend> for WlcsPointerMotionAbsoluteEvent {}
pub struct WlcsTouchDownEvent {
pub device_id: u32,
pub time: u64,
pub position: Point<f64, Logical>,
}
impl Into<InputEvent<WlcsInputBackend>> for WlcsTouchDownEvent {
fn into(self) -> InputEvent<WlcsInputBackend> {
InputEvent::<WlcsInputBackend>::TouchDown { event: self }
}
}
impl Event<WlcsInputBackend> for WlcsTouchDownEvent {
fn time(&self) -> u64 {
self.time
}
fn device(&self) -> <WlcsInputBackend as InputBackend>::Device {
WlcsDevice {
device_id: self.device_id,
capability: DeviceCapability::Touch,
}
}
}
impl TouchEvent<WlcsInputBackend> for WlcsTouchDownEvent {
fn slot(&self) -> TouchSlot {
None.into()
}
}
impl AbsolutePositionEvent<WlcsInputBackend> for WlcsTouchDownEvent {
fn x(&self) -> f64 {
self.position.x
}
fn y(&self) -> f64 {
self.position.y
}
fn x_transformed(&self, _width: i32) -> f64 {
self.x()
}
fn y_transformed(&self, _height: i32) -> f64 {
self.y()
}
}
impl TouchDownEvent<WlcsInputBackend> for WlcsTouchDownEvent {}
pub struct WlcsTouchUpEvent {
pub device_id: u32,
pub time: u64,
}
impl Into<InputEvent<WlcsInputBackend>> for WlcsTouchUpEvent {
fn into(self) -> InputEvent<WlcsInputBackend> {
InputEvent::<WlcsInputBackend>::TouchUp { event: self }
}
}
impl Event<WlcsInputBackend> for WlcsTouchUpEvent {
fn time(&self) -> u64 {
self.time
}
fn device(&self) -> <WlcsInputBackend as InputBackend>::Device {
WlcsDevice {
device_id: self.device_id,
capability: DeviceCapability::Touch,
}
}
}
impl TouchEvent<WlcsInputBackend> for WlcsTouchUpEvent {
fn slot(&self) -> TouchSlot {
None.into()
}
}
impl TouchUpEvent<WlcsInputBackend> for WlcsTouchUpEvent {}
pub struct WlcsTouchMotionEvent {
pub device_id: u32,
pub time: u64,
pub position: Point<f64, Logical>,
}
impl Into<InputEvent<WlcsInputBackend>> for WlcsTouchMotionEvent {
fn into(self) -> InputEvent<WlcsInputBackend> {
InputEvent::<WlcsInputBackend>::TouchMotion { event: self }
}
}
impl Event<WlcsInputBackend> for WlcsTouchMotionEvent {
fn time(&self) -> u64 {
self.time
}
fn device(&self) -> <WlcsInputBackend as InputBackend>::Device {
WlcsDevice {
device_id: self.device_id,
capability: DeviceCapability::Touch,
}
}
}
impl TouchEvent<WlcsInputBackend> for WlcsTouchMotionEvent {
fn slot(&self) -> TouchSlot {
None.into()
}
}
impl AbsolutePositionEvent<WlcsInputBackend> for WlcsTouchMotionEvent {
fn x(&self) -> f64 {
self.position.x
}
fn y(&self) -> f64 {
self.position.y
}
fn x_transformed(&self, _width: i32) -> f64 {
self.x()
}
fn y_transformed(&self, _height: i32) -> f64 {
self.y()
}
}
impl TouchMotionEvent<WlcsInputBackend> for WlcsTouchMotionEvent {}

View file

@ -1,3 +1,4 @@
mod input_backend;
mod main_loop; mod main_loop;
use std::{ use std::{
@ -47,23 +48,32 @@ pub enum WlcsEvent {
surface_id: u32, surface_id: u32,
location: Point<i32, Logical>, location: Point<i32, Logical>,
}, },
PointerMove { NewPointer {
device_id: u32,
},
PointerMoveRelative {
device_id: u32,
delta: Point<f64, Logical>,
},
PointerMoveAbsolute {
device_id: u32, device_id: u32,
position: Point<f64, Logical>, position: Point<f64, Logical>,
absolute: bool,
}, },
PointerButton { PointerButton {
device_id: u32, device_id: u32,
button_id: i32, button_id: i32,
pressed: bool, pressed: bool,
}, },
NewTouch {
device_id: u32,
},
TouchDown { TouchDown {
device_id: u32, device_id: u32,
location: Point<f64, Logical>, position: Point<f64, Logical>,
}, },
TouchMove { TouchMove {
device_id: u32, device_id: u32,
location: Point<f64, Logical>, position: Point<f64, Logical>,
}, },
TouchUp { TouchUp {
device_id: u32, device_id: u32,
@ -88,12 +98,18 @@ struct PinnacleHandle {
} }
static SUPPORTED_EXTENSIONS: &[WlcsExtensionDescriptor] = extension_list!( static SUPPORTED_EXTENSIONS: &[WlcsExtensionDescriptor] = extension_list!(
// ("wl_compositor", 4), // Skip reasons:
// ("wl_subcompositor", 1), // 5 Missing extension: gtk_primary_selection_device_manager>= 1
// ("wl_data_device_manager", 3), // 1 Missing extension: wlcs_non_existent_extension>= 1
// ("wl_seat", 7), // 89 Missing extension: wl_shell>= 2
// ("wl_output", 4), // 1 Missing extension: xdg_not_really_an_extension>= 1
// ("xdg_wm_base", 3), // 30 Missing extension: zwlr_foreign_toplevel_manager_v1>= 1
// 12 Missing extension: zwlr_virtual_pointer_manager_v1>= 1
// 15 Missing extension: zwp_pointer_constraints_v1>= 1
// 3 Missing extension: zwp_relative_pointer_manager_v1>= 1
// 12 Missing extension: zwp_text_input_manager_v2>= 1
// 11 Missing extension: zwp_text_input_manager_v3>= 1
// 180 Missing extension: zxdg_shell_v6>= 1
); );
static DESCRIPTOR: WlcsIntegrationDescriptor = WlcsIntegrationDescriptor { static DESCRIPTOR: WlcsIntegrationDescriptor = WlcsIntegrationDescriptor {
@ -218,20 +234,18 @@ struct PointerHandle {
impl Pointer for PointerHandle { impl Pointer for PointerHandle {
fn move_absolute(&mut self, x: wl_fixed_t, y: wl_fixed_t) { fn move_absolute(&mut self, x: wl_fixed_t, y: wl_fixed_t) {
self.sender self.sender
.send(WlcsEvent::PointerMove { .send(WlcsEvent::PointerMoveAbsolute {
device_id: self.device_id, device_id: self.device_id,
position: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(), position: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(),
absolute: true,
}) })
.expect("failed to send move_absolute"); .expect("failed to send move_absolute");
} }
fn move_relative(&mut self, dx: wl_fixed_t, dy: wl_fixed_t) { fn move_relative(&mut self, dx: wl_fixed_t, dy: wl_fixed_t) {
self.sender self.sender
.send(WlcsEvent::PointerMove { .send(WlcsEvent::PointerMoveRelative {
device_id: self.device_id, device_id: self.device_id,
position: (wl_fixed_to_double(dx), wl_fixed_to_double(dy)).into(), delta: (wl_fixed_to_double(dx), wl_fixed_to_double(dy)).into(),
absolute: false,
}) })
.expect("failed to send move_relative"); .expect("failed to send move_relative");
} }
@ -267,7 +281,7 @@ impl Touch for TouchHandle {
self.sender self.sender
.send(WlcsEvent::TouchDown { .send(WlcsEvent::TouchDown {
device_id: self.device_id, device_id: self.device_id,
location: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(), position: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(),
}) })
.expect("failed to send touch_down"); .expect("failed to send touch_down");
} }
@ -276,7 +290,7 @@ impl Touch for TouchHandle {
self.sender self.sender
.send(WlcsEvent::TouchMove { .send(WlcsEvent::TouchMove {
device_id: self.device_id, device_id: self.device_id,
location: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(), position: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(),
}) })
.expect("failed to send touch_move"); .expect("failed to send touch_move");
} }

View file

@ -2,22 +2,24 @@ use std::{sync::Arc, time::Duration};
use pinnacle::{ use pinnacle::{
backend::dummy::setup_dummy, backend::dummy::setup_dummy,
focus::{keyboard::KeyboardFocusTarget, pointer::PointerFocusTarget},
state::{ClientState, State}, state::{ClientState, State},
}; };
use smithay::{ use smithay::{
backend::input::ButtonState, backend::input::{ButtonState, DeviceCapability, InputEvent},
input::pointer::{ButtonEvent, MotionEvent, RelativeMotionEvent},
reexports::{ reexports::{
calloop::channel::{Channel, Event}, calloop::channel::{Channel, Event},
wayland_server::Resource, wayland_server::Resource,
}, },
utils::SERIAL_COUNTER,
wayland::seat::WaylandFocus, wayland::seat::WaylandFocus,
}; };
use tracing::warn;
use crate::WlcsEvent; use crate::{
input_backend::{
WlcsDevice, WlcsInputBackend, WlcsPointerButtonEvent, WlcsPointerMotionAbsoluteEvent,
WlcsPointerMotionEvent, WlcsTouchDownEvent, WlcsTouchUpEvent,
},
WlcsEvent,
};
pub(crate) fn run(channel: Channel<WlcsEvent>) { pub(crate) fn run(channel: Channel<WlcsEvent>) {
let config_path = let config_path =
@ -95,88 +97,87 @@ fn handle_event(event: WlcsEvent, state: &mut State) {
state.space.map_element(toplevel.clone(), location, false); state.space.map_element(toplevel.clone(), location, false);
} }
} }
WlcsEvent::PointerMove {
device_id: _,
position,
absolute,
} => {
let serial = SERIAL_COUNTER.next_serial();
let ptr = state.seat.get_pointer().unwrap();
let ptr_location = ptr.current_location();
let location = if absolute { position } else { ptr_location + position }; WlcsEvent::NewPointer { device_id } => {
state.process_input_event(InputEvent::<WlcsInputBackend>::DeviceAdded {
let under = state device: WlcsDevice {
.space device_id,
.element_under(location) capability: DeviceCapability::Pointer,
.and_then(|(w, _)| w.wl_surface())
.map(|surf| (PointerFocusTarget::WlSurface(surf), location.to_i32_round()));
let time = Duration::from(state.clock.now()).as_millis() as u32;
ptr.motion(
state,
under.clone(),
&MotionEvent {
location,
serial,
time,
}, },
); })
if !absolute {
let utime = Duration::from(state.clock.now()).as_micros() as u64;
ptr.relative_motion(
state,
under,
&RelativeMotionEvent {
delta: position,
delta_unaccel: position,
utime,
},
)
}
ptr.frame(state);
} }
WlcsEvent::PointerMoveAbsolute {
device_id,
position,
} => state.process_input_event(
WlcsPointerMotionAbsoluteEvent {
device_id,
time: Duration::from(state.clock.now()).as_millis() as u64,
position,
}
.into(),
),
WlcsEvent::PointerMoveRelative { device_id, delta } => state.process_input_event(
WlcsPointerMotionEvent {
device_id,
time: Duration::from(state.clock.now()).as_millis() as u64,
delta,
}
.into(),
),
WlcsEvent::PointerButton { WlcsEvent::PointerButton {
device_id: _, device_id,
button_id, button_id,
pressed, pressed,
} => { } => state.process_input_event(
let serial = SERIAL_COUNTER.next_serial(); WlcsPointerButtonEvent {
let ptr = state.seat.get_pointer().unwrap(); device_id,
if !ptr.is_grabbed() { time: Duration::from(state.clock.now()).as_millis() as u64,
let ptr_location = ptr.current_location(); button_code: button_id as u32,
let under = state state: if pressed {
.space ButtonState::Pressed
.element_under(ptr_location) } else {
.map(|(w, _)| w.clone()); ButtonState::Released
if let Some(win) = &under {
state.space.raise_element(win, true);
}
state.seat.get_keyboard().unwrap().set_focus(
state,
under.map(|w| KeyboardFocusTarget::Window(w)),
serial,
);
}
let time = Duration::from(state.clock.now()).as_millis() as u32;
ptr.button(
state,
&ButtonEvent {
serial,
time,
button: button_id as u32,
state: if pressed {
ButtonState::Pressed
} else {
ButtonState::Released
},
}, },
); }
ptr.frame(state); .into(),
),
WlcsEvent::NewTouch { device_id } => {
state.process_input_event(InputEvent::<WlcsInputBackend>::DeviceAdded {
device: WlcsDevice {
device_id,
capability: DeviceCapability::Pointer,
},
})
} }
WlcsEvent::TouchDown { .. } => warn!("TouchDown"), WlcsEvent::TouchDown {
WlcsEvent::TouchMove { .. } => warn!("TouchMove"), device_id,
WlcsEvent::TouchUp { .. } => warn!("TouchUp"), position,
} => state.process_input_event(
WlcsTouchDownEvent {
device_id,
time: Duration::from(state.clock.now()).as_millis() as u64,
position,
}
.into(),
),
WlcsEvent::TouchMove {
device_id,
position,
} => state.process_input_event(
WlcsTouchDownEvent {
device_id,
time: Duration::from(state.clock.now()).as_millis() as u64,
position,
}
.into(),
),
WlcsEvent::TouchUp { device_id } => state.process_input_event(
WlcsTouchUpEvent {
device_id,
time: Duration::from(state.clock.now()).as_millis() as u64,
}
.into(),
),
} }
} }