parent
73ca9c91f1
commit
c77b66cc93
6 changed files with 925 additions and 66 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::server::{ObjectEvent, ObjectKey};
|
use crate::server::{ObjectEvent, ObjectKey};
|
||||||
use std::os::unix::net::UnixStream;
|
use std::os::unix::net::UnixStream;
|
||||||
|
use std::sync::{mpsc, Mutex, Once, OnceLock};
|
||||||
use wayland_client::protocol::{
|
use wayland_client::protocol::{
|
||||||
wl_buffer::WlBuffer, wl_callback::WlCallback, wl_compositor::WlCompositor,
|
wl_buffer::WlBuffer, wl_callback::WlCallback, wl_compositor::WlCompositor,
|
||||||
wl_keyboard::WlKeyboard, wl_output::WlOutput, wl_pointer::WlPointer, wl_region::WlRegion,
|
wl_keyboard::WlKeyboard, wl_output::WlOutput, wl_pointer::WlPointer, wl_region::WlRegion,
|
||||||
|
|
@ -7,7 +8,7 @@ use wayland_client::protocol::{
|
||||||
wl_surface::WlSurface, wl_touch::WlTouch,
|
wl_surface::WlSurface, wl_touch::WlTouch,
|
||||||
};
|
};
|
||||||
use wayland_client::{
|
use wayland_client::{
|
||||||
delegate_noop,
|
delegate_noop, event_created_child,
|
||||||
globals::{registry_queue_init, Global, GlobalList, GlobalListContents},
|
globals::{registry_queue_init, Global, GlobalList, GlobalListContents},
|
||||||
Connection, Dispatch, EventQueue, Proxy, QueueHandle,
|
Connection, Dispatch, EventQueue, Proxy, QueueHandle,
|
||||||
};
|
};
|
||||||
|
|
@ -27,6 +28,19 @@ use wayland_protocols::{
|
||||||
zwp_locked_pointer_v1::ZwpLockedPointerV1,
|
zwp_locked_pointer_v1::ZwpLockedPointerV1,
|
||||||
zwp_pointer_constraints_v1::ZwpPointerConstraintsV1,
|
zwp_pointer_constraints_v1::ZwpPointerConstraintsV1,
|
||||||
},
|
},
|
||||||
|
tablet::zv2::client::{
|
||||||
|
zwp_tablet_manager_v2::ZwpTabletManagerV2,
|
||||||
|
zwp_tablet_pad_group_v2::{ZwpTabletPadGroupV2, EVT_RING_OPCODE, EVT_STRIP_OPCODE},
|
||||||
|
zwp_tablet_pad_ring_v2::ZwpTabletPadRingV2,
|
||||||
|
zwp_tablet_pad_strip_v2::ZwpTabletPadStripV2,
|
||||||
|
zwp_tablet_pad_v2::{ZwpTabletPadV2, EVT_GROUP_OPCODE},
|
||||||
|
zwp_tablet_seat_v2::{
|
||||||
|
ZwpTabletSeatV2, EVT_PAD_ADDED_OPCODE, EVT_TABLET_ADDED_OPCODE,
|
||||||
|
EVT_TOOL_ADDED_OPCODE,
|
||||||
|
},
|
||||||
|
zwp_tablet_tool_v2::ZwpTabletToolV2,
|
||||||
|
zwp_tablet_v2::ZwpTabletV2,
|
||||||
|
},
|
||||||
viewporter::client::{wp_viewport::WpViewport, wp_viewporter::WpViewporter},
|
viewporter::client::{wp_viewport::WpViewport, wp_viewporter::WpViewporter},
|
||||||
},
|
},
|
||||||
xdg::{
|
xdg::{
|
||||||
|
|
@ -44,7 +58,8 @@ use wl_drm::client::wl_drm::WlDrm;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Globals {
|
pub struct Globals {
|
||||||
pub(crate) events: Vec<(ObjectKey, ObjectEvent)>,
|
events: Vec<(ObjectKey, ObjectEvent)>,
|
||||||
|
queued_events: Vec<mpsc::Receiver<(ObjectKey, ObjectEvent)>>,
|
||||||
pub new_globals: Vec<Global>,
|
pub new_globals: Vec<Global>,
|
||||||
pub selection: Option<wayland_client::protocol::wl_data_device::WlDataDevice>,
|
pub selection: Option<wayland_client::protocol::wl_data_device::WlDataDevice>,
|
||||||
pub selection_requests: Vec<(
|
pub selection_requests: Vec<(
|
||||||
|
|
@ -57,7 +72,7 @@ pub struct Globals {
|
||||||
pub type ClientQueueHandle = QueueHandle<Globals>;
|
pub type ClientQueueHandle = QueueHandle<Globals>;
|
||||||
|
|
||||||
pub struct ClientState {
|
pub struct ClientState {
|
||||||
pub connection: Connection,
|
_connection: Connection,
|
||||||
pub queue: EventQueue<Globals>,
|
pub queue: EventQueue<Globals>,
|
||||||
pub qh: ClientQueueHandle,
|
pub qh: ClientQueueHandle,
|
||||||
pub globals: Globals,
|
pub globals: Globals,
|
||||||
|
|
@ -77,13 +92,31 @@ impl ClientState {
|
||||||
let qh = queue.handle();
|
let qh = queue.handle();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
connection,
|
_connection: connection,
|
||||||
queue,
|
queue,
|
||||||
qh,
|
qh,
|
||||||
globals,
|
globals,
|
||||||
global_list,
|
global_list,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_events(&mut self) -> Vec<(ObjectKey, ObjectEvent)> {
|
||||||
|
let mut events = std::mem::take(&mut self.globals.events);
|
||||||
|
self.globals.queued_events.retain(|rx| {
|
||||||
|
match rx.try_recv() {
|
||||||
|
Ok(event) => {
|
||||||
|
events.push(event);
|
||||||
|
}
|
||||||
|
Err(std::sync::mpsc::TryRecvError::Empty) => return true,
|
||||||
|
|
||||||
|
Err(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
events.extend(rx.try_iter());
|
||||||
|
false
|
||||||
|
});
|
||||||
|
events
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Event<T> = <T as Proxy>::Event;
|
pub type Event<T> = <T as Proxy>::Event;
|
||||||
|
|
@ -100,6 +133,7 @@ delegate_noop!(Globals: WpViewporter);
|
||||||
delegate_noop!(Globals: WpViewport);
|
delegate_noop!(Globals: WpViewport);
|
||||||
delegate_noop!(Globals: ZxdgOutputManagerV1);
|
delegate_noop!(Globals: ZxdgOutputManagerV1);
|
||||||
delegate_noop!(Globals: ZwpPointerConstraintsV1);
|
delegate_noop!(Globals: ZwpPointerConstraintsV1);
|
||||||
|
delegate_noop!(Globals: ZwpTabletManagerV2);
|
||||||
|
|
||||||
impl Dispatch<WlRegistry, GlobalListContents> for Globals {
|
impl Dispatch<WlRegistry, GlobalListContents> for Globals {
|
||||||
fn event(
|
fn event(
|
||||||
|
|
@ -188,3 +222,130 @@ push_events!(XdgOutput);
|
||||||
push_events!(WlTouch);
|
push_events!(WlTouch);
|
||||||
push_events!(ZwpConfinedPointerV1);
|
push_events!(ZwpConfinedPointerV1);
|
||||||
push_events!(ZwpLockedPointerV1);
|
push_events!(ZwpLockedPointerV1);
|
||||||
|
|
||||||
|
pub(crate) struct LateInitObjectKey<P: Proxy> {
|
||||||
|
key: OnceLock<ObjectKey>,
|
||||||
|
queued_events: Mutex<Vec<P::Event>>,
|
||||||
|
sender: Mutex<Option<mpsc::Sender<(ObjectKey, ObjectEvent)>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Proxy> LateInitObjectKey<P>
|
||||||
|
where
|
||||||
|
P::Event: Into<ObjectEvent>,
|
||||||
|
{
|
||||||
|
pub fn init(&self, key: ObjectKey) {
|
||||||
|
self.key.set(key).expect("Object key should not be set");
|
||||||
|
if let Some(sender) = self.sender.lock().unwrap().take() {
|
||||||
|
for event in self.queued_events.lock().unwrap().drain(..) {
|
||||||
|
sender.send((key, event.into())).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
key: OnceLock::new(),
|
||||||
|
queued_events: Mutex::default(),
|
||||||
|
sender: Mutex::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_or_queue_event(&self, state: &mut Globals, event: P::Event) {
|
||||||
|
if let Some(key) = self.key.get().copied() {
|
||||||
|
state.events.push((key, event.into()));
|
||||||
|
} else {
|
||||||
|
let mut sender = self.sender.lock().unwrap();
|
||||||
|
if sender.is_none() {
|
||||||
|
let (send, recv) = mpsc::channel();
|
||||||
|
*sender = Some(send);
|
||||||
|
state.queued_events.push(recv);
|
||||||
|
}
|
||||||
|
self.queued_events.lock().unwrap().push(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Proxy> std::ops::Deref for LateInitObjectKey<P> {
|
||||||
|
type Target = ObjectKey;
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.key.get().expect("object key has not been initialized")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<ZwpTabletSeatV2, ObjectKey> for Globals {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
_: &ZwpTabletSeatV2,
|
||||||
|
event: <ZwpTabletSeatV2 as Proxy>::Event,
|
||||||
|
key: &ObjectKey,
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
state.events.push((*key, event.into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
event_created_child!(Globals, ZwpTabletSeatV2, [
|
||||||
|
EVT_TABLET_ADDED_OPCODE => (ZwpTabletV2, LateInitObjectKey::new()),
|
||||||
|
EVT_PAD_ADDED_OPCODE => (ZwpTabletPadV2, LateInitObjectKey::new()),
|
||||||
|
EVT_TOOL_ADDED_OPCODE => (ZwpTabletToolV2, LateInitObjectKey::new())
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! push_or_queue_events {
|
||||||
|
($type:ty) => {
|
||||||
|
impl Dispatch<$type, LateInitObjectKey<$type>> for Globals {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
_: &$type,
|
||||||
|
event: <$type as Proxy>::Event,
|
||||||
|
key: &LateInitObjectKey<$type>,
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
key.push_or_queue_event(state, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
push_or_queue_events!(ZwpTabletV2);
|
||||||
|
push_or_queue_events!(ZwpTabletToolV2);
|
||||||
|
push_or_queue_events!(ZwpTabletPadRingV2);
|
||||||
|
push_or_queue_events!(ZwpTabletPadStripV2);
|
||||||
|
|
||||||
|
impl Dispatch<ZwpTabletPadV2, LateInitObjectKey<ZwpTabletPadV2>> for Globals {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
_: &ZwpTabletPadV2,
|
||||||
|
event: <ZwpTabletPadV2 as Proxy>::Event,
|
||||||
|
key: &LateInitObjectKey<ZwpTabletPadV2>,
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
key.push_or_queue_event(state, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
event_created_child!(Globals, ZwpTabletPadV2, [
|
||||||
|
EVT_GROUP_OPCODE => (ZwpTabletPadGroupV2, LateInitObjectKey::new())
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<ZwpTabletPadGroupV2, LateInitObjectKey<ZwpTabletPadGroupV2>> for Globals {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
_: &ZwpTabletPadGroupV2,
|
||||||
|
event: <ZwpTabletPadGroupV2 as Proxy>::Event,
|
||||||
|
key: &LateInitObjectKey<ZwpTabletPadGroupV2>,
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
key.push_or_queue_event(state, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
event_created_child!(Globals, ZwpTabletPadGroupV2, [
|
||||||
|
EVT_RING_OPCODE => (ZwpTabletPadRingV2, LateInitObjectKey::new()),
|
||||||
|
EVT_STRIP_OPCODE => (ZwpTabletPadStripV2, LateInitObjectKey::new())
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,9 @@ use wayland_protocols::{
|
||||||
},
|
},
|
||||||
relative_pointer::zv1::{
|
relative_pointer::zv1::{
|
||||||
client::zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1 as RelativePointerManClient,
|
client::zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1 as RelativePointerManClient,
|
||||||
server::{
|
server::zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1 as RelativePointerManServer,
|
||||||
zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1 as RelativePointerManServer,
|
|
||||||
zwp_relative_pointer_v1::ZwpRelativePointerV1 as RelativePointerServer,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
tablet::zv2::{client as c_tablet, server as s_tablet},
|
||||||
viewporter::{client as c_vp, server as s_vp},
|
viewporter::{client as c_vp, server as s_vp},
|
||||||
},
|
},
|
||||||
xdg::xdg_output::zv1::{
|
xdg::xdg_output::zv1::{
|
||||||
|
|
@ -59,6 +57,40 @@ use wayland_server::{
|
||||||
Dispatch, DisplayHandle, GlobalDispatch, Resource,
|
Dispatch, DisplayHandle, GlobalDispatch, Resource,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
macro_rules! only_destroy_request_impl {
|
||||||
|
($object_type:ty) => {
|
||||||
|
impl<C: XConnection> Dispatch<<$object_type as GenericObjectExt>::Server, ObjectKey>
|
||||||
|
for ServerState<C>
|
||||||
|
{
|
||||||
|
fn request(
|
||||||
|
state: &mut Self,
|
||||||
|
_: &Client,
|
||||||
|
_: &<$object_type as GenericObjectExt>::Server,
|
||||||
|
request: <<$object_type as GenericObjectExt>::Server as Resource>::Request,
|
||||||
|
key: &ObjectKey,
|
||||||
|
_: &DisplayHandle,
|
||||||
|
_: &mut wayland_server::DataInit<'_, Self>,
|
||||||
|
) {
|
||||||
|
if !matches!(
|
||||||
|
request,
|
||||||
|
<<$object_type as GenericObjectExt>::Server as Resource>::Request::Destroy
|
||||||
|
) {
|
||||||
|
warn!(
|
||||||
|
"unrecognized {} request: {:?}",
|
||||||
|
stringify!($object_type),
|
||||||
|
request
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let obj: &$object_type = state.objects[*key].as_ref();
|
||||||
|
obj.client.destroy();
|
||||||
|
state.objects.remove(*key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// noop
|
// noop
|
||||||
impl<C: XConnection> Dispatch<WlCallback, ()> for ServerState<C> {
|
impl<C: XConnection> Dispatch<WlCallback, ()> for ServerState<C> {
|
||||||
fn request(
|
fn request(
|
||||||
|
|
@ -166,7 +198,7 @@ impl<C: XConnection> Dispatch<WlRegion, client::wl_region::WlRegion> for ServerS
|
||||||
_: &DisplayHandle,
|
_: &DisplayHandle,
|
||||||
_: &mut wayland_server::DataInit<'_, Self>,
|
_: &mut wayland_server::DataInit<'_, Self>,
|
||||||
) {
|
) {
|
||||||
simple_event_shunt! {
|
macros::simple_event_shunt! {
|
||||||
client, request: wl_region::Request => [
|
client, request: wl_region::Request => [
|
||||||
Add { x, y, width, height },
|
Add { x, y, width, height },
|
||||||
Subtract { x, y, width, height },
|
Subtract { x, y, width, height },
|
||||||
|
|
@ -432,24 +464,7 @@ impl<C: XConnection> Dispatch<WlSeat, ObjectKey> for ServerState<C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
only_destroy_request_impl!(RelativePointer);
|
||||||
impl<C: XConnection> Dispatch<RelativePointerServer, ObjectKey> for ServerState<C> {
|
|
||||||
fn request(
|
|
||||||
state: &mut Self,
|
|
||||||
_: &wayland_server::Client,
|
|
||||||
_: &RelativePointerServer,
|
|
||||||
request: <RelativePointerServer as Resource>::Request,
|
|
||||||
key: &ObjectKey,
|
|
||||||
_: &DisplayHandle,
|
|
||||||
_: &mut wayland_server::DataInit<'_, Self>,
|
|
||||||
) {
|
|
||||||
if let Request::<RelativePointerServer>::Destroy = request {
|
|
||||||
let obj: &RelativePointer = state.objects[*key].as_ref();
|
|
||||||
obj.client.destroy();
|
|
||||||
state.objects.remove(*key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C: XConnection>
|
impl<C: XConnection>
|
||||||
Dispatch<RelativePointerManServer, ClientGlobalWrapper<RelativePointerManClient>>
|
Dispatch<RelativePointerManServer, ClientGlobalWrapper<RelativePointerManClient>>
|
||||||
|
|
@ -980,6 +995,170 @@ impl<C: XConnection>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<C: XConnection>
|
||||||
|
Dispatch<
|
||||||
|
s_tablet::zwp_tablet_manager_v2::ZwpTabletManagerV2,
|
||||||
|
ClientGlobalWrapper<c_tablet::zwp_tablet_manager_v2::ZwpTabletManagerV2>,
|
||||||
|
> for ServerState<C>
|
||||||
|
{
|
||||||
|
fn request(
|
||||||
|
state: &mut Self,
|
||||||
|
_: &wayland_server::Client,
|
||||||
|
_: &s_tablet::zwp_tablet_manager_v2::ZwpTabletManagerV2,
|
||||||
|
request: <s_tablet::zwp_tablet_manager_v2::ZwpTabletManagerV2 as Resource>::Request,
|
||||||
|
client: &ClientGlobalWrapper<c_tablet::zwp_tablet_manager_v2::ZwpTabletManagerV2>,
|
||||||
|
_: &DisplayHandle,
|
||||||
|
data_init: &mut wayland_server::DataInit<'_, Self>,
|
||||||
|
) {
|
||||||
|
use s_tablet::zwp_tablet_manager_v2::Request::*;
|
||||||
|
match request {
|
||||||
|
GetTabletSeat { tablet_seat, seat } => {
|
||||||
|
let seat_key: ObjectKey = seat.data().copied().unwrap();
|
||||||
|
state
|
||||||
|
.objects
|
||||||
|
.insert_from_other_objects([seat_key], |[seat_obj], key| {
|
||||||
|
let Seat { client: c_seat, .. }: &Seat = seat_obj.try_into().unwrap();
|
||||||
|
let client = client.get_tablet_seat(c_seat, &state.qh, key);
|
||||||
|
let server = data_init.init(tablet_seat, key);
|
||||||
|
TabletSeat { client, server }.into()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
warn!("unhandled tablet request: {other:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
only_destroy_request_impl!(TabletSeat);
|
||||||
|
only_destroy_request_impl!(Tablet);
|
||||||
|
only_destroy_request_impl!(TabletPadGroup);
|
||||||
|
|
||||||
|
impl<C: XConnection> Dispatch<s_tablet::zwp_tablet_pad_v2::ZwpTabletPadV2, ObjectKey>
|
||||||
|
for ServerState<C>
|
||||||
|
{
|
||||||
|
fn request(
|
||||||
|
state: &mut Self,
|
||||||
|
_: &Client,
|
||||||
|
_: &s_tablet::zwp_tablet_pad_v2::ZwpTabletPadV2,
|
||||||
|
request: <s_tablet::zwp_tablet_pad_v2::ZwpTabletPadV2 as Resource>::Request,
|
||||||
|
key: &ObjectKey,
|
||||||
|
_: &DisplayHandle,
|
||||||
|
_: &mut wayland_server::DataInit<'_, Self>,
|
||||||
|
) {
|
||||||
|
let pad: &TabletPad = state.objects[*key].as_ref();
|
||||||
|
match request {
|
||||||
|
s_tablet::zwp_tablet_pad_v2::Request::SetFeedback {
|
||||||
|
button,
|
||||||
|
description,
|
||||||
|
serial,
|
||||||
|
} => {
|
||||||
|
pad.client.set_feedback(button, description, serial);
|
||||||
|
}
|
||||||
|
s_tablet::zwp_tablet_pad_v2::Request::Destroy => {
|
||||||
|
pad.client.destroy();
|
||||||
|
state.objects.remove(*key);
|
||||||
|
}
|
||||||
|
other => warn!("unhandled tablet pad request: {other:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: XConnection> Dispatch<s_tablet::zwp_tablet_tool_v2::ZwpTabletToolV2, ObjectKey>
|
||||||
|
for ServerState<C>
|
||||||
|
{
|
||||||
|
fn request(
|
||||||
|
state: &mut Self,
|
||||||
|
_: &Client,
|
||||||
|
_: &s_tablet::zwp_tablet_tool_v2::ZwpTabletToolV2,
|
||||||
|
request: <s_tablet::zwp_tablet_tool_v2::ZwpTabletToolV2 as Resource>::Request,
|
||||||
|
key: &ObjectKey,
|
||||||
|
_: &DisplayHandle,
|
||||||
|
_: &mut wayland_server::DataInit<'_, Self>,
|
||||||
|
) {
|
||||||
|
let tool: &TabletTool = state.objects[*key].as_ref();
|
||||||
|
match request {
|
||||||
|
s_tablet::zwp_tablet_tool_v2::Request::SetCursor {
|
||||||
|
serial,
|
||||||
|
surface,
|
||||||
|
hotspot_x,
|
||||||
|
hotspot_y,
|
||||||
|
} => {
|
||||||
|
let surf_key: Option<ObjectKey> = surface.map(|s| s.data().copied().unwrap());
|
||||||
|
let c_surface = surf_key.map(|key| {
|
||||||
|
let d: &SurfaceData = state.objects[key].as_ref();
|
||||||
|
&d.client
|
||||||
|
});
|
||||||
|
tool.client
|
||||||
|
.set_cursor(serial, c_surface, hotspot_x, hotspot_y);
|
||||||
|
}
|
||||||
|
s_tablet::zwp_tablet_tool_v2::Request::Destroy => {
|
||||||
|
tool.client.destroy();
|
||||||
|
state.objects.remove(*key);
|
||||||
|
}
|
||||||
|
other => warn!("unhandled tablet tool request: {other:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: XConnection> Dispatch<s_tablet::zwp_tablet_pad_ring_v2::ZwpTabletPadRingV2, ObjectKey>
|
||||||
|
for ServerState<C>
|
||||||
|
{
|
||||||
|
fn request(
|
||||||
|
state: &mut Self,
|
||||||
|
_: &Client,
|
||||||
|
_: &s_tablet::zwp_tablet_pad_ring_v2::ZwpTabletPadRingV2,
|
||||||
|
request: <s_tablet::zwp_tablet_pad_ring_v2::ZwpTabletPadRingV2 as Resource>::Request,
|
||||||
|
key: &ObjectKey,
|
||||||
|
_: &DisplayHandle,
|
||||||
|
_: &mut wayland_server::DataInit<'_, Self>,
|
||||||
|
) {
|
||||||
|
let ring: &TabletPadRing = state.objects[*key].as_ref();
|
||||||
|
match request {
|
||||||
|
s_tablet::zwp_tablet_pad_ring_v2::Request::SetFeedback {
|
||||||
|
description,
|
||||||
|
serial,
|
||||||
|
} => {
|
||||||
|
ring.client.set_feedback(description, serial);
|
||||||
|
}
|
||||||
|
s_tablet::zwp_tablet_pad_ring_v2::Request::Destroy => {
|
||||||
|
ring.client.destroy();
|
||||||
|
state.objects.remove(*key);
|
||||||
|
}
|
||||||
|
other => warn!("unhandled tablet pad ring requst: {other:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: XConnection> Dispatch<s_tablet::zwp_tablet_pad_strip_v2::ZwpTabletPadStripV2, ObjectKey>
|
||||||
|
for ServerState<C>
|
||||||
|
{
|
||||||
|
fn request(
|
||||||
|
state: &mut Self,
|
||||||
|
_: &Client,
|
||||||
|
_: &s_tablet::zwp_tablet_pad_strip_v2::ZwpTabletPadStripV2,
|
||||||
|
request: <s_tablet::zwp_tablet_pad_strip_v2::ZwpTabletPadStripV2 as Resource>::Request,
|
||||||
|
key: &ObjectKey,
|
||||||
|
_: &DisplayHandle,
|
||||||
|
_: &mut wayland_server::DataInit<'_, Self>,
|
||||||
|
) {
|
||||||
|
let strip: &TabletPadStrip = state.objects[*key].as_ref();
|
||||||
|
match request {
|
||||||
|
s_tablet::zwp_tablet_pad_strip_v2::Request::SetFeedback {
|
||||||
|
description,
|
||||||
|
serial,
|
||||||
|
} => {
|
||||||
|
strip.client.set_feedback(description, serial);
|
||||||
|
}
|
||||||
|
s_tablet::zwp_tablet_pad_strip_v2::Request::Destroy => {
|
||||||
|
strip.client.destroy();
|
||||||
|
state.objects.remove(*key);
|
||||||
|
}
|
||||||
|
other => warn!("unhandled tablet pad strip requst: {other:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct ClientGlobalWrapper<T: Proxy>(Arc<OnceLock<T>>);
|
pub(crate) struct ClientGlobalWrapper<T: Proxy>(Arc<OnceLock<T>>);
|
||||||
impl<T: Proxy> std::ops::Deref for ClientGlobalWrapper<T> {
|
impl<T: Proxy> std::ops::Deref for ClientGlobalWrapper<T> {
|
||||||
|
|
@ -1072,6 +1251,10 @@ global_dispatch_no_events!(
|
||||||
c_vp::wp_viewporter::WpViewporter
|
c_vp::wp_viewporter::WpViewporter
|
||||||
);
|
);
|
||||||
global_dispatch_no_events!(PointerConstraintsServer, PointerConstraintsClient);
|
global_dispatch_no_events!(PointerConstraintsServer, PointerConstraintsClient);
|
||||||
|
global_dispatch_no_events!(
|
||||||
|
s_tablet::zwp_tablet_manager_v2::ZwpTabletManagerV2,
|
||||||
|
c_tablet::zwp_tablet_manager_v2::ZwpTabletManagerV2
|
||||||
|
);
|
||||||
|
|
||||||
impl<C: XConnection> GlobalDispatch<WlSeat, Global> for ServerState<C>
|
impl<C: XConnection> GlobalDispatch<WlSeat, Global> for ServerState<C>
|
||||||
where
|
where
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::clientside::LateInitObjectKey;
|
||||||
use log::{debug, trace, warn};
|
use log::{debug, trace, warn};
|
||||||
use macros::simple_event_shunt;
|
use macros::simple_event_shunt;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
@ -22,6 +23,26 @@ use wayland_protocols::{
|
||||||
},
|
},
|
||||||
server::zwp_relative_pointer_v1::ZwpRelativePointerV1 as RelativePointerServer,
|
server::zwp_relative_pointer_v1::ZwpRelativePointerV1 as RelativePointerServer,
|
||||||
},
|
},
|
||||||
|
tablet::zv2::{
|
||||||
|
client::{
|
||||||
|
zwp_tablet_pad_group_v2::{self, ZwpTabletPadGroupV2 as TabletPadGroupClient},
|
||||||
|
zwp_tablet_pad_ring_v2::{self, ZwpTabletPadRingV2 as TabletPadRingClient},
|
||||||
|
zwp_tablet_pad_strip_v2::{self, ZwpTabletPadStripV2 as TabletPadStripClient},
|
||||||
|
zwp_tablet_pad_v2::{self, ZwpTabletPadV2 as TabletPadClient},
|
||||||
|
zwp_tablet_seat_v2::{self, ZwpTabletSeatV2 as TabletSeatClient},
|
||||||
|
zwp_tablet_tool_v2::{self, ZwpTabletToolV2 as TabletToolClient},
|
||||||
|
zwp_tablet_v2::{self, ZwpTabletV2 as TabletClient},
|
||||||
|
},
|
||||||
|
server::{
|
||||||
|
zwp_tablet_pad_group_v2::ZwpTabletPadGroupV2 as TabletPadGroupServer,
|
||||||
|
zwp_tablet_pad_ring_v2::ZwpTabletPadRingV2 as TabletPadRingServer,
|
||||||
|
zwp_tablet_pad_strip_v2::ZwpTabletPadStripV2 as TabletPadStripServer,
|
||||||
|
zwp_tablet_pad_v2::ZwpTabletPadV2 as TabletPadServer,
|
||||||
|
zwp_tablet_seat_v2::ZwpTabletSeatV2 as TabletSeatServer,
|
||||||
|
zwp_tablet_tool_v2::ZwpTabletToolV2 as TabletToolServer,
|
||||||
|
zwp_tablet_v2::ZwpTabletV2 as TabletServer,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
xdg::{
|
xdg::{
|
||||||
shell::client::{xdg_popup, xdg_surface, xdg_toplevel},
|
shell::client::{xdg_popup, xdg_surface, xdg_toplevel},
|
||||||
|
|
@ -237,6 +258,41 @@ pub struct GenericObject<Server: Resource, Client: Proxy> {
|
||||||
pub client: Client,
|
pub client: Client,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<S: Resource + 'static, C: Proxy + 'static> GenericObject<S, C> {
|
||||||
|
fn from_client<XC: XConnection>(client: C, state: &mut ServerState<XC>) -> &Self
|
||||||
|
where
|
||||||
|
Self: Into<WrappedObject>,
|
||||||
|
for<'a> &'a Self: TryFrom<&'a Object, Error = String>,
|
||||||
|
ServerState<XC>: wayland_server::Dispatch<S, ObjectKey>,
|
||||||
|
C::Event: Send + Into<ObjectEvent>,
|
||||||
|
{
|
||||||
|
let key = state.objects.insert_with_key(|key| {
|
||||||
|
let server = state
|
||||||
|
.client
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.create_resource::<_, _, ServerState<XC>>(&state.dh, 1, key)
|
||||||
|
.unwrap();
|
||||||
|
let obj_key: &LateInitObjectKey<C> = client.data().unwrap();
|
||||||
|
obj_key.init(key);
|
||||||
|
|
||||||
|
Self { client, server }.into()
|
||||||
|
});
|
||||||
|
|
||||||
|
state.objects[key].as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GenericObjectExt {
|
||||||
|
type Server: Resource;
|
||||||
|
type Client: Proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Resource, C: Proxy> GenericObjectExt for GenericObject<S, C> {
|
||||||
|
type Server = S;
|
||||||
|
type Client = C;
|
||||||
|
}
|
||||||
|
|
||||||
pub type Buffer = GenericObject<WlBuffer, client::wl_buffer::WlBuffer>;
|
pub type Buffer = GenericObject<WlBuffer, client::wl_buffer::WlBuffer>;
|
||||||
impl HandleEvent for Buffer {
|
impl HandleEvent for Buffer {
|
||||||
type Event = client::wl_buffer::Event;
|
type Event = client::wl_buffer::Event;
|
||||||
|
|
@ -790,3 +846,183 @@ impl HandleEvent for ConfinedPointer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type TabletSeat = GenericObject<TabletSeatServer, TabletSeatClient>;
|
||||||
|
impl HandleEvent for TabletSeat {
|
||||||
|
type Event = zwp_tablet_seat_v2::Event;
|
||||||
|
|
||||||
|
fn handle_event<C: XConnection>(&mut self, event: Self::Event, state: &mut ServerState<C>) {
|
||||||
|
simple_event_shunt! {
|
||||||
|
self.server, event: zwp_tablet_seat_v2::Event => [
|
||||||
|
TabletAdded {
|
||||||
|
|id| &Tablet::from_client(id, state).server
|
||||||
|
},
|
||||||
|
ToolAdded {
|
||||||
|
|id| &TabletTool::from_client(id, state).server
|
||||||
|
},
|
||||||
|
PadAdded {
|
||||||
|
|id| &TabletPad::from_client(id, state).server
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Tablet = GenericObject<TabletServer, TabletClient>;
|
||||||
|
impl HandleEvent for Tablet {
|
||||||
|
type Event = zwp_tablet_v2::Event;
|
||||||
|
|
||||||
|
fn handle_event<C: XConnection>(&mut self, event: Self::Event, _: &mut ServerState<C>) {
|
||||||
|
simple_event_shunt! {
|
||||||
|
self.server, event: zwp_tablet_v2::Event => [
|
||||||
|
Name { name },
|
||||||
|
Id { vid, pid },
|
||||||
|
Path { path },
|
||||||
|
Done,
|
||||||
|
Removed
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type TabletPad = GenericObject<TabletPadServer, TabletPadClient>;
|
||||||
|
impl HandleEvent for TabletPad {
|
||||||
|
type Event = zwp_tablet_pad_v2::Event;
|
||||||
|
|
||||||
|
fn handle_event<C: XConnection>(&mut self, event: Self::Event, state: &mut ServerState<C>) {
|
||||||
|
simple_event_shunt! {
|
||||||
|
self.server, event: zwp_tablet_pad_v2::Event => [
|
||||||
|
Group { |pad_group| &TabletPadGroup::from_client(pad_group, state).server },
|
||||||
|
Path { path },
|
||||||
|
Buttons { buttons },
|
||||||
|
Done,
|
||||||
|
Button {
|
||||||
|
time,
|
||||||
|
button,
|
||||||
|
|state| convert_wenum(state)
|
||||||
|
},
|
||||||
|
Enter {
|
||||||
|
serial,
|
||||||
|
|tablet| {
|
||||||
|
let key: &LateInitObjectKey<TabletClient> = tablet.data().unwrap();
|
||||||
|
let Some(tablet): Option<&Tablet> = state.objects.get(**key).map(|o| o.as_ref()) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
&tablet.server
|
||||||
|
},
|
||||||
|
|surface| {
|
||||||
|
let Some(surface_data) = state.get_server_surface_from_client(surface) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
surface_data
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Leave {
|
||||||
|
serial,
|
||||||
|
|surface| {
|
||||||
|
let Some(surface_data) = state.get_server_surface_from_client(surface) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
surface_data
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Removed
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type TabletTool = GenericObject<TabletToolServer, TabletToolClient>;
|
||||||
|
impl HandleEvent for TabletTool {
|
||||||
|
type Event = zwp_tablet_tool_v2::Event;
|
||||||
|
|
||||||
|
fn handle_event<C: XConnection>(&mut self, event: Self::Event, state: &mut ServerState<C>) {
|
||||||
|
simple_event_shunt! {
|
||||||
|
self.server, event: zwp_tablet_tool_v2::Event => [
|
||||||
|
Type { |tool_type| convert_wenum(tool_type) },
|
||||||
|
HardwareSerial { hardware_serial_hi, hardware_serial_lo },
|
||||||
|
HardwareIdWacom { hardware_id_hi, hardware_id_lo },
|
||||||
|
Capability { |capability| convert_wenum(capability) },
|
||||||
|
Done,
|
||||||
|
Removed,
|
||||||
|
ProximityIn {
|
||||||
|
serial,
|
||||||
|
|tablet| {
|
||||||
|
let key: &LateInitObjectKey<TabletClient> = tablet.data().unwrap();
|
||||||
|
let Some(tablet): Option<&Tablet> = state.objects.get(**key).map(|o| o.as_ref()) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
&tablet.server
|
||||||
|
},
|
||||||
|
|surface| {
|
||||||
|
let Some(surface_data) = state.get_server_surface_from_client(surface) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
surface_data
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ProximityOut,
|
||||||
|
Down { serial },
|
||||||
|
Up,
|
||||||
|
Motion { x, y },
|
||||||
|
Pressure { pressure },
|
||||||
|
Tilt { tilt_x, tilt_y },
|
||||||
|
Rotation { degrees },
|
||||||
|
Slider { position },
|
||||||
|
Wheel { degrees, clicks },
|
||||||
|
Button { serial, button, |state| convert_wenum(state) },
|
||||||
|
Frame { time },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type TabletPadGroup = GenericObject<TabletPadGroupServer, TabletPadGroupClient>;
|
||||||
|
impl HandleEvent for TabletPadGroup {
|
||||||
|
type Event = zwp_tablet_pad_group_v2::Event;
|
||||||
|
|
||||||
|
fn handle_event<C: XConnection>(&mut self, event: Self::Event, state: &mut ServerState<C>) {
|
||||||
|
simple_event_shunt! {
|
||||||
|
self.server, event: zwp_tablet_pad_group_v2::Event => [
|
||||||
|
Buttons { buttons },
|
||||||
|
Ring { |ring| &TabletPadRing::from_client(ring, state).server },
|
||||||
|
Strip { |strip| &TabletPadStrip::from_client(strip, state).server },
|
||||||
|
Modes { modes },
|
||||||
|
Done,
|
||||||
|
ModeSwitch { time, serial, mode }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type TabletPadRing = GenericObject<TabletPadRingServer, TabletPadRingClient>;
|
||||||
|
impl HandleEvent for TabletPadRing {
|
||||||
|
type Event = zwp_tablet_pad_ring_v2::Event;
|
||||||
|
|
||||||
|
fn handle_event<C: XConnection>(&mut self, event: Self::Event, _: &mut ServerState<C>) {
|
||||||
|
simple_event_shunt! {
|
||||||
|
self.server, event: zwp_tablet_pad_ring_v2::Event => [
|
||||||
|
Source { |source| convert_wenum(source) },
|
||||||
|
Angle { degrees },
|
||||||
|
Stop,
|
||||||
|
Frame { time }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type TabletPadStrip = GenericObject<TabletPadStripServer, TabletPadStripClient>;
|
||||||
|
impl HandleEvent for TabletPadStrip {
|
||||||
|
type Event = zwp_tablet_pad_strip_v2::Event;
|
||||||
|
|
||||||
|
fn handle_event<C: XConnection>(&mut self, event: Self::Event, _: &mut ServerState<C>) {
|
||||||
|
simple_event_shunt! {
|
||||||
|
self.server, event: zwp_tablet_pad_strip_v2::Event => [
|
||||||
|
Source { |source| convert_wenum(source) },
|
||||||
|
Position { position },
|
||||||
|
Stop,
|
||||||
|
Frame { time }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ use wayland_protocols::{
|
||||||
linux_dmabuf::zv1::{client as c_dmabuf, server as s_dmabuf},
|
linux_dmabuf::zv1::{client as c_dmabuf, server as s_dmabuf},
|
||||||
pointer_constraints::zv1::server::zwp_pointer_constraints_v1::ZwpPointerConstraintsV1,
|
pointer_constraints::zv1::server::zwp_pointer_constraints_v1::ZwpPointerConstraintsV1,
|
||||||
relative_pointer::zv1::server::zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1,
|
relative_pointer::zv1::server::zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1,
|
||||||
|
tablet::zv2::server::zwp_tablet_manager_v2::ZwpTabletManagerV2,
|
||||||
viewporter::server as s_vp,
|
viewporter::server as s_vp,
|
||||||
},
|
},
|
||||||
xdg::{
|
xdg::{
|
||||||
|
|
@ -49,7 +50,7 @@ use wayland_server::{
|
||||||
wl_callback::WlCallback, wl_compositor::WlCompositor, wl_output::WlOutput, wl_seat::WlSeat,
|
wl_callback::WlCallback, wl_compositor::WlCompositor, wl_output::WlOutput, wl_seat::WlSeat,
|
||||||
wl_shm::WlShm, wl_surface::WlSurface,
|
wl_shm::WlShm, wl_surface::WlSurface,
|
||||||
},
|
},
|
||||||
DisplayHandle, Resource, WEnum,
|
Client, DisplayHandle, Resource, WEnum,
|
||||||
};
|
};
|
||||||
use wl_drm::{client::wl_drm::WlDrm as WlDrmClient, server::wl_drm::WlDrm as WlDrmServer};
|
use wl_drm::{client::wl_drm::WlDrm as WlDrmClient, server::wl_drm::WlDrm as WlDrmServer};
|
||||||
use xcb::x;
|
use xcb::x;
|
||||||
|
|
@ -362,12 +363,20 @@ pub(crate) enum Object {
|
||||||
Drm(Drm),
|
Drm(Drm),
|
||||||
Touch(Touch),
|
Touch(Touch),
|
||||||
ConfinedPointer(ConfinedPointer),
|
ConfinedPointer(ConfinedPointer),
|
||||||
LockedPointer(LockedPointer)
|
LockedPointer(LockedPointer),
|
||||||
|
TabletSeat(TabletSeat),
|
||||||
|
Tablet(Tablet),
|
||||||
|
TabletTool(TabletTool),
|
||||||
|
TabletPad(TabletPad),
|
||||||
|
TabletPadGroup(TabletPadGroup),
|
||||||
|
TabletPadRing(TabletPadRing),
|
||||||
|
TabletPadStrip(TabletPadStrip)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WrappedObject(Option<Object>);
|
#[derive(Default)]
|
||||||
|
pub(crate) struct WrappedObject(Option<Object>);
|
||||||
|
|
||||||
impl<T> From<T> for WrappedObject
|
impl<T> From<T> for WrappedObject
|
||||||
where
|
where
|
||||||
|
|
@ -450,7 +459,8 @@ fn handle_globals<'a, C: XConnection>(
|
||||||
s_dmabuf::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1,
|
s_dmabuf::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1,
|
||||||
ZxdgOutputManagerV1,
|
ZxdgOutputManagerV1,
|
||||||
s_vp::wp_viewporter::WpViewporter,
|
s_vp::wp_viewporter::WpViewporter,
|
||||||
ZwpPointerConstraintsV1
|
ZwpPointerConstraintsV1,
|
||||||
|
ZwpTabletManagerV2
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -467,6 +477,7 @@ pub struct ServerState<C: XConnection> {
|
||||||
windows: HashMap<x::Window, WindowData>,
|
windows: HashMap<x::Window, WindowData>,
|
||||||
|
|
||||||
qh: ClientQueueHandle,
|
qh: ClientQueueHandle,
|
||||||
|
client: Option<Client>,
|
||||||
to_focus: Option<x::Window>,
|
to_focus: Option<x::Window>,
|
||||||
last_focused_toplevel: Option<x::Window>,
|
last_focused_toplevel: Option<x::Window>,
|
||||||
last_hovered: Option<x::Window>,
|
last_hovered: Option<x::Window>,
|
||||||
|
|
@ -511,6 +522,7 @@ impl<C: XConnection> ServerState<C> {
|
||||||
Self {
|
Self {
|
||||||
windows: HashMap::new(),
|
windows: HashMap::new(),
|
||||||
clientside,
|
clientside,
|
||||||
|
client: None,
|
||||||
atoms: None,
|
atoms: None,
|
||||||
qh,
|
qh,
|
||||||
dh,
|
dh,
|
||||||
|
|
@ -531,9 +543,11 @@ impl<C: XConnection> ServerState<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect(&mut self, connection: UnixStream) {
|
pub fn connect(&mut self, connection: UnixStream) {
|
||||||
|
self.client = Some(
|
||||||
self.dh
|
self.dh
|
||||||
.insert_client(connection, std::sync::Arc::new(()))
|
.insert_client(connection, std::sync::Arc::new(()))
|
||||||
.unwrap();
|
.unwrap(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_x_connection(&mut self, connection: C) {
|
pub fn set_x_connection(&mut self, connection: C) {
|
||||||
|
|
@ -800,8 +814,7 @@ impl<C: XConnection> ServerState<C> {
|
||||||
pub fn handle_clientside_events(&mut self) {
|
pub fn handle_clientside_events(&mut self) {
|
||||||
self.handle_new_globals();
|
self.handle_new_globals();
|
||||||
|
|
||||||
let client_events = std::mem::take(&mut self.clientside.globals.events);
|
for (key, event) in self.clientside.read_events() {
|
||||||
for (key, event) in client_events {
|
|
||||||
let Some(object) = &mut self.objects.get_mut(key) else {
|
let Some(object) = &mut self.objects.get_mut(key) else {
|
||||||
warn!("could not handle clientside event: stale surface");
|
warn!("could not handle clientside event: stale surface");
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,27 @@ use wayland_client::{
|
||||||
},
|
},
|
||||||
Connection, Proxy, WEnum,
|
Connection, Proxy, WEnum,
|
||||||
};
|
};
|
||||||
|
|
||||||
use wayland_protocols::{
|
use wayland_protocols::{
|
||||||
wp::{
|
wp::{
|
||||||
linux_dmabuf::zv1::client::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1,
|
linux_dmabuf::zv1::client::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1,
|
||||||
pointer_constraints::zv1::client::zwp_pointer_constraints_v1::ZwpPointerConstraintsV1,
|
pointer_constraints::zv1::client::zwp_pointer_constraints_v1::ZwpPointerConstraintsV1,
|
||||||
relative_pointer::zv1::client::zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1,
|
relative_pointer::zv1::client::zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1,
|
||||||
|
tablet::zv2::client::{
|
||||||
|
zwp_tablet_manager_v2::{self, ZwpTabletManagerV2},
|
||||||
|
zwp_tablet_pad_group_v2::{
|
||||||
|
self, ZwpTabletPadGroupV2, EVT_RING_OPCODE, EVT_STRIP_OPCODE,
|
||||||
|
},
|
||||||
|
zwp_tablet_pad_ring_v2::ZwpTabletPadRingV2,
|
||||||
|
zwp_tablet_pad_strip_v2::ZwpTabletPadStripV2,
|
||||||
|
zwp_tablet_pad_v2::{self, ZwpTabletPadV2, EVT_GROUP_OPCODE},
|
||||||
|
zwp_tablet_seat_v2::{
|
||||||
|
self, ZwpTabletSeatV2, EVT_PAD_ADDED_OPCODE, EVT_TABLET_ADDED_OPCODE,
|
||||||
|
EVT_TOOL_ADDED_OPCODE,
|
||||||
|
},
|
||||||
|
zwp_tablet_tool_v2::{self, ZwpTabletToolV2},
|
||||||
|
zwp_tablet_v2::{self, ZwpTabletV2},
|
||||||
|
},
|
||||||
viewporter::client::wp_viewporter::WpViewporter,
|
viewporter::client::wp_viewporter::WpViewporter,
|
||||||
},
|
},
|
||||||
xdg::{
|
xdg::{
|
||||||
|
|
@ -93,6 +109,7 @@ struct Compositor {
|
||||||
shm: TestObject<WlShm>,
|
shm: TestObject<WlShm>,
|
||||||
shell: TestObject<XwaylandShellV1>,
|
shell: TestObject<XwaylandShellV1>,
|
||||||
seat: TestObject<WlSeat>,
|
seat: TestObject<WlSeat>,
|
||||||
|
tablet_man: TestObject<ZwpTabletManagerV2>
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -298,6 +315,23 @@ impl TestFixture {
|
||||||
let events = std::mem::take(&mut *self.registry.data.events.lock().unwrap());
|
let events = std::mem::take(&mut *self.registry.data.events.lock().unwrap());
|
||||||
assert!(!events.is_empty());
|
assert!(!events.is_empty());
|
||||||
|
|
||||||
|
fn bind<T: Proxy + Sync + Send + 'static>(
|
||||||
|
registry: &TestObject<WlRegistry>,
|
||||||
|
name: u32,
|
||||||
|
version: u32,
|
||||||
|
) -> TestObject<T>
|
||||||
|
where
|
||||||
|
T::Event: Sync + Send + std::fmt::Debug,
|
||||||
|
{
|
||||||
|
TestObject::from_request(
|
||||||
|
®istry.obj,
|
||||||
|
Req::<WlRegistry>::Bind {
|
||||||
|
name,
|
||||||
|
id: (T::interface(), version),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
for event in events {
|
for event in events {
|
||||||
if let Ev::<WlRegistry>::Global {
|
if let Ev::<WlRegistry>::Global {
|
||||||
name,
|
name,
|
||||||
|
|
@ -305,36 +339,18 @@ impl TestFixture {
|
||||||
version,
|
version,
|
||||||
} = event
|
} = event
|
||||||
{
|
{
|
||||||
let bind_req = |interface| Req::<WlRegistry>::Bind {
|
macro_rules! bind {
|
||||||
name,
|
($field:ident) => {
|
||||||
id: (interface, version),
|
ret.$field = Some(bind(&self.registry, name, version))
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
match interface {
|
match interface {
|
||||||
x if x == WlCompositor::interface().name => {
|
x if x == WlCompositor::interface().name => bind!(compositor),
|
||||||
ret.compositor = Some(TestObject::from_request(
|
x if x == WlShm::interface().name => bind!(shm),
|
||||||
&self.registry.obj,
|
x if x == XwaylandShellV1::interface().name => bind!(shell),
|
||||||
bind_req(WlCompositor::interface()),
|
x if x == WlSeat::interface().name => bind!(seat),
|
||||||
));
|
x if x == ZwpTabletManagerV2::interface().name => bind!(tablet_man),
|
||||||
}
|
|
||||||
x if x == WlShm::interface().name => {
|
|
||||||
ret.shm = Some(TestObject::from_request(
|
|
||||||
&self.registry.obj,
|
|
||||||
bind_req(WlShm::interface()),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
x if x == XwaylandShellV1::interface().name => {
|
|
||||||
ret.shell = Some(TestObject::from_request(
|
|
||||||
&self.registry.obj,
|
|
||||||
bind_req(XwaylandShellV1::interface()),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
x if x == WlSeat::interface().name => {
|
|
||||||
ret.seat = Some(TestObject::from_request(
|
|
||||||
&self.registry.obj,
|
|
||||||
bind_req(WlSeat::interface()),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -349,6 +365,18 @@ impl TestFixture {
|
||||||
ret.into()
|
ret.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn object_data<P>(&self, obj: &P) -> Arc<TestObjectData<P>>
|
||||||
|
where
|
||||||
|
P: Proxy + Send + Sync + 'static,
|
||||||
|
P::Event: Send + Sync + std::fmt::Debug,
|
||||||
|
{
|
||||||
|
self.xwls_connection
|
||||||
|
.get_object_data(obj.id())
|
||||||
|
.unwrap()
|
||||||
|
.downcast_arc::<TestObjectData<P>>()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
/// Cascade our requests/events through satellite and testwl
|
/// Cascade our requests/events through satellite and testwl
|
||||||
fn run(&mut self) {
|
fn run(&mut self) {
|
||||||
// Flush our requests to satellite
|
// Flush our requests to satellite
|
||||||
|
|
@ -709,10 +737,35 @@ where
|
||||||
backend: &Backend,
|
backend: &Backend,
|
||||||
msg: Message<ObjectId, std::os::fd::OwnedFd>,
|
msg: Message<ObjectId, std::os::fd::OwnedFd>,
|
||||||
) -> Option<Arc<dyn ObjectData>> {
|
) -> Option<Arc<dyn ObjectData>> {
|
||||||
|
fn obj_data<T: Proxy>() -> Arc<dyn ObjectData>
|
||||||
|
where
|
||||||
|
T: Send + Sync + 'static,
|
||||||
|
T::Event: Send + Sync + std::fmt::Debug,
|
||||||
|
{
|
||||||
|
Arc::new(TestObjectData::<T>::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_data = match (msg.sender_id.interface().name, msg.opcode) {
|
||||||
|
(x, opcode) if x == ZwpTabletSeatV2::interface().name => match opcode {
|
||||||
|
EVT_TABLET_ADDED_OPCODE => Some(obj_data::<ZwpTabletV2>()),
|
||||||
|
EVT_TOOL_ADDED_OPCODE => Some(obj_data::<ZwpTabletToolV2>()),
|
||||||
|
EVT_PAD_ADDED_OPCODE => Some(obj_data::<ZwpTabletPadV2>()),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
(x, EVT_GROUP_OPCODE) if x == ZwpTabletPadV2::interface().name => {
|
||||||
|
Some(obj_data::<ZwpTabletPadGroupV2>())
|
||||||
|
}
|
||||||
|
(x, opcode) if x == ZwpTabletPadGroupV2::interface().name => match opcode {
|
||||||
|
EVT_RING_OPCODE => Some(obj_data::<ZwpTabletPadRingV2>()),
|
||||||
|
EVT_STRIP_OPCODE => Some(obj_data::<ZwpTabletPadStripV2>()),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
let connection = Connection::from_backend(backend.clone());
|
let connection = Connection::from_backend(backend.clone());
|
||||||
let event = T::parse_event(&connection, msg).unwrap().1;
|
let event = T::parse_event(&connection, msg).unwrap().1;
|
||||||
self.events.lock().unwrap().push(event);
|
self.events.lock().unwrap().push(event);
|
||||||
None
|
new_data
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroyed(&self, _: ObjectId) {}
|
fn destroyed(&self, _: ObjectId) {}
|
||||||
|
|
@ -849,7 +902,8 @@ fn pass_through_globals() {
|
||||||
WpViewporter,
|
WpViewporter,
|
||||||
WlDrm,
|
WlDrm,
|
||||||
ZwpPointerConstraintsV1,
|
ZwpPointerConstraintsV1,
|
||||||
XwaylandShellV1
|
XwaylandShellV1,
|
||||||
|
ZwpTabletManagerV2
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut globals = SupportedGlobals::default();
|
let mut globals = SupportedGlobals::default();
|
||||||
|
|
@ -1457,6 +1511,136 @@ fn ignore_toplevel_reconfigure() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn events_check<'a, Event: std::fmt::Debug, const N: usize>(
|
||||||
|
mut it: impl Iterator<Item = Event>,
|
||||||
|
mut matchers: [Box<dyn FnMut(&Event) -> bool + 'a>; N],
|
||||||
|
) {
|
||||||
|
for (idx, matcher) in matchers.iter_mut().enumerate() {
|
||||||
|
let item = it.next();
|
||||||
|
if item.is_none() {
|
||||||
|
panic!("event {idx} does not exist");
|
||||||
|
}
|
||||||
|
if !matcher(item.as_ref().unwrap()) {
|
||||||
|
panic!("event {idx} was wrong ({item:?})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut remaining = it.peekable();
|
||||||
|
if remaining.peek().is_some() {
|
||||||
|
panic!("remaining events: {:?}", remaining.collect::<Vec<_>>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tablet_smoke_test() {
|
||||||
|
let (mut f, comp) = TestFixture::new_with_compositor();
|
||||||
|
let seat = TestObject::<ZwpTabletSeatV2>::from_request(
|
||||||
|
&comp.tablet_man.obj,
|
||||||
|
zwp_tablet_manager_v2::Request::GetTabletSeat {
|
||||||
|
seat: comp.seat.obj,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// Not sure why exactly this requires 4 runs but it works so idk
|
||||||
|
for _ in 0..4 {
|
||||||
|
f.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
let events = std::mem::take(&mut *seat.data.events.lock().unwrap()).into_iter();
|
||||||
|
let (mut tab_id, mut tool_id, mut pad_id) = (None, None, None);
|
||||||
|
events_check(
|
||||||
|
events,
|
||||||
|
[
|
||||||
|
Box::new(|e| match e {
|
||||||
|
zwp_tablet_seat_v2::Event::TabletAdded { id } => {
|
||||||
|
tab_id = Some(id.clone());
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}),
|
||||||
|
Box::new(|e| match e {
|
||||||
|
zwp_tablet_seat_v2::Event::ToolAdded { id } => {
|
||||||
|
tool_id = Some(id.clone());
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}),
|
||||||
|
Box::new(|e| match e {
|
||||||
|
zwp_tablet_seat_v2::Event::PadAdded { id } => {
|
||||||
|
pad_id = Some(id.clone());
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
let (tab_id, tool_id, pad_id) = (tab_id.unwrap(), tool_id.unwrap(), pad_id.unwrap());
|
||||||
|
|
||||||
|
// For reasons beyond my mortal understanding, `id.object_data()` does not work properly.
|
||||||
|
let tab_data = f.object_data(&tab_id);
|
||||||
|
let tab_events = std::mem::take(&mut *tab_data.events.lock().unwrap()).into_iter();
|
||||||
|
events_check(
|
||||||
|
tab_events,
|
||||||
|
[
|
||||||
|
Box::new(|e| match e {
|
||||||
|
zwp_tablet_v2::Event::Name { name } if name == "tabby" => true,
|
||||||
|
_ => false,
|
||||||
|
}),
|
||||||
|
Box::new(|e| matches!(e, zwp_tablet_v2::Event::Done)),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
let tool_data = f.object_data(&tool_id);
|
||||||
|
let tool_events = std::mem::take(&mut *tool_data.events.lock().unwrap()).into_iter();
|
||||||
|
events_check(
|
||||||
|
tool_events,
|
||||||
|
[
|
||||||
|
Box::new(|e| {
|
||||||
|
matches!(
|
||||||
|
e,
|
||||||
|
zwp_tablet_tool_v2::Event::Type {
|
||||||
|
tool_type: WEnum::Value(zwp_tablet_tool_v2::Type::Finger)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
Box::new(|e| matches!(e, zwp_tablet_tool_v2::Event::Done)),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
let pad_data = f.object_data(&pad_id);
|
||||||
|
let pad_events = std::mem::take(&mut *pad_data.events.lock().unwrap()).into_iter();
|
||||||
|
let mut group = None;
|
||||||
|
events_check(
|
||||||
|
pad_events,
|
||||||
|
[
|
||||||
|
Box::new(|e| matches!(e, zwp_tablet_pad_v2::Event::Buttons { buttons: 5 })),
|
||||||
|
Box::new(|e| match e {
|
||||||
|
zwp_tablet_pad_v2::Event::Group { pad_group } => {
|
||||||
|
group = Some(pad_group.clone());
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}),
|
||||||
|
Box::new(|e| matches!(e, zwp_tablet_pad_v2::Event::Done)),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
let group = group.unwrap();
|
||||||
|
let g_data = f.object_data(&group);
|
||||||
|
let g_events = std::mem::take(&mut *g_data.events.lock().unwrap()).into_iter();
|
||||||
|
events_check(
|
||||||
|
g_events,
|
||||||
|
[
|
||||||
|
Box::new(|e| match e {
|
||||||
|
zwp_tablet_pad_group_v2::Event::Buttons { buttons } if buttons.is_empty() => true,
|
||||||
|
_ => false,
|
||||||
|
}),
|
||||||
|
Box::new(|e| matches!(e, zwp_tablet_pad_group_v2::Event::Ring { .. })),
|
||||||
|
Box::new(|e| matches!(e, zwp_tablet_pad_group_v2::Event::Strip { .. })),
|
||||||
|
Box::new(|e| matches!(e, zwp_tablet_pad_group_v2::Event::Done)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
/// See Pointer::handle_event for an explanation.
|
/// See Pointer::handle_event for an explanation.
|
||||||
#[test]
|
#[test]
|
||||||
fn popup_pointer_motion_workaround() {}
|
fn popup_pointer_motion_workaround() {}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,16 @@ use wayland_protocols::{
|
||||||
linux_dmabuf::zv1::server::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1,
|
linux_dmabuf::zv1::server::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1,
|
||||||
pointer_constraints::zv1::server::zwp_pointer_constraints_v1::ZwpPointerConstraintsV1,
|
pointer_constraints::zv1::server::zwp_pointer_constraints_v1::ZwpPointerConstraintsV1,
|
||||||
relative_pointer::zv1::server::zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1,
|
relative_pointer::zv1::server::zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1,
|
||||||
|
tablet::zv2::server::{
|
||||||
|
zwp_tablet_manager_v2::ZwpTabletManagerV2,
|
||||||
|
zwp_tablet_pad_group_v2::ZwpTabletPadGroupV2,
|
||||||
|
zwp_tablet_pad_ring_v2::ZwpTabletPadRingV2,
|
||||||
|
zwp_tablet_pad_strip_v2::ZwpTabletPadStripV2,
|
||||||
|
zwp_tablet_pad_v2::ZwpTabletPadV2,
|
||||||
|
zwp_tablet_seat_v2::ZwpTabletSeatV2,
|
||||||
|
zwp_tablet_tool_v2::{self, ZwpTabletToolV2},
|
||||||
|
zwp_tablet_v2::ZwpTabletV2,
|
||||||
|
},
|
||||||
viewporter::server::wp_viewporter::WpViewporter,
|
viewporter::server::wp_viewporter::WpViewporter,
|
||||||
},
|
},
|
||||||
xdg::{
|
xdg::{
|
||||||
|
|
@ -338,6 +348,7 @@ impl Server {
|
||||||
dh.create_global::<State, XdgWmBase, _>(6, ());
|
dh.create_global::<State, XdgWmBase, _>(6, ());
|
||||||
dh.create_global::<State, WlSeat, _>(5, ());
|
dh.create_global::<State, WlSeat, _>(5, ());
|
||||||
dh.create_global::<State, WlDataDeviceManager, _>(3, ());
|
dh.create_global::<State, WlDataDeviceManager, _>(3, ());
|
||||||
|
dh.create_global::<State, ZwpTabletManagerV2, _>(1, ());
|
||||||
global_noop!(ZwpLinuxDmabufV1);
|
global_noop!(ZwpLinuxDmabufV1);
|
||||||
global_noop!(ZwpRelativePointerManagerV1);
|
global_noop!(ZwpRelativePointerManagerV1);
|
||||||
global_noop!(WpViewporter);
|
global_noop!(WpViewporter);
|
||||||
|
|
@ -641,6 +652,77 @@ simple_global_dispatch!(WlShm);
|
||||||
simple_global_dispatch!(WlCompositor);
|
simple_global_dispatch!(WlCompositor);
|
||||||
simple_global_dispatch!(XdgWmBase);
|
simple_global_dispatch!(XdgWmBase);
|
||||||
simple_global_dispatch!(ZxdgOutputManagerV1);
|
simple_global_dispatch!(ZxdgOutputManagerV1);
|
||||||
|
simple_global_dispatch!(ZwpTabletManagerV2);
|
||||||
|
|
||||||
|
impl Dispatch<ZwpTabletManagerV2, ()> for State {
|
||||||
|
fn request(
|
||||||
|
_: &mut Self,
|
||||||
|
client: &Client,
|
||||||
|
_: &ZwpTabletManagerV2,
|
||||||
|
request: <ZwpTabletManagerV2 as Resource>::Request,
|
||||||
|
_: &(),
|
||||||
|
dhandle: &DisplayHandle,
|
||||||
|
data_init: &mut wayland_server::DataInit<'_, Self>,
|
||||||
|
) {
|
||||||
|
match request {
|
||||||
|
wayland_protocols::wp::tablet::zv2::server::zwp_tablet_manager_v2::Request::GetTabletSeat { tablet_seat, seat: _ } => {
|
||||||
|
let seat = data_init.init(tablet_seat, ());
|
||||||
|
let tablet = client.create_resource::<_, _, State>(dhandle, 1, ()).unwrap();
|
||||||
|
seat.tablet_added(&tablet);
|
||||||
|
tablet.name("tabby".to_owned());
|
||||||
|
tablet.done();
|
||||||
|
|
||||||
|
let tool = client.create_resource::<_, _, State>(dhandle, 1, ()).unwrap();
|
||||||
|
seat.tool_added(&tool);
|
||||||
|
tool._type(zwp_tablet_tool_v2::Type::Finger);
|
||||||
|
tool.done();
|
||||||
|
|
||||||
|
let pad = client.create_resource::<_, _, State>(dhandle, 1, ()).unwrap();
|
||||||
|
let group = client.create_resource::<_, _, State>(dhandle, 1, ()).unwrap();
|
||||||
|
let ring = client.create_resource::<_, _, State>(dhandle, 1, ()).unwrap();
|
||||||
|
let strip = client.create_resource::<_, _, State>(dhandle, 1, ()).unwrap();
|
||||||
|
|
||||||
|
seat.pad_added(&pad);
|
||||||
|
pad.buttons(5);
|
||||||
|
pad.group(&group);
|
||||||
|
pad.done();
|
||||||
|
|
||||||
|
group.buttons(vec![]);
|
||||||
|
group.ring(&ring);
|
||||||
|
group.strip(&strip);
|
||||||
|
group.done();
|
||||||
|
}
|
||||||
|
wayland_protocols::wp::tablet::zv2::server::zwp_tablet_manager_v2::Request::Destroy => {}
|
||||||
|
other => todo!("unhandled tablet manager request: {other:?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! unhandled {
|
||||||
|
($type:ty) => {
|
||||||
|
impl Dispatch<$type, ()> for State {
|
||||||
|
fn request(
|
||||||
|
_: &mut Self,
|
||||||
|
_: &Client,
|
||||||
|
_: &$type,
|
||||||
|
_: <$type as Resource>::Request,
|
||||||
|
_: &(),
|
||||||
|
_: &DisplayHandle,
|
||||||
|
_: &mut wayland_server::DataInit<'_, Self>,
|
||||||
|
) {
|
||||||
|
todo!(concat!(stringify!($type), " unhandled"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
unhandled!(ZwpTabletSeatV2);
|
||||||
|
unhandled!(ZwpTabletV2);
|
||||||
|
unhandled!(ZwpTabletToolV2);
|
||||||
|
unhandled!(ZwpTabletPadV2);
|
||||||
|
unhandled!(ZwpTabletPadGroupV2);
|
||||||
|
unhandled!(ZwpTabletPadRingV2);
|
||||||
|
unhandled!(ZwpTabletPadStripV2);
|
||||||
|
|
||||||
impl Dispatch<ZxdgOutputManagerV1, ()> for State {
|
impl Dispatch<ZxdgOutputManagerV1, ()> for State {
|
||||||
fn request(
|
fn request(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue