use { crate::{ cursor::KnownCursor, fixed::Fixed, ifs::{ wl_seat::{ tablet::{ normalizei, normalizeu, zwp_tablet_tool_v2::ZwpTabletToolV2, zwp_tablet_v2::ZwpTabletV2, TabletTool, TabletToolChanges, TabletToolId, TabletToolInit, TabletToolOpt, TabletToolType, ToolButtonState, }, WlSeatGlobal, }, wl_surface::WlSurface, }, rect::Rect, time::usec_to_msec, utils::clonecell::CloneCell, }, std::{cell::Cell, rc::Rc}, }; impl WlSeatGlobal { pub fn tablet_handle_remove_tool(self: &Rc, time_usec: u64, id: TabletToolId) { let Some(tool) = self.tablet.tools.remove(&id) else { return; }; self.state.for_each_seat_tester(|t| { t.send_tablet_tool_proximity_out(self.id, tool.tablet.dev, tool.id, time_usec) }); tool.opt.tool.take(); tool.cursor.detach(); tool.tool_owner.destroy(&tool); for (_, binding) in tool.bindings.lock().drain() { binding.send_removed(); } tool.tablet.tools.remove(&id); } pub fn tablet_handle_new_tool(self: &Rc, time_usec: u64, init: &TabletToolInit) { let Some(tablet) = self.tablet.tablets.get(&init.tablet_id) else { return; }; let tool = Rc::new(TabletTool { id: init.id, opt: Default::default(), tablet, type_: init.type_, hardware_serial: init.hardware_serial, hardware_id_wacom: init.hardware_id_wacom, capabilities: init.capabilities.clone(), bindings: Default::default(), node: CloneCell::new(self.state.root.clone()), tool_owner: Default::default(), cursor: self.cursor_user_group.create_user(), down: Cell::new(false), pressure: Cell::new(0.0), distance: Cell::new(0.0), tilt_x: Cell::new(0.0), tilt_y: Cell::new(0.0), rotation: Cell::new(0.0), slider: Cell::new(0.0), }); tool.opt.tool.set(Some(tool.clone())); tool.cursor.set_known(KnownCursor::Default); self.tablet.tools.set(init.id, tool.clone()); self.state.for_each_seat_tester(|t| { t.send_tablet_tool_proximity_in(self.id, tool.tablet.dev, tool.id, time_usec) }); self.tablet_for_each_seat_obj(|s| s.announce_tool(&tool)); } pub fn tablet_event_tool_button( self: &Rc, id: TabletToolId, time_usec: u64, button: u32, state: ToolButtonState, ) { let Some(tool) = self.tablet.tools.get(&id) else { return; }; self.state.for_each_seat_tester(|t| { t.send_tablet_tool_button(self.id, tool.tablet.dev, &tool, time_usec, button, state); }); tool.cursor.activate(); tool.tool_owner.button(&tool, time_usec, button, state); } pub fn tablet_event_tool_changes( self: &Rc, id: TabletToolId, time_usec: u64, rect: Rect, changes: &TabletToolChanges, ) { let Some(tool) = self.tablet.tools.get(&id) else { return; }; self.state.for_each_seat_tester(|t| { t.send_tablet_tool_changes(self.id, tool.tablet.dev, &tool, time_usec, changes); }); if let Some(val) = changes.down { tool.down.set(val); } if let Some(val) = changes.pressure { tool.pressure.set(val); } if let Some(val) = changes.distance { tool.distance.set(val); } if let Some(val) = changes.tilt { tool.tilt_x.set(val.x); tool.tilt_y.set(val.y); } if let Some(val) = changes.rotation { tool.rotation.set(val); } if let Some(val) = changes.slider { tool.slider.set(val); } if let Some(delta) = changes.pos { let (x, y) = match tool.type_ { TabletToolType::Mouse | TabletToolType::Lens => { let (mut x, mut y) = tool.cursor.position(); x += Fixed::from_f64(delta.x.dx); y += Fixed::from_f64(delta.y.dx); (x, y) } TabletToolType::Pen | TabletToolType::Eraser | TabletToolType::Brush | TabletToolType::Pencil | TabletToolType::Airbrush | TabletToolType::Finger => { let x = Fixed::from_f64(rect.x1() as f64 + (rect.width() as f64 * delta.x.x)); let y = Fixed::from_f64(rect.y1() as f64 + (rect.height() as f64 * delta.y.x)); (x, y) } }; tool.cursor.set_position(x, y); } tool.cursor.activate(); tool.tool_owner .apply_changes(&tool, time_usec, Some(changes)); } } impl TabletTool { fn for_each_pair(&self, n: &WlSurface, mut f: impl FnMut(&ZwpTabletV2, &ZwpTabletToolV2)) { self.tablet.seat.tablet_for_each_seat(n, |s| { let Some(tablet) = self.tablet.bindings.get(s) else { return; }; let Some(tool) = self.bindings.get(s) else { return; }; f(&tablet, &tool); }) } fn for_each_entered(&self, n: &WlSurface, mut f: impl FnMut(&ZwpTabletToolV2)) { self.tablet.seat.tablet_for_each_seat(n, |s| { let Some(tool) = self.bindings.get(s) else { return; }; if !tool.entered.get() { return; } f(&tool); }) } pub fn surface_leave(&self, n: &WlSurface, time_usec: u64) { let time = usec_to_msec(time_usec); self.for_each_entered(n, |t| { t.send_proximity_out(); t.send_frame(time); }) } pub fn surface_enter(&self, n: &WlSurface, time_usec: u64, x: Fixed, y: Fixed) { let time = usec_to_msec(time_usec); let mut serial = n.client.pending_serial(); self.for_each_pair(n, |tablet, tool| { tool.send_proximity_in(serial.get(), tablet, n); tool.send_motion(x, y); tool.send_pressure(normalizeu(self.pressure.get())); tool.send_distance(normalizeu(self.distance.get())); tool.send_tilt( Fixed::from_f64(self.tilt_x.get()), Fixed::from_f64(self.tilt_y.get()), ); tool.send_rotation(Fixed::from_f64(self.rotation.get())); tool.send_slider(normalizei(self.slider.get())); tool.send_frame(time); }) } pub fn surface_button( &self, n: &WlSurface, time_usec: u64, button: u32, state: ToolButtonState, ) { let time = usec_to_msec(time_usec); let mut serial = n.client.pending_serial(); self.for_each_entered(n, |tool| { tool.send_button(serial.get(), button, state); tool.send_frame(time); }); if state == ToolButtonState::Pressed { if let Some(node) = n.get_focus_node(self.tablet.seat.id) { self.tablet.seat.focus_node(node); } } } pub fn surface_apply_changes( &self, n: &WlSurface, time_usec: u64, changes: Option<&TabletToolChanges>, x: Fixed, y: Fixed, ) { let mut serial = n.client.pending_serial(); let time = usec_to_msec(time_usec); self.for_each_entered(n, |tool| { if let Some(changes) = changes { if let Some(val) = changes.down { match val { false => tool.send_up(), true => tool.send_down(serial.get()), } } if let Some(val) = changes.pressure { tool.send_pressure(normalizeu(val)); } if let Some(val) = changes.distance { tool.send_distance(normalizeu(val)); } if let Some(val) = changes.tilt { tool.send_tilt(Fixed::from_f64(val.x), Fixed::from_f64(val.y)); } if let Some(val) = changes.rotation { tool.send_rotation(Fixed::from_f64(val)); } if let Some(val) = changes.slider { tool.send_slider(normalizei(val)); } if let Some(val) = changes.wheel { tool.send_wheel(Fixed::from_f64(val.degrees), val.clicks); } } tool.send_motion(x, y); tool.send_frame(time); }); if let Some(changes) = changes { if changes.down == Some(true) { if let Some(node) = n.get_focus_node(self.tablet.seat.id) { self.tablet.seat.focus_node(node); } } } } } impl TabletToolOpt { pub fn get(&self) -> Option> { self.tool.get() } }