wayland: implement tablet-v2
This commit is contained in:
parent
86e283d255
commit
7ed499eabd
62 changed files with 5174 additions and 318 deletions
|
|
@ -3,7 +3,14 @@ use {
|
|||
backend::{InputDeviceId, KeyState},
|
||||
client::Client,
|
||||
fixed::Fixed,
|
||||
ifs::wl_seat::{wl_pointer::PendingScroll, SeatId},
|
||||
ifs::wl_seat::{
|
||||
tablet::{
|
||||
PadButtonState, TabletRingEventSource, TabletStripEventSource, TabletTool,
|
||||
TabletToolChanges, TabletToolId, ToolButtonState,
|
||||
},
|
||||
wl_pointer::PendingScroll,
|
||||
SeatId,
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
wire::{jay_seat_events::*, JaySeatEventsId},
|
||||
|
|
@ -236,6 +243,231 @@ impl JaySeatEvents {
|
|||
event: event as _,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_tablet_tool_proximity_in(
|
||||
&self,
|
||||
seat: SeatId,
|
||||
tablet: InputDeviceId,
|
||||
tool: TabletToolId,
|
||||
time_usec: u64,
|
||||
) {
|
||||
self.client
|
||||
.event(TabletToolProximityIn { self_id: self.id });
|
||||
self.client.event(TabletToolFrame {
|
||||
self_id: self.id,
|
||||
seat: seat.raw(),
|
||||
time_usec,
|
||||
input_device: tablet.raw(),
|
||||
tool: tool.raw() as _,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_tablet_tool_proximity_out(
|
||||
&self,
|
||||
seat: SeatId,
|
||||
tablet: InputDeviceId,
|
||||
tool: TabletToolId,
|
||||
time_usec: u64,
|
||||
) {
|
||||
self.client
|
||||
.event(TabletToolProximityOut { self_id: self.id });
|
||||
self.client.event(TabletToolFrame {
|
||||
self_id: self.id,
|
||||
seat: seat.raw(),
|
||||
time_usec,
|
||||
input_device: tablet.raw(),
|
||||
tool: tool.raw() as _,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_tablet_tool_changes(
|
||||
&self,
|
||||
seat: SeatId,
|
||||
tablet: InputDeviceId,
|
||||
tool: &TabletTool,
|
||||
time_usec: u64,
|
||||
changes: &TabletToolChanges,
|
||||
) {
|
||||
let self_id = self.id;
|
||||
if let Some(down) = changes.down {
|
||||
match down {
|
||||
true => self.client.event(TabletToolDown { self_id }),
|
||||
false => self.client.event(TabletToolUp { self_id }),
|
||||
}
|
||||
}
|
||||
if changes.pos.is_some() {
|
||||
let (x, y) = tool.cursor().position();
|
||||
self.client.event(TabletToolMotion { self_id, x, y });
|
||||
}
|
||||
if let Some(val) = changes.pressure {
|
||||
self.client.event(TabletToolPressure {
|
||||
self_id,
|
||||
pressure: val,
|
||||
});
|
||||
}
|
||||
if let Some(val) = changes.distance {
|
||||
self.client.event(TabletToolDistance {
|
||||
self_id,
|
||||
distance: val,
|
||||
});
|
||||
}
|
||||
if let Some(val) = changes.tilt {
|
||||
self.client.event(TabletToolTilt {
|
||||
self_id,
|
||||
tilt_x: val.x,
|
||||
tilt_y: val.y,
|
||||
});
|
||||
}
|
||||
if let Some(val) = changes.rotation {
|
||||
self.client.event(TabletToolRotation {
|
||||
self_id,
|
||||
degrees: val,
|
||||
});
|
||||
}
|
||||
if let Some(val) = changes.slider {
|
||||
self.client.event(TabletToolSlider {
|
||||
self_id,
|
||||
position: val,
|
||||
});
|
||||
}
|
||||
if let Some(val) = changes.wheel {
|
||||
self.client.event(TabletToolWheel {
|
||||
self_id,
|
||||
degrees: val.degrees,
|
||||
clicks: val.clicks,
|
||||
});
|
||||
}
|
||||
self.client.event(TabletToolFrame {
|
||||
self_id: self.id,
|
||||
seat: seat.raw(),
|
||||
time_usec,
|
||||
input_device: tablet.raw(),
|
||||
tool: tool.id.raw() as _,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_tablet_tool_button(
|
||||
&self,
|
||||
seat: SeatId,
|
||||
tablet: InputDeviceId,
|
||||
tool: &TabletTool,
|
||||
time_usec: u64,
|
||||
button: u32,
|
||||
state: ToolButtonState,
|
||||
) {
|
||||
self.client.event(TabletToolButton {
|
||||
self_id: self.id,
|
||||
button,
|
||||
state: state as _,
|
||||
});
|
||||
self.client.event(TabletToolFrame {
|
||||
self_id: self.id,
|
||||
seat: seat.raw(),
|
||||
time_usec,
|
||||
input_device: tablet.raw(),
|
||||
tool: tool.id.raw() as _,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_tablet_pad_mode_switch(
|
||||
&self,
|
||||
seat: SeatId,
|
||||
pad: InputDeviceId,
|
||||
time_usec: u64,
|
||||
group: u32,
|
||||
mode: u32,
|
||||
) {
|
||||
self.client.event(TabletPadModeSwitch {
|
||||
self_id: self.id,
|
||||
seat: seat.raw(),
|
||||
time_usec,
|
||||
input_device: pad.raw(),
|
||||
group,
|
||||
mode,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_tablet_pad_button(
|
||||
&self,
|
||||
seat: SeatId,
|
||||
pad: InputDeviceId,
|
||||
time_usec: u64,
|
||||
button: u32,
|
||||
state: PadButtonState,
|
||||
) {
|
||||
self.client.event(TabletPadButton {
|
||||
self_id: self.id,
|
||||
seat: seat.raw(),
|
||||
time_usec,
|
||||
input_device: pad.raw(),
|
||||
button,
|
||||
state: state as _,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_tablet_pad_strip(
|
||||
&self,
|
||||
seat: SeatId,
|
||||
pad: InputDeviceId,
|
||||
time_usec: u64,
|
||||
strip: u32,
|
||||
source: Option<TabletStripEventSource>,
|
||||
position: Option<f64>,
|
||||
) {
|
||||
if let Some(source) = source {
|
||||
self.client.event(TabletPadStripSource {
|
||||
self_id: self.id,
|
||||
source: source as _,
|
||||
});
|
||||
}
|
||||
if let Some(position) = position {
|
||||
self.client.event(TabletPadStripPosition {
|
||||
self_id: self.id,
|
||||
position,
|
||||
});
|
||||
} else {
|
||||
self.client.event(TabletPadStripStop { self_id: self.id });
|
||||
}
|
||||
self.client.event(TabletPadStripFrame {
|
||||
self_id: self.id,
|
||||
seat: seat.raw(),
|
||||
time_usec,
|
||||
input_device: pad.raw(),
|
||||
strip,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_tablet_pad_ring(
|
||||
&self,
|
||||
seat: SeatId,
|
||||
pad: InputDeviceId,
|
||||
time_usec: u64,
|
||||
ring: u32,
|
||||
source: Option<TabletRingEventSource>,
|
||||
degrees: Option<f64>,
|
||||
) {
|
||||
if let Some(source) = source {
|
||||
self.client.event(TabletPadRingSource {
|
||||
self_id: self.id,
|
||||
source: source as _,
|
||||
});
|
||||
}
|
||||
if let Some(degrees) = degrees {
|
||||
self.client.event(TabletPadRingAngle {
|
||||
self_id: self.id,
|
||||
degrees,
|
||||
});
|
||||
} else {
|
||||
self.client.event(TabletPadRingStop { self_id: self.id });
|
||||
}
|
||||
self.client.event(TabletPadRingFrame {
|
||||
self_id: self.id,
|
||||
seat: seat.raw(),
|
||||
time_usec,
|
||||
input_device: pad.raw(),
|
||||
ring,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl JaySeatEventsRequestHandler for JaySeatEvents {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ pub mod ext_transient_seat_v1;
|
|||
mod gesture_owner;
|
||||
mod kb_owner;
|
||||
mod pointer_owner;
|
||||
pub mod tablet;
|
||||
pub mod text_input;
|
||||
pub mod wl_keyboard;
|
||||
pub mod wl_pointer;
|
||||
|
|
@ -46,6 +47,7 @@ use {
|
|||
gesture_owner::GestureOwnerHolder,
|
||||
kb_owner::KbOwnerHolder,
|
||||
pointer_owner::PointerOwnerHolder,
|
||||
tablet::TabletSeatData,
|
||||
text_input::{
|
||||
zwp_input_method_keyboard_grab_v2::ZwpInputMethodKeyboardGrabV2,
|
||||
zwp_input_method_v2::ZwpInputMethodV2, zwp_text_input_v3::ZwpTextInputV3,
|
||||
|
|
@ -64,6 +66,7 @@ use {
|
|||
},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
rect::Rect,
|
||||
state::{DeviceHandlerData, State},
|
||||
time::now_usec,
|
||||
tree::{
|
||||
|
|
@ -188,6 +191,7 @@ pub struct WlSeatGlobal {
|
|||
swipe_bindings: PerClientBindings<ZwpPointerGestureSwipeV1>,
|
||||
pinch_bindings: PerClientBindings<ZwpPointerGesturePinchV1>,
|
||||
hold_bindings: PerClientBindings<ZwpPointerGestureHoldV1>,
|
||||
tablet: TabletSeatData,
|
||||
}
|
||||
|
||||
const CHANGE_CURSOR_MOVED: u32 = 1 << 0;
|
||||
|
|
@ -252,6 +256,7 @@ impl WlSeatGlobal {
|
|||
swipe_bindings: Default::default(),
|
||||
pinch_bindings: Default::default(),
|
||||
hold_bindings: Default::default(),
|
||||
tablet: Default::default(),
|
||||
});
|
||||
slf.pointer_cursor.set_owner(slf.clone());
|
||||
let seat = slf.clone();
|
||||
|
|
@ -861,6 +866,7 @@ impl WlSeatGlobal {
|
|||
self.pinch_bindings.clear();
|
||||
self.hold_bindings.clear();
|
||||
self.cursor_user_group.detach();
|
||||
self.tablet_clear();
|
||||
}
|
||||
|
||||
pub fn id(&self) -> SeatId {
|
||||
|
|
@ -1122,7 +1128,7 @@ impl DeviceHandlerData {
|
|||
pub fn set_seat(&self, seat: Option<Rc<WlSeatGlobal>>) {
|
||||
let old = self.seat.set(seat.clone());
|
||||
if let Some(old) = old {
|
||||
if let Some(new) = seat {
|
||||
if let Some(new) = &seat {
|
||||
if old.id() == new.id() {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1131,8 +1137,22 @@ impl DeviceHandlerData {
|
|||
let xkb_state = &mut *xkb_state.borrow_mut();
|
||||
xkb_state.reset();
|
||||
old.handle_xkb_state_change(xkb_state, xkb_state);
|
||||
if let Some(info) = &self.tablet_init {
|
||||
old.tablet_remove_tablet(info.id);
|
||||
}
|
||||
if let Some(info) = &self.tablet_pad_init {
|
||||
old.tablet_remove_tablet_pad(info.id);
|
||||
}
|
||||
}
|
||||
self.update_xkb_state();
|
||||
if let Some(seat) = &seat {
|
||||
if let Some(info) = &self.tablet_init {
|
||||
seat.tablet_add_tablet(self.device.id(), info);
|
||||
}
|
||||
if let Some(info) = &self.tablet_pad_init {
|
||||
seat.tablet_add_tablet_pad(self.device.id(), info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_keymap(&self, keymap: Option<Rc<XkbKeymap>>) {
|
||||
|
|
@ -1177,4 +1197,13 @@ impl DeviceHandlerData {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_rect(&self, state: &State) -> Rect {
|
||||
if let Some(output) = self.output.get() {
|
||||
if let Some(output) = output.get() {
|
||||
return output.pos.get();
|
||||
}
|
||||
}
|
||||
state.root.extents.get()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use {
|
|||
DynDataSource,
|
||||
},
|
||||
wl_seat::{
|
||||
tablet::{TabletPad, TabletPadId, TabletTool, TabletToolId},
|
||||
text_input::TextDisconnectReason,
|
||||
wl_keyboard::{self, WlKeyboard},
|
||||
wl_pointer::{
|
||||
|
|
@ -25,7 +26,7 @@ use {
|
|||
},
|
||||
zwp_pointer_constraints_v1::{ConstraintType, SeatConstraintStatus},
|
||||
zwp_relative_pointer_v1::ZwpRelativePointerV1,
|
||||
Dnd, SeatId, WlSeat, WlSeatGlobal, CHANGE_CURSOR_MOVED,
|
||||
Dnd, SeatId, WlSeat, WlSeatGlobal, CHANGE_CURSOR_MOVED, CHANGE_TREE,
|
||||
},
|
||||
wl_surface::{xdg_surface::xdg_popup::XdgPopup, WlSurface},
|
||||
},
|
||||
|
|
@ -55,6 +56,8 @@ pub struct NodeSeatState {
|
|||
gesture_foci: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
||||
pointer_grabs: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
||||
dnd_targets: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
||||
tablet_pad_foci: SmallMap<TabletPadId, Rc<TabletPad>, 1>,
|
||||
tablet_tool_foci: SmallMap<TabletToolId, Rc<TabletTool>, 1>,
|
||||
}
|
||||
|
||||
impl NodeSeatState {
|
||||
|
|
@ -92,6 +95,22 @@ impl NodeSeatState {
|
|||
self.pointer_grabs.remove(&seat.id);
|
||||
}
|
||||
|
||||
pub(super) fn add_tablet_pad_focus(&self, pad: &Rc<TabletPad>) {
|
||||
self.tablet_pad_foci.insert(pad.id, pad.clone());
|
||||
}
|
||||
|
||||
pub(super) fn remove_tablet_pad_focus(&self, pad: &TabletPad) {
|
||||
self.tablet_pad_foci.remove(&pad.id);
|
||||
}
|
||||
|
||||
pub(super) fn add_tablet_tool_focus(&self, tool: &Rc<TabletTool>) {
|
||||
self.tablet_tool_foci.insert(tool.id, tool.clone());
|
||||
}
|
||||
|
||||
pub(super) fn remove_tablet_tool_focus(&self, tool: &TabletTool) {
|
||||
self.tablet_tool_foci.remove(&tool.id);
|
||||
}
|
||||
|
||||
pub(super) fn add_dnd_target(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
self.dnd_targets.insert(seat.id, seat.clone());
|
||||
}
|
||||
|
|
@ -163,6 +182,12 @@ impl NodeSeatState {
|
|||
seat.pointer_stack_modified.set(true);
|
||||
seat.state.tree_changed();
|
||||
}
|
||||
while let Some((_, tool)) = self.tablet_tool_foci.pop() {
|
||||
tool.tool_owner.focus_root(&tool);
|
||||
}
|
||||
while let Some((_, pad)) = self.tablet_pad_foci.pop() {
|
||||
pad.pad_owner.focus_root(&pad);
|
||||
}
|
||||
self.release_kb_focus2(focus_last);
|
||||
}
|
||||
|
||||
|
|
@ -203,7 +228,13 @@ impl WlSeatGlobal {
|
|||
| InputEvent::PinchEnd { time_usec, .. }
|
||||
| InputEvent::HoldBegin { time_usec, .. }
|
||||
| InputEvent::HoldEnd { time_usec, .. }
|
||||
| InputEvent::SwitchEvent { time_usec, .. } => {
|
||||
| InputEvent::SwitchEvent { time_usec, .. }
|
||||
| InputEvent::TabletToolChanged { time_usec, .. }
|
||||
| InputEvent::TabletToolButton { time_usec, .. }
|
||||
| InputEvent::TabletPadButton { time_usec, .. }
|
||||
| InputEvent::TabletPadModeSwitch { time_usec, .. }
|
||||
| InputEvent::TabletPadRing { time_usec, .. }
|
||||
| InputEvent::TabletPadStrip { time_usec, .. } => {
|
||||
self.last_input_usec.set(time_usec);
|
||||
if self.idle_notifications.is_not_empty() {
|
||||
for (_, notification) in self.idle_notifications.lock().drain() {
|
||||
|
|
@ -214,7 +245,39 @@ impl WlSeatGlobal {
|
|||
InputEvent::AxisPx { .. }
|
||||
| InputEvent::AxisSource { .. }
|
||||
| InputEvent::AxisStop { .. }
|
||||
| InputEvent::Axis120 { .. } => {}
|
||||
| InputEvent::Axis120 { .. }
|
||||
| InputEvent::TabletToolAdded { .. }
|
||||
| InputEvent::TabletToolRemoved { .. } => {}
|
||||
}
|
||||
match event {
|
||||
InputEvent::ConnectorPosition { .. }
|
||||
| InputEvent::Motion { .. }
|
||||
| InputEvent::Button { .. }
|
||||
| InputEvent::AxisFrame { .. }
|
||||
| InputEvent::SwipeBegin { .. }
|
||||
| InputEvent::SwipeUpdate { .. }
|
||||
| InputEvent::SwipeEnd { .. }
|
||||
| InputEvent::PinchBegin { .. }
|
||||
| InputEvent::PinchUpdate { .. }
|
||||
| InputEvent::PinchEnd { .. }
|
||||
| InputEvent::HoldBegin { .. }
|
||||
| InputEvent::HoldEnd { .. } => {
|
||||
self.pointer_cursor.activate();
|
||||
}
|
||||
InputEvent::Key { .. } => {}
|
||||
InputEvent::AxisPx { .. } => {}
|
||||
InputEvent::AxisSource { .. } => {}
|
||||
InputEvent::AxisStop { .. } => {}
|
||||
InputEvent::Axis120 { .. } => {}
|
||||
InputEvent::SwitchEvent { .. } => {}
|
||||
InputEvent::TabletToolAdded { .. } => {}
|
||||
InputEvent::TabletToolChanged { .. } => {}
|
||||
InputEvent::TabletToolButton { .. } => {}
|
||||
InputEvent::TabletToolRemoved { .. } => {}
|
||||
InputEvent::TabletPadButton { .. } => {}
|
||||
InputEvent::TabletPadModeSwitch { .. } => {}
|
||||
InputEvent::TabletPadRing { .. } => {}
|
||||
InputEvent::TabletPadStrip { .. } => {}
|
||||
}
|
||||
match event {
|
||||
InputEvent::Key {
|
||||
|
|
@ -305,6 +368,49 @@ impl WlSeatGlobal {
|
|||
InputEvent::SwitchEvent { time_usec, event } => {
|
||||
self.switch_event(dev.device.id(), time_usec, event)
|
||||
}
|
||||
InputEvent::TabletToolAdded { time_usec, init } => {
|
||||
self.tablet_handle_new_tool(time_usec, &init)
|
||||
}
|
||||
InputEvent::TabletToolChanged {
|
||||
time_usec,
|
||||
id,
|
||||
changes: change,
|
||||
} => self.tablet_event_tool_changes(id, time_usec, dev.get_rect(&self.state), &change),
|
||||
InputEvent::TabletToolButton {
|
||||
time_usec,
|
||||
id,
|
||||
button,
|
||||
state,
|
||||
} => self.tablet_event_tool_button(id, time_usec, button, state),
|
||||
InputEvent::TabletToolRemoved { time_usec, id } => {
|
||||
self.tablet_handle_remove_tool(time_usec, id)
|
||||
}
|
||||
InputEvent::TabletPadButton {
|
||||
time_usec,
|
||||
id,
|
||||
button,
|
||||
state,
|
||||
} => self.tablet_event_pad_button(id, time_usec, button, state),
|
||||
InputEvent::TabletPadModeSwitch {
|
||||
time_usec,
|
||||
pad,
|
||||
group,
|
||||
mode,
|
||||
} => self.tablet_event_pad_mode_switch(pad, time_usec, group, mode),
|
||||
InputEvent::TabletPadRing {
|
||||
time_usec,
|
||||
pad,
|
||||
ring,
|
||||
source,
|
||||
angle,
|
||||
} => self.tablet_event_pad_ring(pad, ring, source, angle, time_usec),
|
||||
InputEvent::TabletPadStrip {
|
||||
time_usec,
|
||||
pad,
|
||||
strip,
|
||||
source,
|
||||
position,
|
||||
} => self.tablet_event_pad_strip(pad, strip, source, position, time_usec),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -784,6 +890,9 @@ impl WlSeatGlobal {
|
|||
pub(super) fn apply_changes(self: &Rc<Self>) {
|
||||
self.state.damage();
|
||||
self.pointer_owner.apply_changes(self);
|
||||
if self.changes.get().contains(CHANGE_TREE) {
|
||||
self.tablet_apply_changes();
|
||||
}
|
||||
self.changes.set(0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ impl KbOwner for DefaultKbOwner {
|
|||
// log::info!("focus {}", node.node_id());
|
||||
node.clone().node_on_focus(seat);
|
||||
seat.keyboard_node.set(node.clone());
|
||||
seat.tablet_on_keyboard_node_change();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
393
src/ifs/wl_seat/tablet.rs
Normal file
393
src/ifs/wl_seat/tablet.rs
Normal file
|
|
@ -0,0 +1,393 @@
|
|||
use {
|
||||
crate::{
|
||||
backend::{InputDeviceGroupId, InputDeviceId},
|
||||
cursor_user::CursorUser,
|
||||
ifs::{
|
||||
wl_seat::{
|
||||
tablet::{
|
||||
pad_owner::PadOwnerHolder, tablet_bindings::TabletBindings,
|
||||
tool_owner::ToolOwnerHolder, 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,
|
||||
},
|
||||
WlSeatGlobal,
|
||||
},
|
||||
wl_surface::WlSurface,
|
||||
},
|
||||
object::Version,
|
||||
time::now_usec,
|
||||
tree::{FoundNode, Node},
|
||||
utils::{bindings::PerClientBindings, clonecell::CloneCell, copyhashmap::CopyHashMap},
|
||||
},
|
||||
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_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<ZwpTabletSeatV2>,
|
||||
tablets: CopyHashMap<TabletId, Rc<Tablet>>,
|
||||
tools: CopyHashMap<TabletToolId, Rc<TabletTool>>,
|
||||
pads: CopyHashMap<TabletPadId, Rc<TabletPad>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TabletInit {
|
||||
pub id: TabletId,
|
||||
pub group: InputDeviceGroupId,
|
||||
pub name: String,
|
||||
pub pid: u32,
|
||||
pub vid: u32,
|
||||
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<TabletToolCapability>,
|
||||
}
|
||||
|
||||
#[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 groups: Vec<TabletPadGroupInit>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TabletPadGroupInit {
|
||||
pub buttons: Vec<u32>,
|
||||
pub rings: Vec<u32>,
|
||||
pub strips: Vec<u32>,
|
||||
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,
|
||||
path: String,
|
||||
bindings: TabletBindings<ZwpTabletV2>,
|
||||
tools: CopyHashMap<TabletToolId, Rc<TabletTool>>,
|
||||
pads: CopyHashMap<TabletPadId, Rc<TabletPad>>,
|
||||
tree: RefCell<Vec<FoundNode>>,
|
||||
seat: Rc<WlSeatGlobal>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum TabletToolType {
|
||||
Pen,
|
||||
Eraser,
|
||||
Brush,
|
||||
Pencil,
|
||||
Airbrush,
|
||||
#[allow(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<Option<Rc<TabletTool>>>,
|
||||
}
|
||||
|
||||
pub struct TabletTool {
|
||||
pub id: TabletToolId,
|
||||
opt: Rc<TabletToolOpt>,
|
||||
tablet: Rc<Tablet>,
|
||||
type_: TabletToolType,
|
||||
hardware_serial: u64,
|
||||
hardware_id_wacom: u64,
|
||||
capabilities: Vec<TabletToolCapability>,
|
||||
bindings: TabletBindings<ZwpTabletToolV2>,
|
||||
node: CloneCell<Rc<dyn Node>>,
|
||||
pub(super) tool_owner: ToolOwnerHolder,
|
||||
cursor: Rc<CursorUser>,
|
||||
|
||||
down: Cell<bool>,
|
||||
pressure: Cell<f64>,
|
||||
distance: Cell<f64>,
|
||||
tilt_x: Cell<f64>,
|
||||
tilt_y: Cell<f64>,
|
||||
rotation: Cell<f64>,
|
||||
slider: Cell<f64>,
|
||||
}
|
||||
|
||||
linear_ids!(TabletPadIds, TabletPadId);
|
||||
|
||||
pub struct TabletPad {
|
||||
pub id: TabletPadId,
|
||||
dev: InputDeviceId,
|
||||
seat: Rc<WlSeatGlobal>,
|
||||
group: InputDeviceGroupId,
|
||||
tablet: CloneCell<Option<Rc<Tablet>>>,
|
||||
path: String,
|
||||
buttons: u32,
|
||||
bindings: TabletBindings<ZwpTabletPadV2>,
|
||||
groups: Vec<Rc<TabletPadGroup>>,
|
||||
strips: Vec<Rc<TabletPadStrip>>,
|
||||
rings: Vec<Rc<TabletPadRing>>,
|
||||
node: CloneCell<Rc<dyn Node>>,
|
||||
pub(super) pad_owner: PadOwnerHolder,
|
||||
}
|
||||
|
||||
pub struct TabletPadGroup {
|
||||
buttons: Vec<u32>,
|
||||
mode: Cell<u32>,
|
||||
modes: u32,
|
||||
rings: Vec<u32>,
|
||||
strips: Vec<u32>,
|
||||
bindings: TabletBindings<ZwpTabletPadGroupV2>,
|
||||
}
|
||||
|
||||
pub struct TabletPadStrip {
|
||||
bindings: TabletBindings<ZwpTabletPadStripV2>,
|
||||
}
|
||||
|
||||
pub struct TabletPadRing {
|
||||
bindings: TabletBindings<ZwpTabletPadRingV2>,
|
||||
}
|
||||
|
||||
#[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<bool>,
|
||||
pub pos: Option<TabletTool2dChange<TabletToolPositionChange>>,
|
||||
pub pressure: Option<f64>,
|
||||
pub distance: Option<f64>,
|
||||
pub tilt: Option<TabletTool2dChange<f64>>,
|
||||
pub rotation: Option<f64>,
|
||||
pub slider: Option<f64>,
|
||||
pub wheel: Option<TabletToolWheelChange>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct TabletTool2dChange<T> {
|
||||
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<ZwpTabletSeatV2>) {
|
||||
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<Self>, 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,
|
||||
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<ZwpTabletSeatV2>)) {
|
||||
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() {
|
||||
tablet.pads.clear();
|
||||
tablet.bindings.clear();
|
||||
tablet.tools.clear();
|
||||
}
|
||||
for (_, tool) in self.tablet.tools.lock().drain() {
|
||||
tool.cursor.detach();
|
||||
tool.opt.tool.take();
|
||||
tool.tool_owner.destroy(&tool);
|
||||
tool.bindings.clear();
|
||||
}
|
||||
for (_, pad) in self.tablet.pads.lock().drain() {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tablet_remove_tablet(self: &Rc<Self>, id: TabletId) {
|
||||
let Some(tablet) = self.tablet.tablets.remove(&id) else {
|
||||
return;
|
||||
};
|
||||
for (_, tool) in tablet.tools.lock().drain() {
|
||||
self.tablet_handle_remove_tool(now_usec(), tool.id);
|
||||
}
|
||||
for (_, pad) in tablet.pads.lock().drain() {
|
||||
pad.pad_owner.destroy(&pad);
|
||||
pad.tablet.take();
|
||||
}
|
||||
for (_, binding) in tablet.bindings.lock().drain() {
|
||||
binding.send_removed();
|
||||
}
|
||||
}
|
||||
|
||||
fn connect_tablet_and_pad(self: &Rc<Self>, tablet: &Rc<Tablet>, pad: &Rc<TabletPad>) {
|
||||
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<Self>) {
|
||||
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<Self>) {
|
||||
if self.tablet.tools.is_empty() {
|
||||
return;
|
||||
}
|
||||
let now = 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<CursorUser> {
|
||||
&self.cursor
|
||||
}
|
||||
|
||||
pub fn node(&self) -> Rc<dyn Node> {
|
||||
self.node.get()
|
||||
}
|
||||
|
||||
pub fn seat(&self) -> &Rc<WlSeatGlobal> {
|
||||
&self.tablet.seat
|
||||
}
|
||||
}
|
||||
290
src/ifs/wl_seat/tablet/pad.rs
Normal file
290
src/ifs/wl_seat/tablet/pad.rs
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
use {
|
||||
crate::{
|
||||
backend::InputDeviceId,
|
||||
fixed::Fixed,
|
||||
ifs::{
|
||||
wl_seat::{
|
||||
tablet::{
|
||||
normalizeu, zwp_tablet_pad_v2::ZwpTabletPadV2, zwp_tablet_v2::ZwpTabletV2,
|
||||
PadButtonState, TabletPad, TabletPadGroup, TabletPadId, TabletPadInit,
|
||||
TabletPadRing, TabletPadStrip, TabletRingEventSource, TabletStripEventSource,
|
||||
},
|
||||
WlSeatGlobal,
|
||||
},
|
||||
wl_surface::WlSurface,
|
||||
},
|
||||
time::{now_usec, usec_to_msec},
|
||||
utils::clonecell::CloneCell,
|
||||
},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
};
|
||||
|
||||
impl WlSeatGlobal {
|
||||
pub fn tablet_add_tablet_pad(self: &Rc<Self>, dev: InputDeviceId, init: &TabletPadInit) {
|
||||
let mut strips = Vec::new();
|
||||
for _ in 0..init.strips {
|
||||
strips.push(Rc::new(TabletPadStrip {
|
||||
bindings: Default::default(),
|
||||
}));
|
||||
}
|
||||
let mut rings = Vec::new();
|
||||
for _ in 0..init.rings {
|
||||
rings.push(Rc::new(TabletPadRing {
|
||||
bindings: Default::default(),
|
||||
}));
|
||||
}
|
||||
let mut groups = Vec::new();
|
||||
for group_init in &init.groups {
|
||||
groups.push(Rc::new(TabletPadGroup {
|
||||
buttons: group_init.buttons.clone(),
|
||||
mode: Cell::new(group_init.mode),
|
||||
modes: group_init.modes,
|
||||
rings: group_init.rings.clone(),
|
||||
strips: group_init.strips.clone(),
|
||||
bindings: Default::default(),
|
||||
}));
|
||||
}
|
||||
let pad = Rc::new(TabletPad {
|
||||
id: init.id,
|
||||
dev,
|
||||
seat: self.clone(),
|
||||
group: init.group,
|
||||
tablet: Default::default(),
|
||||
path: init.path.clone(),
|
||||
buttons: init.buttons,
|
||||
bindings: Default::default(),
|
||||
groups,
|
||||
strips,
|
||||
rings,
|
||||
node: CloneCell::new(self.state.root.clone()),
|
||||
pad_owner: Default::default(),
|
||||
});
|
||||
self.tablet.pads.set(init.id, pad.clone());
|
||||
self.tablet_for_each_seat_obj(|s| s.announce_pad(&pad));
|
||||
for tablet in self.tablet.tablets.lock().values() {
|
||||
if tablet.group == init.group {
|
||||
self.connect_tablet_and_pad(tablet, &pad);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tablet_remove_tablet_pad(self: &Rc<Self>, id: TabletPadId) {
|
||||
let Some(pad) = self.tablet.pads.remove(&id) else {
|
||||
return;
|
||||
};
|
||||
pad.pad_owner.destroy(&pad);
|
||||
if let Some(tablet) = pad.tablet.take() {
|
||||
tablet.pads.remove(&pad.id);
|
||||
}
|
||||
for (_, binding) in pad.bindings.lock().drain() {
|
||||
binding.send_removed();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tablet_event_pad_mode_switch(
|
||||
self: &Rc<Self>,
|
||||
pad: TabletPadId,
|
||||
time_usec: u64,
|
||||
group_idx: u32,
|
||||
mode: u32,
|
||||
) {
|
||||
if let Some(pad) = self.tablet.pads.get(&pad) {
|
||||
if let Some(group) = pad.groups.get(group_idx as usize) {
|
||||
if group.mode.replace(mode) != mode {
|
||||
self.state.for_each_seat_tester(|t| {
|
||||
t.send_tablet_pad_mode_switch(self.id, pad.dev, time_usec, group_idx, mode)
|
||||
});
|
||||
if pad.tablet.is_some() {
|
||||
let node = pad.node.get();
|
||||
node.node_on_tablet_pad_mode_switch(&pad, group, time_usec, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tablet_event_pad_button(
|
||||
self: &Rc<Self>,
|
||||
pad: TabletPadId,
|
||||
time_usec: u64,
|
||||
button: u32,
|
||||
state: PadButtonState,
|
||||
) {
|
||||
if let Some(pad) = self.tablet.pads.get(&pad) {
|
||||
self.state.for_each_seat_tester(|t| {
|
||||
t.send_tablet_pad_button(self.id, pad.dev, time_usec, button, state)
|
||||
});
|
||||
if pad.tablet.is_some() {
|
||||
pad.pad_owner.button(&pad, time_usec, button, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tablet_event_pad_ring(
|
||||
self: &Rc<Self>,
|
||||
pad: TabletPadId,
|
||||
ring: u32,
|
||||
source: Option<TabletRingEventSource>,
|
||||
angle: Option<f64>,
|
||||
time_usec: u64,
|
||||
) {
|
||||
if let Some(pad) = self.tablet.pads.get(&pad) {
|
||||
self.state.for_each_seat_tester(|t| {
|
||||
t.send_tablet_pad_ring(self.id, pad.dev, time_usec, ring, source, angle)
|
||||
});
|
||||
if pad.tablet.is_some() {
|
||||
if let Some(ring) = pad.rings.get(ring as usize) {
|
||||
let node = self.keyboard_node.get();
|
||||
node.node_on_tablet_pad_ring(&pad, ring, source, angle, time_usec);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tablet_event_pad_strip(
|
||||
self: &Rc<Self>,
|
||||
pad: TabletPadId,
|
||||
strip: u32,
|
||||
source: Option<TabletStripEventSource>,
|
||||
position: Option<f64>,
|
||||
time_usec: u64,
|
||||
) {
|
||||
if let Some(pad) = self.tablet.pads.get(&pad) {
|
||||
self.state.for_each_seat_tester(|t| {
|
||||
t.send_tablet_pad_strip(self.id, pad.dev, time_usec, strip, source, position)
|
||||
});
|
||||
if pad.tablet.is_some() {
|
||||
if let Some(strip) = pad.strips.get(strip as usize) {
|
||||
let node = pad.node.get();
|
||||
node.node_on_tablet_pad_strip(&pad, strip, source, position, time_usec);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TabletPad {
|
||||
fn for_each_pair(&self, n: &WlSurface, mut f: impl FnMut(&ZwpTabletV2, &ZwpTabletPadV2)) {
|
||||
let Some(tablet) = self.tablet.get() else {
|
||||
return;
|
||||
};
|
||||
self.seat.tablet_for_each_seat(n, |s| {
|
||||
let Some(tablet) = tablet.bindings.get(s) else {
|
||||
return;
|
||||
};
|
||||
let Some(pad) = self.bindings.get(s) else {
|
||||
return;
|
||||
};
|
||||
f(&tablet, &pad);
|
||||
})
|
||||
}
|
||||
|
||||
fn for_each_entered(&self, n: &WlSurface, mut f: impl FnMut(&ZwpTabletPadV2)) {
|
||||
self.seat.tablet_for_each_seat(n, |s| {
|
||||
let Some(pad) = self.bindings.get(s) else {
|
||||
return;
|
||||
};
|
||||
if pad.entered.get() {
|
||||
f(&pad);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn surface_enter(self: &Rc<Self>, n: &WlSurface) {
|
||||
let mut serial = n.client.pending_serial();
|
||||
let time = usec_to_msec(now_usec());
|
||||
self.for_each_pair(n, |tablet, pad| {
|
||||
pad.send_enter(serial.get(), &tablet, n);
|
||||
for group in &self.groups {
|
||||
let mode = group.mode.get();
|
||||
if let Some(group) = group.bindings.get(&pad.seat) {
|
||||
group.send_mode_switch(time, serial.get(), mode);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn surface_leave(self: &Rc<Self>, n: &WlSurface) {
|
||||
let mut serial = n.client.pending_serial();
|
||||
self.for_each_entered(n, |pad| {
|
||||
pad.send_leave(serial.get(), n);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn surface_ring(
|
||||
self: &Rc<Self>,
|
||||
n: &WlSurface,
|
||||
ring: &Rc<TabletPadRing>,
|
||||
source: Option<TabletRingEventSource>,
|
||||
angle: Option<f64>,
|
||||
time_usec: u64,
|
||||
) {
|
||||
let time = usec_to_msec(time_usec);
|
||||
self.seat.tablet_for_each_seat(n, |s| {
|
||||
if let Some(ring) = ring.bindings.get(&s) {
|
||||
if let Some(source) = source {
|
||||
ring.send_source(source);
|
||||
}
|
||||
if let Some(angle) = angle {
|
||||
ring.send_angle(Fixed::from_f64(angle));
|
||||
} else {
|
||||
ring.send_stop();
|
||||
}
|
||||
ring.send_frame(time);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn surface_strip(
|
||||
self: &Rc<Self>,
|
||||
n: &WlSurface,
|
||||
strip: &Rc<TabletPadStrip>,
|
||||
source: Option<TabletStripEventSource>,
|
||||
position: Option<f64>,
|
||||
time_usec: u64,
|
||||
) {
|
||||
let time = usec_to_msec(time_usec);
|
||||
self.for_each_entered(n, |pad| {
|
||||
if let Some(strip) = strip.bindings.get(&pad.seat) {
|
||||
if let Some(source) = source {
|
||||
strip.send_source(source);
|
||||
}
|
||||
if let Some(position) = position {
|
||||
strip.send_position(normalizeu(position));
|
||||
} else {
|
||||
strip.send_stop();
|
||||
}
|
||||
strip.send_frame(time);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn surface_mode_switch(
|
||||
self: &Rc<Self>,
|
||||
n: &WlSurface,
|
||||
group: &Rc<TabletPadGroup>,
|
||||
time_usec: u64,
|
||||
mode: u32,
|
||||
) {
|
||||
let time = usec_to_msec(time_usec);
|
||||
let mut serial = n.client.pending_serial();
|
||||
self.for_each_entered(n, |pad| {
|
||||
if let Some(group) = group.bindings.get(&pad.seat) {
|
||||
group.send_mode_switch(time, serial.get(), mode);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn surface_button(
|
||||
self: &Rc<Self>,
|
||||
n: &WlSurface,
|
||||
time_usec: u64,
|
||||
button: u32,
|
||||
state: PadButtonState,
|
||||
) {
|
||||
let time = usec_to_msec(time_usec);
|
||||
self.for_each_entered(n, |pad| {
|
||||
pad.send_button(time, button, state);
|
||||
})
|
||||
}
|
||||
}
|
||||
135
src/ifs/wl_seat/tablet/pad_owner.rs
Normal file
135
src/ifs/wl_seat/tablet/pad_owner.rs
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
use {
|
||||
crate::{
|
||||
ifs::wl_seat::tablet::{PadButtonState, TabletPad},
|
||||
time::now_usec,
|
||||
tree::Node,
|
||||
utils::{clonecell::CloneCell, smallmap::SmallMap},
|
||||
},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
pub struct PadOwnerHolder {
|
||||
default: Rc<DefaultPadOwner>,
|
||||
owner: CloneCell<Rc<dyn PadOwner>>,
|
||||
}
|
||||
|
||||
trait PadOwner {
|
||||
fn revert_to_default(&self, pad: &Rc<TabletPad>, time_usec: u64);
|
||||
fn update_node(&self, pad: &Rc<TabletPad>);
|
||||
fn button(&self, pad: &Rc<TabletPad>, time_usec: u64, button: u32, state: PadButtonState);
|
||||
}
|
||||
|
||||
struct DefaultPadOwner;
|
||||
|
||||
struct GrabPadOwner {
|
||||
buttons: SmallMap<u32, (), 4>,
|
||||
node: Rc<dyn Node>,
|
||||
}
|
||||
|
||||
impl Default for PadOwnerHolder {
|
||||
fn default() -> Self {
|
||||
let default = Rc::new(DefaultPadOwner);
|
||||
Self {
|
||||
owner: CloneCell::new(default.clone()),
|
||||
default,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PadOwnerHolder {
|
||||
pub fn update_node(&self, pad: &Rc<TabletPad>) {
|
||||
self.owner.get().update_node(pad);
|
||||
}
|
||||
|
||||
pub fn destroy(&self, pad: &Rc<TabletPad>) {
|
||||
self.owner.get().revert_to_default(pad, now_usec());
|
||||
let prev = pad.node.set(pad.seat.state.root.clone());
|
||||
prev.node_on_tablet_pad_leave(pad);
|
||||
prev.node_seat_state().remove_tablet_pad_focus(pad);
|
||||
}
|
||||
|
||||
pub fn button(&self, pad: &Rc<TabletPad>, time_usec: u64, button: u32, state: PadButtonState) {
|
||||
self.owner.get().button(pad, time_usec, button, state);
|
||||
}
|
||||
|
||||
pub fn focus_root(&self, pad: &Rc<TabletPad>) {
|
||||
self.owner.get().revert_to_default(pad, now_usec());
|
||||
let node = pad.seat.state.root.clone();
|
||||
pad.focus_node(node);
|
||||
}
|
||||
|
||||
fn set_default_owner(&self) {
|
||||
self.owner.set(self.default.clone());
|
||||
}
|
||||
}
|
||||
|
||||
impl TabletPad {
|
||||
fn focus_node(self: &Rc<Self>, node: Rc<dyn Node>) {
|
||||
let prev = self.node.set(node.clone());
|
||||
if node.node_id() != prev.node_id() {
|
||||
prev.node_on_tablet_pad_leave(self);
|
||||
prev.node_seat_state().remove_tablet_pad_focus(self);
|
||||
node.node_seat_state().add_tablet_pad_focus(self);
|
||||
node.node_on_tablet_pad_enter(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PadOwner for DefaultPadOwner {
|
||||
fn revert_to_default(&self, _pad: &Rc<TabletPad>, _time_usec: u64) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
fn update_node(&self, pad: &Rc<TabletPad>) {
|
||||
let node = pad.seat.keyboard_node.get();
|
||||
pad.focus_node(node);
|
||||
}
|
||||
|
||||
fn button(&self, pad: &Rc<TabletPad>, time_usec: u64, button: u32, state: PadButtonState) {
|
||||
if state != PadButtonState::Pressed {
|
||||
return;
|
||||
}
|
||||
let node = pad.node.get();
|
||||
let owner = Rc::new(GrabPadOwner {
|
||||
buttons: Default::default(),
|
||||
node,
|
||||
});
|
||||
pad.pad_owner.owner.set(owner.clone());
|
||||
owner.button(pad, time_usec, button, state);
|
||||
}
|
||||
}
|
||||
|
||||
impl PadOwner for GrabPadOwner {
|
||||
fn revert_to_default(&self, pad: &Rc<TabletPad>, time_usec: u64) {
|
||||
for (button, _) in &self.buttons {
|
||||
self.node
|
||||
.node_on_tablet_pad_button(pad, time_usec, button, PadButtonState::Released);
|
||||
}
|
||||
pad.pad_owner.set_default_owner();
|
||||
}
|
||||
|
||||
fn update_node(&self, _pad: &Rc<TabletPad>) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
fn button(&self, pad: &Rc<TabletPad>, time_usec: u64, button: u32, state: PadButtonState) {
|
||||
match state {
|
||||
PadButtonState::Released => {
|
||||
if self.buttons.remove(&button).is_none() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
PadButtonState::Pressed => {
|
||||
if self.buttons.insert(button, ()).is_some() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.node
|
||||
.node_on_tablet_pad_button(pad, time_usec, button, state);
|
||||
if self.buttons.is_empty() {
|
||||
pad.pad_owner.set_default_owner();
|
||||
pad.pad_owner.default.update_node(pad);
|
||||
}
|
||||
}
|
||||
}
|
||||
43
src/ifs/wl_seat/tablet/tablet_bindings.rs
Normal file
43
src/ifs/wl_seat/tablet/tablet_bindings.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
use {
|
||||
crate::{
|
||||
client::ClientId,
|
||||
ifs::wl_seat::tablet::zwp_tablet_seat_v2::ZwpTabletSeatV2,
|
||||
utils::copyhashmap::{CopyHashMap, Locked},
|
||||
wire::ZwpTabletSeatV2Id,
|
||||
},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
pub struct TabletBindings<T> {
|
||||
bindings: CopyHashMap<(ClientId, ZwpTabletSeatV2Id), Rc<T>>,
|
||||
}
|
||||
|
||||
impl<T> Default for TabletBindings<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bindings: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TabletBindings<T> {
|
||||
pub fn add(&self, seat: &ZwpTabletSeatV2, t: &Rc<T>) {
|
||||
self.bindings.set((seat.client.id, seat.id), t.clone());
|
||||
}
|
||||
|
||||
pub fn get(&self, seat: &ZwpTabletSeatV2) -> Option<Rc<T>> {
|
||||
self.bindings.get(&(seat.client.id, seat.id))
|
||||
}
|
||||
|
||||
pub fn remove(&self, seat: &ZwpTabletSeatV2) -> Option<Rc<T>> {
|
||||
self.bindings.remove(&(seat.client.id, seat.id))
|
||||
}
|
||||
|
||||
pub fn lock(&self) -> Locked<'_, (ClientId, ZwpTabletSeatV2Id), Rc<T>> {
|
||||
self.bindings.lock()
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
self.bindings.clear();
|
||||
}
|
||||
}
|
||||
274
src/ifs/wl_seat/tablet/tool.rs
Normal file
274
src/ifs/wl_seat/tablet/tool.rs
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
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<Self>, 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<Self>, 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<Self>,
|
||||
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<Self>,
|
||||
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<Rc<TabletTool>> {
|
||||
self.tool.get()
|
||||
}
|
||||
}
|
||||
213
src/ifs/wl_seat/tablet/tool_owner.rs
Normal file
213
src/ifs/wl_seat/tablet/tool_owner.rs
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
use {
|
||||
crate::{
|
||||
fixed::Fixed,
|
||||
ifs::wl_seat::tablet::{TabletTool, TabletToolChanges, ToolButtonState},
|
||||
time::now_usec,
|
||||
tree::{FindTreeUsecase, FoundNode, Node},
|
||||
utils::{clonecell::CloneCell, smallmap::SmallMap},
|
||||
},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
pub struct ToolOwnerHolder {
|
||||
default: Rc<DefaultToolOwner>,
|
||||
owner: CloneCell<Rc<dyn ToolOwner>>,
|
||||
}
|
||||
|
||||
struct DefaultToolOwner;
|
||||
|
||||
struct GrabToolOwner {
|
||||
buttons: SmallMap<u32, (), 4>,
|
||||
node: Rc<dyn Node>,
|
||||
}
|
||||
|
||||
impl Default for ToolOwnerHolder {
|
||||
fn default() -> Self {
|
||||
let default = Rc::new(DefaultToolOwner);
|
||||
Self {
|
||||
owner: CloneCell::new(default.clone()),
|
||||
default,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToolOwnerHolder {
|
||||
pub fn destroy(&self, tool: &Rc<TabletTool>) {
|
||||
let root = tool.tablet.seat.state.root.clone();
|
||||
let prev = tool.node.set(root);
|
||||
prev.node_on_tablet_tool_leave(tool, now_usec());
|
||||
prev.node_seat_state().remove_tablet_tool_focus(tool);
|
||||
}
|
||||
|
||||
pub fn focus_root(&self, tool: &Rc<TabletTool>) {
|
||||
self.owner.set(self.default.clone());
|
||||
let root = tool.tablet.seat.state.root.clone();
|
||||
tool.set_node(root, now_usec());
|
||||
}
|
||||
|
||||
pub fn button(
|
||||
&self,
|
||||
tool: &Rc<TabletTool>,
|
||||
time_usec: u64,
|
||||
button: u32,
|
||||
state: ToolButtonState,
|
||||
) {
|
||||
self.owner.get().button(tool, time_usec, button, state);
|
||||
}
|
||||
|
||||
pub fn apply_changes(
|
||||
&self,
|
||||
tool: &Rc<TabletTool>,
|
||||
time_usec: u64,
|
||||
changes: Option<&TabletToolChanges>,
|
||||
) {
|
||||
self.owner.get().apply_changes(tool, time_usec, changes);
|
||||
}
|
||||
}
|
||||
|
||||
trait ToolOwner {
|
||||
fn button(&self, tool: &Rc<TabletTool>, time_usec: u64, button: u32, state: ToolButtonState);
|
||||
fn apply_changes(
|
||||
&self,
|
||||
tool: &Rc<TabletTool>,
|
||||
time_usec: u64,
|
||||
changes: Option<&TabletToolChanges>,
|
||||
);
|
||||
}
|
||||
|
||||
impl TabletTool {
|
||||
fn set_node(self: &Rc<Self>, node: Rc<dyn Node>, time_usec: u64) {
|
||||
let prev = self.node.set(node.clone());
|
||||
if prev.node_id() != node.node_id() {
|
||||
prev.node_on_tablet_tool_leave(self, time_usec);
|
||||
prev.node_seat_state().remove_tablet_tool_focus(self);
|
||||
let (tool_x, tool_y) = self.cursor.position();
|
||||
let (node_x, node_y) = node.node_absolute_position().position();
|
||||
node.node_seat_state().add_tablet_tool_focus(self);
|
||||
node.node_on_tablet_tool_enter(self, time_usec, tool_x - node_x, tool_y - node_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToolOwner for DefaultToolOwner {
|
||||
fn button(&self, tool: &Rc<TabletTool>, time_usec: u64, button: u32, state: ToolButtonState) {
|
||||
if state == ToolButtonState::Released {
|
||||
return;
|
||||
}
|
||||
let owner = Rc::new(GrabToolOwner {
|
||||
buttons: Default::default(),
|
||||
node: tool.node.get(),
|
||||
});
|
||||
tool.tool_owner.owner.set(owner.clone());
|
||||
owner.button(tool, time_usec, button, state);
|
||||
}
|
||||
|
||||
fn apply_changes(
|
||||
&self,
|
||||
tool: &Rc<TabletTool>,
|
||||
time_usec: u64,
|
||||
changes: Option<&TabletToolChanges>,
|
||||
) {
|
||||
let change = handle_position_change(tool);
|
||||
let node = change.node;
|
||||
if change.changed {
|
||||
tool.set_node(node.clone(), time_usec);
|
||||
} else {
|
||||
node.clone()
|
||||
.node_on_tablet_tool_apply_changes(tool, time_usec, changes, change.x, change.y);
|
||||
}
|
||||
if tool.down.get() {
|
||||
tool.tool_owner.owner.set(Rc::new(GrabToolOwner {
|
||||
buttons: Default::default(),
|
||||
node,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GrabToolOwner {
|
||||
fn maybe_revert(&self, tool: &Rc<TabletTool>) {
|
||||
if !tool.down.get() && self.buttons.is_empty() {
|
||||
tool.tool_owner.owner.set(tool.tool_owner.default.clone());
|
||||
tool.tablet.seat.tree_changed.trigger();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToolOwner for GrabToolOwner {
|
||||
fn button(&self, tool: &Rc<TabletTool>, time_usec: u64, button: u32, state: ToolButtonState) {
|
||||
match state {
|
||||
ToolButtonState::Released => {
|
||||
if self.buttons.remove(&button).is_none() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
ToolButtonState::Pressed => {
|
||||
if self.buttons.insert(button, ()).is_some() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.node
|
||||
.node_on_tablet_tool_button(tool, time_usec, button, state);
|
||||
self.maybe_revert(tool);
|
||||
}
|
||||
|
||||
fn apply_changes(
|
||||
&self,
|
||||
tool: &Rc<TabletTool>,
|
||||
time_usec: u64,
|
||||
changes: Option<&TabletToolChanges>,
|
||||
) {
|
||||
let (x, y) = tool.cursor.position();
|
||||
let node_pos = self.node.node_absolute_position();
|
||||
self.node.clone().node_on_tablet_tool_apply_changes(
|
||||
tool,
|
||||
time_usec,
|
||||
changes,
|
||||
x - node_pos.x1(),
|
||||
y - node_pos.y1(),
|
||||
);
|
||||
self.maybe_revert(tool);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_position_change(tool: &Rc<TabletTool>) -> UpdatedNode {
|
||||
let (x, y) = tool.cursor.position();
|
||||
let x_int = x.round_down();
|
||||
let y_int = y.round_down();
|
||||
let tree = &mut *tool.tablet.tree.borrow_mut();
|
||||
tree.push(FoundNode {
|
||||
node: tool.tablet.seat.state.root.clone(),
|
||||
x: x_int,
|
||||
y: y_int,
|
||||
});
|
||||
tool.tablet
|
||||
.seat
|
||||
.state
|
||||
.root
|
||||
.node_find_tree_at(x_int, y_int, tree, FindTreeUsecase::None);
|
||||
let mut update = UpdatedNode {
|
||||
node: tool.node.get(),
|
||||
x,
|
||||
y,
|
||||
changed: false,
|
||||
};
|
||||
if let Some(last) = tree.last() {
|
||||
if last.node.node_id() != update.node.node_id() {
|
||||
update.changed = true;
|
||||
update.node = last.node.clone();
|
||||
}
|
||||
update.x = x.apply_fract(last.x);
|
||||
update.y = y.apply_fract(last.y);
|
||||
}
|
||||
tree.clear();
|
||||
update
|
||||
}
|
||||
|
||||
struct UpdatedNode {
|
||||
node: Rc<dyn Node>,
|
||||
changed: bool,
|
||||
x: Fixed,
|
||||
y: Fixed,
|
||||
}
|
||||
104
src/ifs/wl_seat/tablet/zwp_tablet_manager_v2.rs
Normal file
104
src/ifs/wl_seat/tablet/zwp_tablet_manager_v2.rs
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
globals::{Global, GlobalName},
|
||||
ifs::wl_seat::tablet::zwp_tablet_seat_v2::ZwpTabletSeatV2,
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
wire::{zwp_tablet_manager_v2::*, ZwpTabletManagerV2Id},
|
||||
},
|
||||
std::rc::Rc,
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
pub struct ZwpTabletManagerV2Global {
|
||||
pub name: GlobalName,
|
||||
}
|
||||
|
||||
pub struct ZwpTabletManagerV2 {
|
||||
pub id: ZwpTabletManagerV2Id,
|
||||
pub client: Rc<Client>,
|
||||
pub tracker: Tracker<Self>,
|
||||
pub version: Version,
|
||||
}
|
||||
|
||||
impl ZwpTabletManagerV2Global {
|
||||
pub fn new(name: GlobalName) -> Self {
|
||||
Self { name }
|
||||
}
|
||||
|
||||
fn bind_(
|
||||
self: Rc<Self>,
|
||||
id: ZwpTabletManagerV2Id,
|
||||
client: &Rc<Client>,
|
||||
version: Version,
|
||||
) -> Result<(), ZwpTabletManagerV2Error> {
|
||||
let obj = Rc::new(ZwpTabletManagerV2 {
|
||||
id,
|
||||
client: client.clone(),
|
||||
tracker: Default::default(),
|
||||
version,
|
||||
});
|
||||
track!(client, obj);
|
||||
client.add_client_obj(&obj)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
global_base!(
|
||||
ZwpTabletManagerV2Global,
|
||||
ZwpTabletManagerV2,
|
||||
ZwpTabletManagerV2Error
|
||||
);
|
||||
|
||||
impl Global for ZwpTabletManagerV2Global {
|
||||
fn singleton(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn version(&self) -> u32 {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
simple_add_global!(ZwpTabletManagerV2Global);
|
||||
|
||||
impl ZwpTabletManagerV2RequestHandler for ZwpTabletManagerV2 {
|
||||
type Error = ZwpTabletManagerV2Error;
|
||||
|
||||
fn get_tablet_seat(&self, req: GetTabletSeat, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
let seat = self.client.lookup(req.seat)?.global.clone();
|
||||
let obj = Rc::new(ZwpTabletSeatV2 {
|
||||
id: req.tablet_seat,
|
||||
client: self.client.clone(),
|
||||
seat: seat.clone(),
|
||||
tracker: Default::default(),
|
||||
version: self.version,
|
||||
});
|
||||
track!(self.client, obj);
|
||||
self.client.add_client_obj(&obj)?;
|
||||
seat.tablet_add_seat(&obj);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.client.remove_obj(self)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
object_base! {
|
||||
self = ZwpTabletManagerV2;
|
||||
version = self.version;
|
||||
}
|
||||
|
||||
impl Object for ZwpTabletManagerV2 {}
|
||||
|
||||
simple_add_obj!(ZwpTabletManagerV2);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ZwpTabletManagerV2Error {
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
}
|
||||
efrom!(ZwpTabletManagerV2Error, ClientError);
|
||||
101
src/ifs/wl_seat/tablet/zwp_tablet_pad_group_v2.rs
Normal file
101
src/ifs/wl_seat/tablet/zwp_tablet_pad_group_v2.rs
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
ifs::wl_seat::tablet::{
|
||||
zwp_tablet_pad_ring_v2::ZwpTabletPadRingV2,
|
||||
zwp_tablet_pad_strip_v2::ZwpTabletPadStripV2, zwp_tablet_seat_v2::ZwpTabletSeatV2,
|
||||
TabletPadGroup,
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
wire::{zwp_tablet_pad_group_v2::*, ZwpTabletPadGroupV2Id},
|
||||
},
|
||||
std::rc::Rc,
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
pub struct ZwpTabletPadGroupV2 {
|
||||
pub id: ZwpTabletPadGroupV2Id,
|
||||
pub client: Rc<Client>,
|
||||
pub tracker: Tracker<Self>,
|
||||
pub version: Version,
|
||||
pub seat: Rc<ZwpTabletSeatV2>,
|
||||
pub group: Rc<TabletPadGroup>,
|
||||
}
|
||||
|
||||
impl ZwpTabletPadGroupV2 {
|
||||
pub fn detach(&self) {
|
||||
self.group.bindings.remove(&self.seat);
|
||||
}
|
||||
|
||||
pub fn send_buttons(&self, buttons: &[u32]) {
|
||||
self.client.event(Buttons {
|
||||
self_id: self.id,
|
||||
buttons,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_ring(&self, ring: &ZwpTabletPadRingV2) {
|
||||
self.client.event(Ring {
|
||||
self_id: self.id,
|
||||
ring: ring.id,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_strip(&self, strip: &ZwpTabletPadStripV2) {
|
||||
self.client.event(Strip {
|
||||
self_id: self.id,
|
||||
strip: strip.id,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_modes(&self, modes: u32) {
|
||||
self.client.event(Modes {
|
||||
self_id: self.id,
|
||||
modes,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_done(&self) {
|
||||
self.client.event(Done { self_id: self.id });
|
||||
}
|
||||
|
||||
pub fn send_mode_switch(&self, time: u32, serial: u32, mode: u32) {
|
||||
self.client.event(ModeSwitch {
|
||||
self_id: self.id,
|
||||
time,
|
||||
serial,
|
||||
mode,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl ZwpTabletPadGroupV2RequestHandler for ZwpTabletPadGroupV2 {
|
||||
type Error = ZwpTabletPadGroupV2Error;
|
||||
|
||||
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.detach();
|
||||
self.client.remove_obj(self)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
object_base! {
|
||||
self = ZwpTabletPadGroupV2;
|
||||
version = self.version;
|
||||
}
|
||||
|
||||
impl Object for ZwpTabletPadGroupV2 {
|
||||
fn break_loops(&self) {
|
||||
self.detach();
|
||||
}
|
||||
}
|
||||
|
||||
simple_add_obj!(ZwpTabletPadGroupV2);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ZwpTabletPadGroupV2Error {
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
}
|
||||
efrom!(ZwpTabletPadGroupV2Error, ClientError);
|
||||
90
src/ifs/wl_seat/tablet/zwp_tablet_pad_ring_v2.rs
Normal file
90
src/ifs/wl_seat/tablet/zwp_tablet_pad_ring_v2.rs
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
fixed::Fixed,
|
||||
ifs::wl_seat::tablet::{
|
||||
zwp_tablet_seat_v2::ZwpTabletSeatV2, TabletPadRing, TabletRingEventSource,
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
wire::{zwp_tablet_pad_ring_v2::*, ZwpTabletPadRingV2Id},
|
||||
},
|
||||
std::rc::Rc,
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
pub struct ZwpTabletPadRingV2 {
|
||||
pub id: ZwpTabletPadRingV2Id,
|
||||
pub client: Rc<Client>,
|
||||
pub tracker: Tracker<Self>,
|
||||
pub version: Version,
|
||||
pub seat: Rc<ZwpTabletSeatV2>,
|
||||
pub ring: Rc<TabletPadRing>,
|
||||
}
|
||||
|
||||
impl ZwpTabletPadRingV2 {
|
||||
pub fn detach(&self) {
|
||||
self.ring.bindings.remove(&self.seat);
|
||||
}
|
||||
|
||||
pub fn send_source(&self, source: TabletRingEventSource) {
|
||||
self.client.event(Source {
|
||||
self_id: self.id,
|
||||
source: match source {
|
||||
TabletRingEventSource::Finger => 1,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_angle(&self, degrees: Fixed) {
|
||||
self.client.event(Angle {
|
||||
self_id: self.id,
|
||||
degrees,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_stop(&self) {
|
||||
self.client.event(Stop { self_id: self.id });
|
||||
}
|
||||
|
||||
pub fn send_frame(&self, time: u32) {
|
||||
self.client.event(Frame {
|
||||
self_id: self.id,
|
||||
time,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl ZwpTabletPadRingV2RequestHandler for ZwpTabletPadRingV2 {
|
||||
type Error = ZwpTabletPadRingV2Error;
|
||||
|
||||
fn set_feedback(&self, _req: SetFeedback<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.detach();
|
||||
self.client.remove_obj(self)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
object_base! {
|
||||
self = ZwpTabletPadRingV2;
|
||||
version = self.version;
|
||||
}
|
||||
|
||||
impl Object for ZwpTabletPadRingV2 {
|
||||
fn break_loops(&self) {
|
||||
self.detach();
|
||||
}
|
||||
}
|
||||
|
||||
simple_add_obj!(ZwpTabletPadRingV2);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ZwpTabletPadRingV2Error {
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
}
|
||||
efrom!(ZwpTabletPadRingV2Error, ClientError);
|
||||
89
src/ifs/wl_seat/tablet/zwp_tablet_pad_strip_v2.rs
Normal file
89
src/ifs/wl_seat/tablet/zwp_tablet_pad_strip_v2.rs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
ifs::wl_seat::tablet::{
|
||||
zwp_tablet_seat_v2::ZwpTabletSeatV2, TabletPadStrip, TabletStripEventSource,
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
wire::{zwp_tablet_pad_strip_v2::*, ZwpTabletPadStripV2Id},
|
||||
},
|
||||
std::rc::Rc,
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
pub struct ZwpTabletPadStripV2 {
|
||||
pub id: ZwpTabletPadStripV2Id,
|
||||
pub client: Rc<Client>,
|
||||
pub tracker: Tracker<Self>,
|
||||
pub version: Version,
|
||||
pub seat: Rc<ZwpTabletSeatV2>,
|
||||
pub strip: Rc<TabletPadStrip>,
|
||||
}
|
||||
|
||||
impl ZwpTabletPadStripV2 {
|
||||
pub fn detach(&self) {
|
||||
self.strip.bindings.remove(&self.seat);
|
||||
}
|
||||
|
||||
pub fn send_source(&self, source: TabletStripEventSource) {
|
||||
self.client.event(Source {
|
||||
self_id: self.id,
|
||||
source: match source {
|
||||
TabletStripEventSource::Finger => 1,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_position(&self, position: u32) {
|
||||
self.client.event(Position {
|
||||
self_id: self.id,
|
||||
position,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_stop(&self) {
|
||||
self.client.event(Stop { self_id: self.id });
|
||||
}
|
||||
|
||||
pub fn send_frame(&self, time: u32) {
|
||||
self.client.event(Frame {
|
||||
self_id: self.id,
|
||||
time,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl ZwpTabletPadStripV2RequestHandler for ZwpTabletPadStripV2 {
|
||||
type Error = ZwpTabletPadStripV2Error;
|
||||
|
||||
fn set_feedback(&self, _req: SetFeedback<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.detach();
|
||||
self.client.remove_obj(self)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
object_base! {
|
||||
self = ZwpTabletPadStripV2;
|
||||
version = self.version;
|
||||
}
|
||||
|
||||
impl Object for ZwpTabletPadStripV2 {
|
||||
fn break_loops(&self) {
|
||||
self.detach();
|
||||
}
|
||||
}
|
||||
|
||||
simple_add_obj!(ZwpTabletPadStripV2);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ZwpTabletPadStripV2Error {
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
}
|
||||
efrom!(ZwpTabletPadStripV2Error, ClientError);
|
||||
127
src/ifs/wl_seat/tablet/zwp_tablet_pad_v2.rs
Normal file
127
src/ifs/wl_seat/tablet/zwp_tablet_pad_v2.rs
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
ifs::{
|
||||
wl_seat::tablet::{
|
||||
zwp_tablet_pad_group_v2::ZwpTabletPadGroupV2, zwp_tablet_seat_v2::ZwpTabletSeatV2,
|
||||
zwp_tablet_v2::ZwpTabletV2, PadButtonState, TabletPad,
|
||||
},
|
||||
wl_surface::WlSurface,
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
wire::{zwp_tablet_pad_v2::*, ZwpTabletPadV2Id},
|
||||
},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
pub struct ZwpTabletPadV2 {
|
||||
pub id: ZwpTabletPadV2Id,
|
||||
pub client: Rc<Client>,
|
||||
pub tracker: Tracker<Self>,
|
||||
pub version: Version,
|
||||
pub seat: Rc<ZwpTabletSeatV2>,
|
||||
pub pad: Rc<TabletPad>,
|
||||
pub entered: Cell<bool>,
|
||||
}
|
||||
|
||||
impl ZwpTabletPadV2 {
|
||||
pub fn detach(&self) {
|
||||
self.pad.bindings.remove(&self.seat);
|
||||
}
|
||||
|
||||
pub fn send_group(&self, group: &ZwpTabletPadGroupV2) {
|
||||
self.client.event(Group {
|
||||
self_id: self.id,
|
||||
pad_group: group.id,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_path(&self, path: &str) {
|
||||
self.client.event(Path {
|
||||
self_id: self.id,
|
||||
path,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_buttons(&self, buttons: u32) {
|
||||
self.client.event(Buttons {
|
||||
self_id: self.id,
|
||||
buttons,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_done(&self) {
|
||||
self.client.event(Done { self_id: self.id });
|
||||
}
|
||||
|
||||
pub fn send_button(&self, time: u32, button: u32, state: PadButtonState) {
|
||||
self.client.event(Button {
|
||||
self_id: self.id,
|
||||
time,
|
||||
button,
|
||||
state: match state {
|
||||
PadButtonState::Released => 0,
|
||||
PadButtonState::Pressed => 1,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_enter(&self, serial: u32, tablet: &ZwpTabletV2, surface: &WlSurface) {
|
||||
self.entered.set(true);
|
||||
self.client.event(Enter {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
tablet: tablet.id,
|
||||
surface: surface.id,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_leave(&self, serial: u32, surface: &WlSurface) {
|
||||
self.entered.set(false);
|
||||
self.client.event(Leave {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
surface: surface.id,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_removed(&self) {
|
||||
self.client.event(Removed { self_id: self.id });
|
||||
}
|
||||
}
|
||||
|
||||
impl ZwpTabletPadV2RequestHandler for ZwpTabletPadV2 {
|
||||
type Error = ZwpTabletPadV2Error;
|
||||
|
||||
fn set_feedback(&self, _req: SetFeedback<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.detach();
|
||||
self.client.remove_obj(self)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
object_base! {
|
||||
self = ZwpTabletPadV2;
|
||||
version = self.version;
|
||||
}
|
||||
|
||||
impl Object for ZwpTabletPadV2 {
|
||||
fn break_loops(&self) {
|
||||
self.detach();
|
||||
}
|
||||
}
|
||||
|
||||
simple_add_obj!(ZwpTabletPadV2);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ZwpTabletPadV2Error {
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
}
|
||||
efrom!(ZwpTabletPadV2Error, ClientError);
|
||||
221
src/ifs/wl_seat/tablet/zwp_tablet_seat_v2.rs
Normal file
221
src/ifs/wl_seat/tablet/zwp_tablet_seat_v2.rs
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
ifs::wl_seat::{
|
||||
tablet::{
|
||||
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_tool_v2::ZwpTabletToolV2, zwp_tablet_v2::ZwpTabletV2, Tablet, TabletPad,
|
||||
TabletTool,
|
||||
},
|
||||
WlSeatGlobal,
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
wire::{zwp_tablet_seat_v2::*, ZwpTabletSeatV2Id},
|
||||
},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
pub struct ZwpTabletSeatV2 {
|
||||
pub id: ZwpTabletSeatV2Id,
|
||||
pub client: Rc<Client>,
|
||||
pub seat: Rc<WlSeatGlobal>,
|
||||
pub tracker: Tracker<Self>,
|
||||
pub version: Version,
|
||||
}
|
||||
|
||||
impl ZwpTabletSeatV2 {
|
||||
pub fn detach(&self) {
|
||||
self.seat.tablet.seats.remove(&self.client, self);
|
||||
}
|
||||
|
||||
pub fn announce_tablet(self: &Rc<Self>, tablet: &Rc<Tablet>) {
|
||||
let id = match self.client.new_id() {
|
||||
Ok(id) => id,
|
||||
Err(e) => {
|
||||
self.client.error(e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let obj = Rc::new(ZwpTabletV2 {
|
||||
id,
|
||||
client: self.client.clone(),
|
||||
seat: self.clone(),
|
||||
tracker: Default::default(),
|
||||
version: self.version,
|
||||
tablet: tablet.clone(),
|
||||
});
|
||||
track!(self.client, obj);
|
||||
self.client.add_server_obj(&obj);
|
||||
self.send_tablet_added(&obj);
|
||||
obj.send_name(&tablet.name);
|
||||
obj.send_id(tablet.vid, tablet.pid);
|
||||
obj.send_path(&tablet.path);
|
||||
obj.send_done();
|
||||
tablet.bindings.add(self, &obj);
|
||||
}
|
||||
|
||||
pub fn announce_tool(self: &Rc<Self>, tool: &Rc<TabletTool>) {
|
||||
let id = match self.client.new_id() {
|
||||
Ok(id) => id,
|
||||
Err(e) => {
|
||||
self.client.error(e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let obj = Rc::new(ZwpTabletToolV2 {
|
||||
id,
|
||||
client: self.client.clone(),
|
||||
seat: self.clone(),
|
||||
tool: tool.opt.clone(),
|
||||
tracker: Default::default(),
|
||||
version: self.version,
|
||||
entered: Cell::new(false),
|
||||
});
|
||||
track!(self.client, obj);
|
||||
self.client.add_server_obj(&obj);
|
||||
self.send_tool_added(&obj);
|
||||
obj.send_type(tool.type_);
|
||||
obj.send_hardware_serial(tool.hardware_serial);
|
||||
obj.send_hardware_id_wacom(tool.hardware_id_wacom);
|
||||
for cap in &tool.capabilities {
|
||||
obj.send_capability(*cap);
|
||||
}
|
||||
obj.send_done();
|
||||
tool.bindings.add(self, &obj);
|
||||
}
|
||||
|
||||
pub fn announce_pad(self: &Rc<Self>, pad: &Rc<TabletPad>) {
|
||||
macro_rules! id {
|
||||
() => {
|
||||
match self.client.new_id() {
|
||||
Ok(id) => id,
|
||||
Err(e) => {
|
||||
self.client.error(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
let obj = Rc::new(ZwpTabletPadV2 {
|
||||
id: id!(),
|
||||
client: self.client.clone(),
|
||||
seat: self.clone(),
|
||||
tracker: Default::default(),
|
||||
version: self.version,
|
||||
pad: pad.clone(),
|
||||
entered: Cell::new(false),
|
||||
});
|
||||
track!(self.client, obj);
|
||||
self.client.add_server_obj(&obj);
|
||||
self.send_pad_added(&obj);
|
||||
obj.send_path(&pad.path);
|
||||
obj.send_buttons(pad.buttons);
|
||||
for group in &pad.groups {
|
||||
let group_obj = Rc::new(ZwpTabletPadGroupV2 {
|
||||
id: id!(),
|
||||
client: self.client.clone(),
|
||||
seat: self.clone(),
|
||||
tracker: Default::default(),
|
||||
version: self.version,
|
||||
group: group.clone(),
|
||||
});
|
||||
track!(self.client, group_obj);
|
||||
self.client.add_server_obj(&group_obj);
|
||||
obj.send_group(&group_obj);
|
||||
group_obj.send_buttons(&group.buttons);
|
||||
group_obj.send_modes(group.modes);
|
||||
for ring in &group.rings {
|
||||
let Some(ring) = pad.rings.get(*ring as usize) else {
|
||||
continue;
|
||||
};
|
||||
let ring_obj = Rc::new(ZwpTabletPadRingV2 {
|
||||
id: id!(),
|
||||
client: self.client.clone(),
|
||||
seat: self.clone(),
|
||||
tracker: Default::default(),
|
||||
version: self.version,
|
||||
ring: ring.clone(),
|
||||
});
|
||||
track!(self.client, ring_obj);
|
||||
self.client.add_server_obj(&ring_obj);
|
||||
group_obj.send_ring(&ring_obj);
|
||||
ring.bindings.add(self, &ring_obj);
|
||||
}
|
||||
for strip in &group.strips {
|
||||
let Some(strip) = pad.strips.get(*strip as usize) else {
|
||||
continue;
|
||||
};
|
||||
let strip_obj = Rc::new(ZwpTabletPadStripV2 {
|
||||
id: id!(),
|
||||
client: self.client.clone(),
|
||||
seat: self.clone(),
|
||||
tracker: Default::default(),
|
||||
version: self.version,
|
||||
strip: strip.clone(),
|
||||
});
|
||||
track!(self.client, strip_obj);
|
||||
self.client.add_server_obj(&strip_obj);
|
||||
group_obj.send_strip(&strip_obj);
|
||||
strip.bindings.add(self, &strip_obj);
|
||||
}
|
||||
group_obj.send_done();
|
||||
}
|
||||
obj.send_done();
|
||||
pad.bindings.add(self, &obj);
|
||||
}
|
||||
|
||||
fn send_tablet_added(&self, tablet: &ZwpTabletV2) {
|
||||
self.client.event(TabletAdded {
|
||||
self_id: self.id,
|
||||
id: tablet.id,
|
||||
});
|
||||
}
|
||||
|
||||
fn send_tool_added(&self, tool: &ZwpTabletToolV2) {
|
||||
self.client.event(ToolAdded {
|
||||
self_id: self.id,
|
||||
id: tool.id,
|
||||
});
|
||||
}
|
||||
|
||||
fn send_pad_added(&self, pad: &ZwpTabletPadV2) {
|
||||
self.client.event(PadAdded {
|
||||
self_id: self.id,
|
||||
id: pad.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl ZwpTabletSeatV2RequestHandler for ZwpTabletSeatV2 {
|
||||
type Error = ZwpTabletSeatV2Error;
|
||||
|
||||
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.detach();
|
||||
self.client.remove_obj(self)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
object_base! {
|
||||
self = ZwpTabletSeatV2;
|
||||
version = self.version;
|
||||
}
|
||||
|
||||
impl Object for ZwpTabletSeatV2 {
|
||||
fn break_loops(&self) {
|
||||
self.detach();
|
||||
}
|
||||
}
|
||||
|
||||
simple_add_obj!(ZwpTabletSeatV2);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ZwpTabletSeatV2Error {
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
}
|
||||
efrom!(ZwpTabletSeatV2Error, ClientError);
|
||||
252
src/ifs/wl_seat/tablet/zwp_tablet_tool_v2.rs
Normal file
252
src/ifs/wl_seat/tablet/zwp_tablet_tool_v2.rs
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
cursor::Cursor,
|
||||
fixed::Fixed,
|
||||
ifs::{
|
||||
wl_seat::tablet::{
|
||||
zwp_tablet_seat_v2::ZwpTabletSeatV2, zwp_tablet_v2::ZwpTabletV2,
|
||||
TabletToolCapability, TabletToolOpt, TabletToolType, ToolButtonState,
|
||||
},
|
||||
wl_surface::{WlSurface, WlSurfaceError},
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
wire::{zwp_tablet_tool_v2::*, ZwpTabletToolV2Id},
|
||||
},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
pub struct ZwpTabletToolV2 {
|
||||
pub id: ZwpTabletToolV2Id,
|
||||
pub client: Rc<Client>,
|
||||
pub tracker: Tracker<Self>,
|
||||
pub version: Version,
|
||||
pub seat: Rc<ZwpTabletSeatV2>,
|
||||
pub tool: Rc<TabletToolOpt>,
|
||||
pub entered: Cell<bool>,
|
||||
}
|
||||
|
||||
pub const BTN_TOOL_PEN: u32 = 0x140;
|
||||
pub const BTN_TOOL_RUBBER: u32 = 0x141;
|
||||
pub const BTN_TOOL_BRUSH: u32 = 0x142;
|
||||
pub const BTN_TOOL_PENCIL: u32 = 0x143;
|
||||
pub const BTN_TOOL_AIRBRUSH: u32 = 0x144;
|
||||
pub const BTN_TOOL_FINGER: u32 = 0x145;
|
||||
pub const BTN_TOOL_MOUSE: u32 = 0x146;
|
||||
pub const BTN_TOOL_LENS: u32 = 0x147;
|
||||
|
||||
impl ZwpTabletToolV2 {
|
||||
pub fn detach(&self) {
|
||||
if let Some(tool) = self.tool.get() {
|
||||
tool.bindings.remove(&self.seat);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_type(&self, tool_type: TabletToolType) {
|
||||
self.client.event(Type {
|
||||
self_id: self.id,
|
||||
tool_type: match tool_type {
|
||||
TabletToolType::Pen => BTN_TOOL_PEN,
|
||||
TabletToolType::Eraser => BTN_TOOL_RUBBER,
|
||||
TabletToolType::Brush => BTN_TOOL_BRUSH,
|
||||
TabletToolType::Pencil => BTN_TOOL_PENCIL,
|
||||
TabletToolType::Airbrush => BTN_TOOL_AIRBRUSH,
|
||||
TabletToolType::Finger => BTN_TOOL_FINGER,
|
||||
TabletToolType::Mouse => BTN_TOOL_MOUSE,
|
||||
TabletToolType::Lens => BTN_TOOL_LENS,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_hardware_serial(&self, serial: u64) {
|
||||
self.client.event(HardwareSerial {
|
||||
self_id: self.id,
|
||||
hardware_serial_hi: (serial >> 32) as _,
|
||||
hardware_serial_lo: serial as _,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_hardware_id_wacom(&self, id: u64) {
|
||||
self.client.event(HardwareIdWacom {
|
||||
self_id: self.id,
|
||||
hardware_id_hi: (id >> 32) as _,
|
||||
hardware_id_lo: id as _,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_capability(&self, capability: TabletToolCapability) {
|
||||
self.client.event(Capability {
|
||||
self_id: self.id,
|
||||
capability: match capability {
|
||||
TabletToolCapability::Tilt => 1,
|
||||
TabletToolCapability::Pressure => 2,
|
||||
TabletToolCapability::Distance => 3,
|
||||
TabletToolCapability::Rotation => 4,
|
||||
TabletToolCapability::Slider => 5,
|
||||
TabletToolCapability::Wheel => 6,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_done(&self) {
|
||||
self.client.event(Done { self_id: self.id });
|
||||
}
|
||||
|
||||
pub fn send_removed(&self) {
|
||||
self.client.event(Removed { self_id: self.id });
|
||||
}
|
||||
|
||||
pub fn send_proximity_in(&self, serial: u32, tablet: &ZwpTabletV2, surface: &WlSurface) {
|
||||
self.entered.set(true);
|
||||
self.client.event(ProximityIn {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
tablet: tablet.id,
|
||||
surface: surface.id,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_proximity_out(&self) {
|
||||
self.entered.set(false);
|
||||
self.client.event(ProximityOut { self_id: self.id });
|
||||
}
|
||||
|
||||
pub fn send_down(&self, serial: u32) {
|
||||
self.client.event(Down {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_up(&self) {
|
||||
self.client.event(Up { self_id: self.id });
|
||||
}
|
||||
|
||||
pub fn send_motion(&self, x: Fixed, y: Fixed) {
|
||||
self.client.event(Motion {
|
||||
self_id: self.id,
|
||||
x,
|
||||
y,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_pressure(&self, pressure: u32) {
|
||||
self.client.event(Pressure {
|
||||
self_id: self.id,
|
||||
pressure,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_distance(&self, distance: u32) {
|
||||
self.client.event(Distance {
|
||||
self_id: self.id,
|
||||
distance,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_tilt(&self, tilt_x: Fixed, tilt_y: Fixed) {
|
||||
self.client.event(Tilt {
|
||||
self_id: self.id,
|
||||
tilt_x,
|
||||
tilt_y,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_rotation(&self, degrees: Fixed) {
|
||||
self.client.event(Rotation {
|
||||
self_id: self.id,
|
||||
degrees,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_slider(&self, position: i32) {
|
||||
self.client.event(Slider {
|
||||
self_id: self.id,
|
||||
position,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_wheel(&self, degrees: Fixed, clicks: i32) {
|
||||
self.client.event(Wheel {
|
||||
self_id: self.id,
|
||||
degrees,
|
||||
clicks,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_button(&self, serial: u32, button: u32, state: ToolButtonState) {
|
||||
self.client.event(Button {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
button,
|
||||
state: match state {
|
||||
ToolButtonState::Released => 0,
|
||||
ToolButtonState::Pressed => 1,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_frame(&self, time: u32) {
|
||||
self.client.event(Frame {
|
||||
self_id: self.id,
|
||||
time,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl ZwpTabletToolV2RequestHandler for ZwpTabletToolV2 {
|
||||
type Error = ZwpTabletToolV2Error;
|
||||
|
||||
fn set_cursor(&self, req: SetCursor, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
let Some(tool) = self.tool.get() else {
|
||||
return Ok(());
|
||||
};
|
||||
if !self.seat.client.valid_serial(req.serial) {
|
||||
log::warn!("Client tried to set_cursor with an invalid serial");
|
||||
return Ok(());
|
||||
}
|
||||
let mut cursor_opt = None;
|
||||
if req.surface.is_some() {
|
||||
let surface = self.seat.client.lookup(req.surface)?;
|
||||
let cursor = surface.get_cursor(&tool.cursor)?;
|
||||
cursor.set_hotspot(req.hotspot_x, req.hotspot_y);
|
||||
cursor_opt = Some(cursor as Rc<dyn Cursor>);
|
||||
}
|
||||
if tool.node.get().node_client_id() != Some(self.seat.client.id) {
|
||||
return Ok(());
|
||||
}
|
||||
tool.cursor.set(cursor_opt);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.detach();
|
||||
self.client.remove_obj(self)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
object_base! {
|
||||
self = ZwpTabletToolV2;
|
||||
version = self.version;
|
||||
}
|
||||
|
||||
impl Object for ZwpTabletToolV2 {
|
||||
fn break_loops(&self) {
|
||||
self.detach();
|
||||
}
|
||||
}
|
||||
|
||||
dedicated_add_obj!(ZwpTabletToolV2, ZwpTabletToolV2Id, tablet_tools);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ZwpTabletToolV2Error {
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
#[error(transparent)]
|
||||
WlSurfaceError(Box<WlSurfaceError>),
|
||||
}
|
||||
efrom!(ZwpTabletToolV2Error, ClientError);
|
||||
efrom!(ZwpTabletToolV2Error, WlSurfaceError);
|
||||
86
src/ifs/wl_seat/tablet/zwp_tablet_v2.rs
Normal file
86
src/ifs/wl_seat/tablet/zwp_tablet_v2.rs
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
ifs::wl_seat::tablet::{zwp_tablet_seat_v2::ZwpTabletSeatV2, Tablet},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
wire::{zwp_tablet_v2::*, ZwpTabletV2Id},
|
||||
},
|
||||
std::rc::Rc,
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
pub struct ZwpTabletV2 {
|
||||
pub id: ZwpTabletV2Id,
|
||||
pub client: Rc<Client>,
|
||||
pub tracker: Tracker<Self>,
|
||||
pub version: Version,
|
||||
pub seat: Rc<ZwpTabletSeatV2>,
|
||||
pub tablet: Rc<Tablet>,
|
||||
}
|
||||
|
||||
impl ZwpTabletV2 {
|
||||
fn detach(&self) {
|
||||
self.tablet.bindings.remove(&self.seat);
|
||||
}
|
||||
|
||||
pub fn send_name(&self, name: &str) {
|
||||
self.client.event(Name {
|
||||
self_id: self.id,
|
||||
name,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_id(&self, vid: u32, pid: u32) {
|
||||
self.client.event(Id {
|
||||
self_id: self.id,
|
||||
vid,
|
||||
pid,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_path(&self, path: &str) {
|
||||
self.client.event(Path {
|
||||
self_id: self.id,
|
||||
path,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_done(&self) {
|
||||
self.client.event(Done { self_id: self.id });
|
||||
}
|
||||
|
||||
pub fn send_removed(&self) {
|
||||
self.client.event(Removed { self_id: self.id });
|
||||
}
|
||||
}
|
||||
|
||||
impl ZwpTabletV2RequestHandler for ZwpTabletV2 {
|
||||
type Error = ZwpTabletV2Error;
|
||||
|
||||
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.detach();
|
||||
self.client.remove_obj(self)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
object_base! {
|
||||
self = ZwpTabletV2;
|
||||
version = self.version;
|
||||
}
|
||||
|
||||
impl Object for ZwpTabletV2 {
|
||||
fn break_loops(&self) {
|
||||
self.detach();
|
||||
}
|
||||
}
|
||||
|
||||
simple_add_obj!(ZwpTabletV2);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ZwpTabletV2Error {
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
}
|
||||
efrom!(ZwpTabletV2Error, ClientError);
|
||||
|
|
@ -26,9 +26,15 @@ use {
|
|||
wl_buffer::WlBuffer,
|
||||
wl_callback::WlCallback,
|
||||
wl_seat::{
|
||||
text_input::TextInputConnection, wl_pointer::PendingScroll,
|
||||
zwp_pointer_constraints_v1::SeatConstraint, Dnd, NodeSeatState, SeatId,
|
||||
WlSeatGlobal,
|
||||
tablet::{
|
||||
PadButtonState, TabletPad, TabletPadGroup, TabletPadRing, TabletPadStrip,
|
||||
TabletRingEventSource, TabletStripEventSource, TabletTool, TabletToolChanges,
|
||||
ToolButtonState,
|
||||
},
|
||||
text_input::TextInputConnection,
|
||||
wl_pointer::PendingScroll,
|
||||
zwp_pointer_constraints_v1::SeatConstraint,
|
||||
Dnd, NodeSeatState, SeatId, WlSeatGlobal,
|
||||
},
|
||||
wl_surface::{
|
||||
commit_timeline::{ClearReason, CommitTimeline, CommitTimelineError},
|
||||
|
|
@ -1497,14 +1503,6 @@ impl Node for WlSurface {
|
|||
dnd.seat.dnd_surface_motion(self, dnd, time_usec, x, y);
|
||||
}
|
||||
|
||||
fn node_into_surface(self: Rc<Self>) -> Option<Rc<WlSurface>> {
|
||||
Some(self.clone())
|
||||
}
|
||||
|
||||
fn node_is_xwayland_surface(&self) -> bool {
|
||||
self.client.is_xwayland
|
||||
}
|
||||
|
||||
fn node_on_swipe_begin(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, finger_count: u32) {
|
||||
seat.swipe_begin_surface(self, time_usec, finger_count)
|
||||
}
|
||||
|
|
@ -1544,6 +1542,99 @@ impl Node for WlSurface {
|
|||
fn node_on_hold_end(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, cancelled: bool) {
|
||||
seat.hold_end_surface(self, time_usec, cancelled)
|
||||
}
|
||||
|
||||
fn node_on_tablet_pad_enter(&self, pad: &Rc<TabletPad>) {
|
||||
pad.surface_enter(self);
|
||||
}
|
||||
|
||||
fn node_on_tablet_pad_leave(&self, pad: &Rc<TabletPad>) {
|
||||
pad.surface_leave(self);
|
||||
}
|
||||
|
||||
fn node_on_tablet_pad_button(
|
||||
&self,
|
||||
pad: &Rc<TabletPad>,
|
||||
time_usec: u64,
|
||||
button: u32,
|
||||
state: PadButtonState,
|
||||
) {
|
||||
pad.surface_button(self, time_usec, button, state);
|
||||
}
|
||||
|
||||
fn node_on_tablet_pad_mode_switch(
|
||||
&self,
|
||||
pad: &Rc<TabletPad>,
|
||||
group: &Rc<TabletPadGroup>,
|
||||
time_usec: u64,
|
||||
mode: u32,
|
||||
) {
|
||||
pad.surface_mode_switch(self, group, time_usec, mode);
|
||||
}
|
||||
|
||||
fn node_on_tablet_pad_ring(
|
||||
&self,
|
||||
pad: &Rc<TabletPad>,
|
||||
ring: &Rc<TabletPadRing>,
|
||||
source: Option<TabletRingEventSource>,
|
||||
angle: Option<f64>,
|
||||
time_usec: u64,
|
||||
) {
|
||||
pad.surface_ring(self, ring, source, angle, time_usec);
|
||||
}
|
||||
|
||||
fn node_on_tablet_pad_strip(
|
||||
&self,
|
||||
pad: &Rc<TabletPad>,
|
||||
strip: &Rc<TabletPadStrip>,
|
||||
source: Option<TabletStripEventSource>,
|
||||
position: Option<f64>,
|
||||
time_usec: u64,
|
||||
) {
|
||||
pad.surface_strip(self, strip, source, position, time_usec);
|
||||
}
|
||||
|
||||
fn node_on_tablet_tool_leave(&self, tool: &Rc<TabletTool>, time_usec: u64) {
|
||||
tool.surface_leave(self, time_usec);
|
||||
}
|
||||
|
||||
fn node_on_tablet_tool_enter(
|
||||
self: Rc<Self>,
|
||||
tool: &Rc<TabletTool>,
|
||||
time_usec: u64,
|
||||
x: Fixed,
|
||||
y: Fixed,
|
||||
) {
|
||||
tool.surface_enter(&self, time_usec, x, y);
|
||||
}
|
||||
|
||||
fn node_on_tablet_tool_button(
|
||||
&self,
|
||||
tool: &Rc<TabletTool>,
|
||||
time_usec: u64,
|
||||
button: u32,
|
||||
state: ToolButtonState,
|
||||
) {
|
||||
tool.surface_button(self, time_usec, button, state);
|
||||
}
|
||||
|
||||
fn node_on_tablet_tool_apply_changes(
|
||||
self: Rc<Self>,
|
||||
tool: &Rc<TabletTool>,
|
||||
time_usec: u64,
|
||||
changes: Option<&TabletToolChanges>,
|
||||
x: Fixed,
|
||||
y: Fixed,
|
||||
) {
|
||||
tool.surface_apply_changes(&self, time_usec, changes, x, y);
|
||||
}
|
||||
|
||||
fn node_into_surface(self: Rc<Self>) -> Option<Rc<WlSurface>> {
|
||||
Some(self.clone())
|
||||
}
|
||||
|
||||
fn node_is_xwayland_surface(&self) -> bool {
|
||||
self.client.is_xwayland
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use {
|
|||
cursor::KnownCursor,
|
||||
fixed::Fixed,
|
||||
ifs::{
|
||||
wl_seat::{NodeSeatState, SeatId, WlSeatGlobal},
|
||||
wl_seat::{tablet::TabletTool, NodeSeatState, SeatId, WlSeatGlobal},
|
||||
wl_surface::{x_surface::XSurface, WlSurface, WlSurfaceError},
|
||||
},
|
||||
rect::Rect,
|
||||
|
|
@ -369,6 +369,16 @@ impl Node for Xwindow {
|
|||
seat.pointer_cursor().set_known(KnownCursor::Default);
|
||||
}
|
||||
|
||||
fn node_on_tablet_tool_enter(
|
||||
self: Rc<Self>,
|
||||
tool: &Rc<TabletTool>,
|
||||
_time_usec: u64,
|
||||
_x: Fixed,
|
||||
_y: Fixed,
|
||||
) {
|
||||
tool.cursor().set_known(KnownCursor::Default)
|
||||
}
|
||||
|
||||
fn node_into_toplevel(self: Rc<Self>) -> Option<Rc<dyn ToplevelNode>> {
|
||||
Some(self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use {
|
|||
cursor::KnownCursor,
|
||||
fixed::Fixed,
|
||||
ifs::{
|
||||
wl_seat::{NodeSeatState, WlSeatGlobal},
|
||||
wl_seat::{tablet::TabletTool, NodeSeatState, WlSeatGlobal},
|
||||
wl_surface::xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceExt},
|
||||
xdg_positioner::{
|
||||
XdgPositioned, XdgPositioner, CA_FLIP_X, CA_FLIP_Y, CA_RESIZE_X, CA_RESIZE_Y,
|
||||
|
|
@ -346,6 +346,16 @@ impl Node for XdgPopup {
|
|||
// log::info!("xdg-popup focus");
|
||||
seat.pointer_cursor().set_known(KnownCursor::Default);
|
||||
}
|
||||
|
||||
fn node_on_tablet_tool_enter(
|
||||
self: Rc<Self>,
|
||||
tool: &Rc<TabletTool>,
|
||||
_time_usec: u64,
|
||||
_x: Fixed,
|
||||
_y: Fixed,
|
||||
) {
|
||||
tool.cursor().set_known(KnownCursor::Default)
|
||||
}
|
||||
}
|
||||
|
||||
impl StackedNode for XdgPopup {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use {
|
|||
fixed::Fixed,
|
||||
ifs::{
|
||||
ext_foreign_toplevel_list_v1::ExtForeignToplevelListV1,
|
||||
wl_seat::{NodeSeatState, SeatId, WlSeatGlobal},
|
||||
wl_seat::{tablet::TabletTool, NodeSeatState, SeatId, WlSeatGlobal},
|
||||
wl_surface::{
|
||||
xdg_surface::{
|
||||
xdg_toplevel::xdg_dialog_v1::XdgDialogV1, XdgSurface, XdgSurfaceError,
|
||||
|
|
@ -529,6 +529,16 @@ impl Node for XdgToplevel {
|
|||
seat.pointer_cursor().set_known(KnownCursor::Default);
|
||||
}
|
||||
|
||||
fn node_on_tablet_tool_enter(
|
||||
self: Rc<Self>,
|
||||
tool: &Rc<TabletTool>,
|
||||
_time_usec: u64,
|
||||
_x: Fixed,
|
||||
_y: Fixed,
|
||||
) {
|
||||
tool.cursor().set_known(KnownCursor::Default)
|
||||
}
|
||||
|
||||
fn node_into_toplevel(self: Rc<Self>) -> Option<Rc<dyn ToplevelNode>> {
|
||||
Some(self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use {
|
|||
crate::{
|
||||
client::{Client, ClientError},
|
||||
cursor::KnownCursor,
|
||||
ifs::wl_seat::WlSeatGlobal,
|
||||
ifs::wl_seat::{tablet::TabletToolOpt, WlSeatGlobal},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
wire::{wp_cursor_shape_device_v1::*, WpCursorShapeDeviceV1Id},
|
||||
|
|
@ -46,10 +46,15 @@ const ALL_SCROLL: u32 = 32;
|
|||
const ZOOM_IN: u32 = 33;
|
||||
const ZOOM_OUT: u32 = 34;
|
||||
|
||||
pub enum CursorShapeCursorUser {
|
||||
Seat(Rc<WlSeatGlobal>),
|
||||
TabletTool(Rc<TabletToolOpt>),
|
||||
}
|
||||
|
||||
pub struct WpCursorShapeDeviceV1 {
|
||||
pub id: WpCursorShapeDeviceV1Id,
|
||||
pub client: Rc<Client>,
|
||||
pub seat: Rc<WlSeatGlobal>,
|
||||
pub cursor_user: CursorShapeCursorUser,
|
||||
pub tracker: Tracker<Self>,
|
||||
pub version: Version,
|
||||
}
|
||||
|
|
@ -100,14 +105,24 @@ impl WpCursorShapeDeviceV1RequestHandler for WpCursorShapeDeviceV1 {
|
|||
ZOOM_OUT => KnownCursor::ZoomOut,
|
||||
_ => return Err(WpCursorShapeDeviceV1Error::UnknownShape(req.shape)),
|
||||
};
|
||||
let pointer_node = match self.seat.pointer_node() {
|
||||
Some(n) => n,
|
||||
_ => return Ok(()),
|
||||
let tablet_tool;
|
||||
let (node_client_id, user) = match &self.cursor_user {
|
||||
CursorShapeCursorUser::Seat(s) => match s.pointer_node() {
|
||||
Some(n) => (n.node_client_id(), s.pointer_cursor()),
|
||||
_ => return Ok(()),
|
||||
},
|
||||
CursorShapeCursorUser::TabletTool(t) => match t.get() {
|
||||
Some(t) => {
|
||||
tablet_tool = t;
|
||||
(tablet_tool.node().node_client_id(), tablet_tool.cursor())
|
||||
}
|
||||
_ => return Ok(()),
|
||||
},
|
||||
};
|
||||
if pointer_node.node_client_id() != Some(self.client.id) {
|
||||
if node_client_id != Some(self.client.id) {
|
||||
return Ok(());
|
||||
}
|
||||
self.seat.pointer_cursor().set_known(cursor);
|
||||
user.set_known(cursor);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ use {
|
|||
crate::{
|
||||
client::{Client, ClientError},
|
||||
globals::{Global, GlobalName},
|
||||
ifs::wp_cursor_shape_device_v1::WpCursorShapeDeviceV1,
|
||||
ifs::wp_cursor_shape_device_v1::{CursorShapeCursorUser, WpCursorShapeDeviceV1},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
wire::{wp_cursor_shape_manager_v1::*, WpCursorShapeManagerV1Id},
|
||||
wire::{wp_cursor_shape_manager_v1::*, WpCursorShapeDeviceV1Id, WpCursorShapeManagerV1Id},
|
||||
},
|
||||
std::rc::Rc,
|
||||
thiserror::Error,
|
||||
|
|
@ -63,6 +63,25 @@ pub struct WpCursorShapeManagerV1 {
|
|||
pub version: Version,
|
||||
}
|
||||
|
||||
impl WpCursorShapeManagerV1 {
|
||||
fn get(
|
||||
&self,
|
||||
id: WpCursorShapeDeviceV1Id,
|
||||
cursor_user: CursorShapeCursorUser,
|
||||
) -> Result<(), WpCursorShapeManagerV1Error> {
|
||||
let device = Rc::new(WpCursorShapeDeviceV1 {
|
||||
id,
|
||||
client: self.client.clone(),
|
||||
cursor_user,
|
||||
tracker: Default::default(),
|
||||
version: self.version,
|
||||
});
|
||||
track!(self.client, device);
|
||||
self.client.add_client_obj(&device)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl WpCursorShapeManagerV1RequestHandler for WpCursorShapeManagerV1 {
|
||||
type Error = WpCursorShapeManagerV1Error;
|
||||
|
||||
|
|
@ -73,24 +92,18 @@ impl WpCursorShapeManagerV1RequestHandler for WpCursorShapeManagerV1 {
|
|||
|
||||
fn get_pointer(&self, req: GetPointer, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
let pointer = self.client.lookup(req.pointer)?;
|
||||
let device = Rc::new(WpCursorShapeDeviceV1 {
|
||||
id: req.cursor_shape_device,
|
||||
client: self.client.clone(),
|
||||
seat: pointer.seat.global.clone(),
|
||||
tracker: Default::default(),
|
||||
version: self.version,
|
||||
});
|
||||
track!(self.client, device);
|
||||
self.client.add_client_obj(&device)?;
|
||||
Ok(())
|
||||
self.get(
|
||||
req.cursor_shape_device,
|
||||
CursorShapeCursorUser::Seat(pointer.seat.global.clone()),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_tablet_tool_v2(
|
||||
&self,
|
||||
_req: GetTabletToolV2,
|
||||
_slf: &Rc<Self>,
|
||||
) -> Result<(), Self::Error> {
|
||||
Err(WpCursorShapeManagerV1Error::TabletToolNotSupported)
|
||||
fn get_tablet_tool_v2(&self, req: GetTabletToolV2, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
let tool = self.client.lookup(req.tablet_tool)?;
|
||||
self.get(
|
||||
req.cursor_shape_device,
|
||||
CursorShapeCursorUser::TabletTool(tool.tool.clone()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +120,5 @@ simple_add_obj!(WpCursorShapeManagerV1);
|
|||
pub enum WpCursorShapeManagerV1Error {
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
#[error("This compositor does not support tablet tools")]
|
||||
TabletToolNotSupported,
|
||||
}
|
||||
efrom!(WpCursorShapeManagerV1Error, ClientError);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue