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")]
pub mod dummy;
#[cfg(feature = "wlcs")]
pub mod wlcs;
pub mod udev;
pub mod winit;
#[cfg(feature = "wlcs")]
pub mod wlcs;
pub enum Backend {
/// The compositor is running in a Winit window

View file

@ -563,14 +563,14 @@ impl State {
error!("gRPC server error: {err}");
}
}));
},
}
None => {
self.grpc_server_join_handle = Some(tokio::spawn(async move {
if let Err(err) = grpc_server.serve_with_incoming(uds_stream).await {
error!("gRPC server error: {err}");
}
}));
},
}
// 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
// | 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;
use std::{
@ -47,23 +48,32 @@ pub enum WlcsEvent {
surface_id: u32,
location: Point<i32, Logical>,
},
PointerMove {
NewPointer {
device_id: u32,
},
PointerMoveRelative {
device_id: u32,
delta: Point<f64, Logical>,
},
PointerMoveAbsolute {
device_id: u32,
position: Point<f64, Logical>,
absolute: bool,
},
PointerButton {
device_id: u32,
button_id: i32,
pressed: bool,
},
NewTouch {
device_id: u32,
},
TouchDown {
device_id: u32,
location: Point<f64, Logical>,
position: Point<f64, Logical>,
},
TouchMove {
device_id: u32,
location: Point<f64, Logical>,
position: Point<f64, Logical>,
},
TouchUp {
device_id: u32,
@ -88,12 +98,18 @@ struct PinnacleHandle {
}
static SUPPORTED_EXTENSIONS: &[WlcsExtensionDescriptor] = extension_list!(
// ("wl_compositor", 4),
// ("wl_subcompositor", 1),
// ("wl_data_device_manager", 3),
// ("wl_seat", 7),
// ("wl_output", 4),
// ("xdg_wm_base", 3),
// Skip reasons:
// 5 Missing extension: gtk_primary_selection_device_manager>= 1
// 1 Missing extension: wlcs_non_existent_extension>= 1
// 89 Missing extension: wl_shell>= 2
// 1 Missing extension: xdg_not_really_an_extension>= 1
// 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 {
@ -218,20 +234,18 @@ struct PointerHandle {
impl Pointer for PointerHandle {
fn move_absolute(&mut self, x: wl_fixed_t, y: wl_fixed_t) {
self.sender
.send(WlcsEvent::PointerMove {
.send(WlcsEvent::PointerMoveAbsolute {
device_id: self.device_id,
position: (wl_fixed_to_double(x), wl_fixed_to_double(y)).into(),
absolute: true,
})
.expect("failed to send move_absolute");
}
fn move_relative(&mut self, dx: wl_fixed_t, dy: wl_fixed_t) {
self.sender
.send(WlcsEvent::PointerMove {
.send(WlcsEvent::PointerMoveRelative {
device_id: self.device_id,
position: (wl_fixed_to_double(dx), wl_fixed_to_double(dy)).into(),
absolute: false,
delta: (wl_fixed_to_double(dx), wl_fixed_to_double(dy)).into(),
})
.expect("failed to send move_relative");
}
@ -267,7 +281,7 @@ impl Touch for TouchHandle {
self.sender
.send(WlcsEvent::TouchDown {
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");
}
@ -276,7 +290,7 @@ impl Touch for TouchHandle {
self.sender
.send(WlcsEvent::TouchMove {
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");
}

View file

@ -2,22 +2,24 @@ use std::{sync::Arc, time::Duration};
use pinnacle::{
backend::dummy::setup_dummy,
focus::{keyboard::KeyboardFocusTarget, pointer::PointerFocusTarget},
state::{ClientState, State},
};
use smithay::{
backend::input::ButtonState,
input::pointer::{ButtonEvent, MotionEvent, RelativeMotionEvent},
backend::input::{ButtonState, DeviceCapability, InputEvent},
reexports::{
calloop::channel::{Channel, Event},
wayland_server::Resource,
},
utils::SERIAL_COUNTER,
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>) {
let config_path =
@ -95,88 +97,87 @@ fn handle_event(event: WlcsEvent, state: &mut State) {
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 };
let under = state
.space
.element_under(location)
.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,
WlcsEvent::NewPointer { device_id } => {
state.process_input_event(InputEvent::<WlcsInputBackend>::DeviceAdded {
device: WlcsDevice {
device_id,
capability: DeviceCapability::Pointer,
},
);
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 {
device_id: _,
device_id,
button_id,
pressed,
} => {
let serial = SERIAL_COUNTER.next_serial();
let ptr = state.seat.get_pointer().unwrap();
if !ptr.is_grabbed() {
let ptr_location = ptr.current_location();
let under = state
.space
.element_under(ptr_location)
.map(|(w, _)| w.clone());
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
},
} => state.process_input_event(
WlcsPointerButtonEvent {
device_id,
time: Duration::from(state.clock.now()).as_millis() as u64,
button_code: 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::TouchMove { .. } => warn!("TouchMove"),
WlcsEvent::TouchUp { .. } => warn!("TouchUp"),
WlcsEvent::TouchDown {
device_id,
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(),
),
}
}