use { crate::{ backend::{InputDeviceGroupId, InputDeviceId}, cursor_user::CursorUser, ifs::{ wl_seat::{ WlSeatGlobal, tablet::{ pad_owner::PadOwnerHolder, tablet_bindings::TabletBindings, tool_owner::ToolOwnerHolder, zwp_tablet_pad_dial_v2::ZwpTabletPadDialV2, 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::ZwpTabletToolV2, zwp_tablet_v2::ZwpTabletV2, }, }, wl_surface::WlSurface, }, object::Version, tree::{FoundNode, Node}, utils::{ bindings::PerClientBindings, clonecell::CloneCell, copyhashmap::CopyHashMap, hash_map_ext::HashMapExt, }, }, std::{ cell::{Cell, RefCell}, rc::Rc, }, }; mod pad; mod pad_owner; mod tablet_bindings; mod tool; pub mod tool_owner; pub mod zwp_tablet_manager_v2; pub mod zwp_tablet_pad_dial_v2; pub mod zwp_tablet_pad_group_v2; pub mod zwp_tablet_pad_ring_v2; pub mod zwp_tablet_pad_strip_v2; pub mod zwp_tablet_pad_v2; pub mod zwp_tablet_seat_v2; pub mod zwp_tablet_tool_v2; pub mod zwp_tablet_v2; #[derive(Default)] pub struct TabletSeatData { seats: PerClientBindings, tablets: CopyHashMap>, tools: CopyHashMap>, pads: CopyHashMap>, } #[derive(Debug, Clone)] pub struct TabletInit { pub id: TabletId, pub group: InputDeviceGroupId, pub name: String, pub pid: u32, pub vid: u32, pub bustype: Option, pub path: String, } #[derive(Debug, Clone)] pub struct TabletToolInit { pub tablet_id: TabletId, pub id: TabletToolId, pub type_: TabletToolType, pub hardware_serial: u64, pub hardware_id_wacom: u64, pub capabilities: Vec, } #[derive(Debug, Clone)] pub struct TabletPadInit { pub id: TabletPadId, pub group: InputDeviceGroupId, pub path: String, pub buttons: u32, pub strips: u32, pub rings: u32, pub dials: u32, pub groups: Vec, } #[derive(Debug, Clone)] pub struct TabletPadGroupInit { pub buttons: Vec, pub rings: Vec, pub strips: Vec, pub dials: Vec, pub modes: u32, pub mode: u32, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum PadButtonState { Released, Pressed, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum ToolButtonState { Released, Pressed, } linear_ids!(TabletIds, TabletId); pub struct Tablet { _id: TabletId, dev: InputDeviceId, group: InputDeviceGroupId, name: String, pid: u32, vid: u32, bustype: Option, path: String, bindings: TabletBindings, tools: CopyHashMap>, pads: CopyHashMap>, tree: RefCell>, seat: Rc, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum TabletToolType { Pen, Eraser, Brush, Pencil, Airbrush, #[expect(dead_code)] Finger, Mouse, Lens, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum TabletToolCapability { Tilt, Pressure, Distance, Rotation, Slider, Wheel, } linear_ids!(TabletToolIds, TabletToolId, usize); #[derive(Default)] pub struct TabletToolOpt { tool: CloneCell>>, } pub struct TabletTool { pub id: TabletToolId, opt: Rc, tablet: Rc, type_: TabletToolType, hardware_serial: u64, hardware_id_wacom: u64, capabilities: Vec, bindings: TabletBindings, node: CloneCell>, pub(super) tool_owner: ToolOwnerHolder, cursor: Rc, down: Cell, pressure: Cell, distance: Cell, tilt_x: Cell, tilt_y: Cell, rotation: Cell, slider: Cell, } linear_ids!(TabletPadIds, TabletPadId); pub struct TabletPad { pub id: TabletPadId, dev: InputDeviceId, seat: Rc, group: InputDeviceGroupId, tablet: CloneCell>>, path: String, buttons: u32, bindings: TabletBindings, groups: Vec>, strips: Vec>, rings: Vec>, dials: Vec>, node: CloneCell>, pub(super) pad_owner: PadOwnerHolder, } pub struct TabletPadGroup { buttons: Vec, mode: Cell, modes: u32, rings: Vec, strips: Vec, dials: Vec, bindings: TabletBindings, } pub struct TabletPadStrip { bindings: TabletBindings, } pub struct TabletPadRing { bindings: TabletBindings, } pub struct TabletPadDial { bindings: TabletBindings, } #[derive(Copy, Clone, Debug)] pub enum TabletRingEventSource { Finger, } #[derive(Copy, Clone, Debug)] pub enum TabletStripEventSource { Finger, } #[derive(Debug, Default)] pub struct TabletToolChanges { pub down: Option, pub pos: Option>, pub pressure: Option, pub distance: Option, pub tilt: Option>, pub rotation: Option, pub slider: Option, pub wheel: Option, } #[derive(Copy, Clone, Debug)] pub struct TabletTool2dChange { pub x: T, pub y: T, } #[derive(Copy, Clone, Debug)] pub struct TabletToolPositionChange { pub x: f64, pub dx: f64, } #[derive(Copy, Clone, Debug)] pub struct TabletToolWheelChange { pub degrees: f64, pub clicks: i32, } impl WlSeatGlobal { fn tablet_add_seat(&self, seat: &Rc) { self.tablet.seats.add(&seat.client, seat); for tablet in self.tablet.tablets.lock().values() { seat.announce_tablet(tablet); } for tool in self.tablet.tools.lock().values() { seat.announce_tool(tool); } for pad in self.tablet.pads.lock().values() { seat.announce_pad(pad); } } pub fn tablet_add_tablet(self: &Rc, dev: InputDeviceId, init: &TabletInit) { let tablet = Rc::new(Tablet { _id: init.id, dev, group: init.group, name: init.name.clone(), pid: init.pid, vid: init.vid, bustype: init.bustype, path: init.path.clone(), bindings: Default::default(), tools: Default::default(), pads: Default::default(), tree: Default::default(), seat: self.clone(), }); self.tablet.tablets.set(init.id, tablet.clone()); self.tablet_for_each_seat_obj(|s| s.announce_tablet(&tablet)); for pad in self.tablet.pads.lock().values() { if pad.tablet.is_none() && pad.group == init.group { self.connect_tablet_and_pad(&tablet, pad); } } } fn tablet_for_each_seat_obj(&self, mut f: impl FnMut(&Rc)) { for seats in self.tablet.seats.borrow().values() { for seat in seats.values() { f(seat); } } } pub fn tablet_clear(&self) { self.tablet.seats.clear(); for tablet in self.tablet.tablets.lock().drain_values() { tablet.pads.clear(); tablet.bindings.clear(); tablet.tools.clear(); } for tool in self.tablet.tools.lock().drain_values() { tool.cursor.detach(); tool.opt.tool.take(); tool.tool_owner.destroy(&tool); tool.bindings.clear(); } for pad in self.tablet.pads.lock().drain_values() { pad.pad_owner.destroy(&pad); pad.tablet.take(); pad.bindings.clear(); for group in &pad.groups { group.bindings.clear(); } for rings in &pad.rings { rings.bindings.clear(); } for strips in &pad.strips { strips.bindings.clear(); } for dials in &pad.dials { dials.bindings.clear(); } } } pub fn tablet_remove_tablet(self: &Rc, id: TabletId) { let Some(tablet) = self.tablet.tablets.remove(&id) else { return; }; for tool in tablet.tools.lock().drain_values() { self.tablet_handle_remove_tool(tablet.seat.state.now_usec(), tool.id); } for pad in tablet.pads.lock().drain_values() { pad.pad_owner.destroy(&pad); pad.tablet.take(); } for binding in tablet.bindings.lock().drain_values() { binding.send_removed(); } } fn connect_tablet_and_pad(self: &Rc, tablet: &Rc, pad: &Rc) { pad.tablet.set(Some(tablet.clone())); tablet.pads.set(pad.id, pad.clone()); pad.pad_owner.update_node(pad); } pub fn tablet_on_keyboard_node_change(self: &Rc) { if self.tablet.pads.is_empty() { return; } for pad in self.tablet.pads.lock().values() { if pad.tablet.is_some() { pad.pad_owner.update_node(pad); } } } fn tablet_for_each_seat(&self, surface: &WlSurface, f: impl FnMut(&ZwpTabletSeatV2)) { self.tablet .seats .for_each(surface.client.id, Version::ALL, f) } pub(super) fn tablet_apply_changes(self: &Rc) { if self.tablet.tools.is_empty() { return; } let now = self.state.now_usec(); for tool in self.tablet.tools.lock().values() { tool.tool_owner.apply_changes(tool, now, None); } } } fn normalizei(n: f64) -> i32 { (65535.0 * n) as i32 } fn normalizeu(n: f64) -> u32 { normalizei(n) as u32 } impl TabletTool { pub fn cursor(&self) -> &Rc { &self.cursor } pub fn node(&self) -> Rc { self.node.get() } pub fn seat(&self) -> &Rc { &self.tablet.seat } }