wl-seat: split device and object handlers
This commit is contained in:
parent
054a3a919f
commit
ff04218023
4 changed files with 357 additions and 346 deletions
|
|
@ -1,9 +1,12 @@
|
||||||
mod event_handling;
|
mod event_handling;
|
||||||
|
mod device_handler;
|
||||||
pub mod ext_transient_seat_manager_v1;
|
pub mod ext_transient_seat_manager_v1;
|
||||||
pub mod ext_transient_seat_v1;
|
pub mod ext_transient_seat_v1;
|
||||||
mod gesture_owner;
|
mod gesture_owner;
|
||||||
mod kb_owner;
|
mod kb_owner;
|
||||||
mod pointer_owner;
|
mod pointer_owner;
|
||||||
|
mod position_hint;
|
||||||
|
mod seat_object;
|
||||||
pub mod tablet;
|
pub mod tablet;
|
||||||
pub mod text_input;
|
pub mod text_input;
|
||||||
mod touch_owner;
|
mod touch_owner;
|
||||||
|
|
@ -107,7 +110,6 @@ use {
|
||||||
},
|
},
|
||||||
wire_ei::EiSeatId,
|
wire_ei::EiSeatId,
|
||||||
},
|
},
|
||||||
CursorPositionType::Warp,
|
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
jay_config::{
|
jay_config::{
|
||||||
input::FallbackOutputMode as ConfigFallbackOutputMode,
|
input::FallbackOutputMode as ConfigFallbackOutputMode,
|
||||||
|
|
@ -128,7 +130,12 @@ use {
|
||||||
};
|
};
|
||||||
pub use {
|
pub use {
|
||||||
event_handling::NodeSeatState,
|
event_handling::NodeSeatState,
|
||||||
|
position_hint::{
|
||||||
|
CursorPositionType, PositionHintRequest, handle_position_hint_requests,
|
||||||
|
handle_warp_mouse_to_focus,
|
||||||
|
},
|
||||||
pointer_owner::{ToplevelSelector, WorkspaceSelector},
|
pointer_owner::{ToplevelSelector, WorkspaceSelector},
|
||||||
|
seat_object::WlSeatError,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const POINTER: u32 = 1;
|
pub const POINTER: u32 = 1;
|
||||||
|
|
@ -1782,147 +1789,6 @@ pub struct WlSeat {
|
||||||
tracker: Tracker<Self>,
|
tracker: Tracker<Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const READ_ONLY_KEYMAP_SINCE: Version = Version(7);
|
|
||||||
|
|
||||||
impl WlSeat {
|
|
||||||
fn send_capabilities(self: &Rc<Self>) {
|
|
||||||
self.client.event(Capabilities {
|
|
||||||
self_id: self.id,
|
|
||||||
capabilities: self.global.capabilities.get(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_name(self: &Rc<Self>, name: &str) {
|
|
||||||
self.client.event(Name {
|
|
||||||
self_id: self.id,
|
|
||||||
name,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn keymap_fd(&self, state: &KeyboardState) -> Result<KeymapFd, WlKeyboardError> {
|
|
||||||
let fd = match self.client.is_xwayland {
|
|
||||||
true => &state.map.xwayland_map,
|
|
||||||
_ => &state.map.map,
|
|
||||||
};
|
|
||||||
if self.version >= READ_ONLY_KEYMAP_SINCE {
|
|
||||||
return Ok(fd.clone());
|
|
||||||
}
|
|
||||||
Ok(fd.create_unprotected_fd()?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WlSeatRequestHandler for WlSeat {
|
|
||||||
type Error = WlSeatError;
|
|
||||||
|
|
||||||
fn get_pointer(&self, req: GetPointer, slf: &Rc<Self>) -> Result<(), Self::Error> {
|
|
||||||
let p = Rc::new(WlPointer::new(req.id, slf));
|
|
||||||
track!(self.client, p);
|
|
||||||
self.client.add_client_obj(&p)?;
|
|
||||||
self.pointers.set(req.id, p.clone());
|
|
||||||
let surface = self
|
|
||||||
.global
|
|
||||||
.pointer_node()
|
|
||||||
.and_then(|n| n.node_into_surface());
|
|
||||||
if let Some(surface) = surface
|
|
||||||
&& surface.client.id == self.client.id
|
|
||||||
{
|
|
||||||
let (x, y) = self.global.pointer_cursor.position();
|
|
||||||
let (x_int, y_int) = surface
|
|
||||||
.buffer_abs_pos
|
|
||||||
.get()
|
|
||||||
.translate(x.round_down(), y.round_down());
|
|
||||||
p.send_enter(
|
|
||||||
self.client.next_serial(),
|
|
||||||
surface.id,
|
|
||||||
x.apply_fract(x_int),
|
|
||||||
y.apply_fract(y_int),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_keyboard(&self, req: GetKeyboard, slf: &Rc<Self>) -> Result<(), Self::Error> {
|
|
||||||
let p = Rc::new(WlKeyboard::new(req.id, slf));
|
|
||||||
track!(self.client, p);
|
|
||||||
self.client.add_client_obj(&p)?;
|
|
||||||
self.keyboards.set(req.id, p.clone());
|
|
||||||
if let Some(surface) = self.global.keyboard_node.get().node_into_surface()
|
|
||||||
&& surface.client.id == self.client.id
|
|
||||||
{
|
|
||||||
p.enter(
|
|
||||||
self.client.next_serial(),
|
|
||||||
surface.id,
|
|
||||||
&self.global.seat_kb_state.get().borrow().kb_state,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if self.version >= REPEAT_INFO_SINCE {
|
|
||||||
let (rate, delay) = self.global.repeat_rate.get();
|
|
||||||
p.send_repeat_info(rate, delay);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_touch(&self, req: GetTouch, slf: &Rc<Self>) -> Result<(), Self::Error> {
|
|
||||||
let p = Rc::new(WlTouch::new(req.id, slf));
|
|
||||||
track!(self.client, p);
|
|
||||||
self.client.add_client_obj(&p)?;
|
|
||||||
self.touches.set(req.id, p);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn release(&self, _req: Release, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
|
||||||
{
|
|
||||||
let mut bindings = self.global.bindings.borrow_mut();
|
|
||||||
if let Entry::Occupied(mut hm) = bindings.entry(self.client.id) {
|
|
||||||
hm.get_mut().remove(&self.id);
|
|
||||||
if hm.get().is_empty() {
|
|
||||||
hm.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.client.remove_obj(self)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object_base! {
|
|
||||||
self = WlSeat;
|
|
||||||
version = self.version;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Object for WlSeat {
|
|
||||||
fn break_loops(&self) {
|
|
||||||
{
|
|
||||||
let mut bindings = self.global.bindings.borrow_mut();
|
|
||||||
if let Entry::Occupied(mut hm) = bindings.entry(self.client.id) {
|
|
||||||
hm.get_mut().remove(&self.id);
|
|
||||||
if hm.get().is_empty() {
|
|
||||||
hm.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.pointers.clear();
|
|
||||||
self.relative_pointers.clear();
|
|
||||||
self.keyboards.clear();
|
|
||||||
self.touches.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dedicated_add_obj!(WlSeat, WlSeatId, seats);
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum WlSeatError {
|
|
||||||
#[error(transparent)]
|
|
||||||
ClientError(Box<ClientError>),
|
|
||||||
#[error(transparent)]
|
|
||||||
TransferError(#[from] TransferError),
|
|
||||||
#[error(transparent)]
|
|
||||||
WlKeyboardError(Box<WlKeyboardError>),
|
|
||||||
#[error("Data source has a toplevel attached")]
|
|
||||||
OfferHasDrag,
|
|
||||||
}
|
|
||||||
efrom!(WlSeatError, ClientError);
|
|
||||||
efrom!(WlSeatError, WlKeyboardError);
|
|
||||||
|
|
||||||
pub fn collect_kb_foci2(node: Rc<dyn Node>, seats: &mut SmallVec<[Rc<WlSeatGlobal>; 3]>) {
|
pub fn collect_kb_foci2(node: Rc<dyn Node>, seats: &mut SmallVec<[Rc<WlSeatGlobal>; 3]>) {
|
||||||
node.node_visit(&mut generic_node_visitor(|node| {
|
node.node_visit(&mut generic_node_visitor(|node| {
|
||||||
|
|
@ -1935,207 +1801,3 @@ pub fn collect_kb_foci(node: Rc<dyn Node>) -> SmallVec<[Rc<WlSeatGlobal>; 3]> {
|
||||||
collect_kb_foci2(node, &mut res);
|
collect_kb_foci2(node, &mut res);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeviceHandlerData {
|
|
||||||
pub fn set_seat(&self, _state: &State, seat: Option<Rc<WlSeatGlobal>>) {
|
|
||||||
if let Some(new) = &seat {
|
|
||||||
if let Some(old) = self.seat.get()
|
|
||||||
&& old.id() == new.id()
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if self.seat.is_none() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.destroy_physical_keyboard_state();
|
|
||||||
let old = self.seat.set(seat.clone());
|
|
||||||
if let Some(old) = old {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
if self.is_touch {
|
|
||||||
old.num_touch_devices.fetch_sub(1);
|
|
||||||
old.update_capabilities();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
if self.is_touch {
|
|
||||||
seat.num_touch_devices.fetch_add(1);
|
|
||||||
seat.update_capabilities();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.attach_event_listeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn destroy_physical_keyboard_state(&self) {
|
|
||||||
self.mods_listener.detach();
|
|
||||||
if let Some(seat) = self.seat.get() {
|
|
||||||
seat.destroy_physical_keyboard(self.keyboard_id);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn attach_event_listeners(&self) {
|
|
||||||
if self.is_kb
|
|
||||||
&& let Some(seat) = self.seat.get()
|
|
||||||
{
|
|
||||||
seat.attach_modifiers_listener(
|
|
||||||
self.keyboard_id,
|
|
||||||
&self.mods_listener,
|
|
||||||
self.keymap.get().as_ref(),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_keymap(&self, _state: &State, keymap: Option<Rc<KbvmMap>>) {
|
|
||||||
self.destroy_physical_keyboard_state();
|
|
||||||
self.keymap.set(keymap);
|
|
||||||
self.attach_event_listeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_output(&self, _state: &State, output: Option<&WlOutputGlobal>) {
|
|
||||||
match output {
|
|
||||||
None => {
|
|
||||||
log::info!("Removing output mapping of {}", self.device.name());
|
|
||||||
self.output.take();
|
|
||||||
}
|
|
||||||
Some(o) => {
|
|
||||||
log::info!("Mapping {} to {}", self.device.name(), o.connector.name);
|
|
||||||
self.output.set(Some(o.opt.clone()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_rect(&self, state: &State) -> Rect {
|
|
||||||
if let Some(output) = self.output.get()
|
|
||||||
&& let Some(output) = output.get()
|
|
||||||
{
|
|
||||||
return output.pos.get();
|
|
||||||
}
|
|
||||||
state.root.extents.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_accel_profile(&self, _state: &State, v: InputDeviceAccelProfile) {
|
|
||||||
self.device.set_accel_profile(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_accel_speed(&self, _state: &State, v: f64) {
|
|
||||||
self.device.set_accel_speed(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_tap_enabled(&self, _state: &State, v: bool) {
|
|
||||||
self.device.set_tap_enabled(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_drag_enabled(&self, _state: &State, v: bool) {
|
|
||||||
self.device.set_drag_enabled(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_drag_lock_enabled(&self, _state: &State, v: bool) {
|
|
||||||
self.device.set_drag_lock_enabled(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_left_handed(&self, _state: &State, v: bool) {
|
|
||||||
self.device.set_left_handed(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_natural_scrolling_enabled(&self, _state: &State, v: bool) {
|
|
||||||
self.device.set_natural_scrolling_enabled(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_px_per_scroll_wheel(&self, _state: &State, v: f64) {
|
|
||||||
self.px_per_scroll_wheel.set(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_transform_matrix(&self, _state: &State, v: TransformMatrix) {
|
|
||||||
self.device.set_transform_matrix(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_calibration_matrix(&self, _state: &State, v: [[f32; 3]; 2]) {
|
|
||||||
self.device.set_calibration_matrix(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_click_method(&self, _state: &State, v: InputDeviceClickMethod) {
|
|
||||||
self.device.set_click_method(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_middle_button_emulation_enabled(&self, _state: &State, v: bool) {
|
|
||||||
self.device.set_middle_button_emulation_enabled(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LedsListener for DeviceHandlerData {
|
|
||||||
fn leds(&self, leds: Leds) {
|
|
||||||
self.device.set_enabled_leds(leds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LedsListener for WlSeatGlobal {
|
|
||||||
fn leds(&self, leds: Leds) {
|
|
||||||
self.dispatch_seat_leds_listeners(leds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PositionHintRequest {
|
|
||||||
seat: Rc<WlSeatGlobal>,
|
|
||||||
client_id: ClientId,
|
|
||||||
old_pos: (Fixed, Fixed),
|
|
||||||
new_pos: (Fixed, Fixed),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handle_position_hint_requests(state: Rc<State>) {
|
|
||||||
loop {
|
|
||||||
let req = state.position_hint_requests.pop().await;
|
|
||||||
let (x, y) = (req.new_pos.0.round_down(), req.new_pos.1.round_down());
|
|
||||||
if state.node_at(x, y).node.node_client_id() != Some(req.client_id) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let current_pos = req.seat.pointer_cursor.position();
|
|
||||||
let (x, y) = (
|
|
||||||
req.new_pos.0 + (current_pos.0 - req.old_pos.0),
|
|
||||||
req.new_pos.1 + (current_pos.1 - req.old_pos.1),
|
|
||||||
);
|
|
||||||
req.seat.motion_event_abs(state.now_usec(), x, y, Warp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handle_warp_mouse_to_focus(state: Rc<State>) {
|
|
||||||
loop {
|
|
||||||
state.pending_warp_mouse_to_focus.non_empty().await;
|
|
||||||
state.eng.yield_now().await;
|
|
||||||
while let Some(seat) = state.pending_warp_mouse_to_focus.try_pop() {
|
|
||||||
seat.warp_mouse_to_focus_scheduled.set(false);
|
|
||||||
let skip_target_check = seat.warp_mouse_to_focus_skip_target_check.take();
|
|
||||||
let Some(tl) = seat.keyboard_node.get().node_toplevel() else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
let (x, y) = tl.node_absolute_position().center();
|
|
||||||
if !skip_target_check {
|
|
||||||
let Some(target) = state.node_at(x, y).node.node_toplevel() else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
if target.node_id() != tl.node_id() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let (x, y) = (Fixed::from_int(x), Fixed::from_int(y));
|
|
||||||
seat.motion_event_abs(state.now_usec(), x, y, Warp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
||||||
pub enum CursorPositionType {
|
|
||||||
Motion,
|
|
||||||
Warp,
|
|
||||||
}
|
|
||||||
|
|
|
||||||
151
src/ifs/wl_seat/device_handler.rs
Normal file
151
src/ifs/wl_seat/device_handler.rs
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl DeviceHandlerData {
|
||||||
|
pub fn set_seat(&self, _state: &State, seat: Option<Rc<WlSeatGlobal>>) {
|
||||||
|
if let Some(new) = &seat {
|
||||||
|
if let Some(old) = self.seat.get()
|
||||||
|
&& old.id() == new.id()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if self.seat.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.destroy_physical_keyboard_state();
|
||||||
|
let old = self.seat.set(seat.clone());
|
||||||
|
if let Some(old) = old {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
if self.is_touch {
|
||||||
|
old.num_touch_devices.fetch_sub(1);
|
||||||
|
old.update_capabilities();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
if self.is_touch {
|
||||||
|
seat.num_touch_devices.fetch_add(1);
|
||||||
|
seat.update_capabilities();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.attach_event_listeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn destroy_physical_keyboard_state(&self) {
|
||||||
|
self.mods_listener.detach();
|
||||||
|
if let Some(seat) = self.seat.get() {
|
||||||
|
seat.destroy_physical_keyboard(self.keyboard_id);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn attach_event_listeners(&self) {
|
||||||
|
if self.is_kb
|
||||||
|
&& let Some(seat) = self.seat.get()
|
||||||
|
{
|
||||||
|
seat.attach_modifiers_listener(
|
||||||
|
self.keyboard_id,
|
||||||
|
&self.mods_listener,
|
||||||
|
self.keymap.get().as_ref(),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_keymap(&self, _state: &State, keymap: Option<Rc<KbvmMap>>) {
|
||||||
|
self.destroy_physical_keyboard_state();
|
||||||
|
self.keymap.set(keymap);
|
||||||
|
self.attach_event_listeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_output(&self, _state: &State, output: Option<&WlOutputGlobal>) {
|
||||||
|
match output {
|
||||||
|
None => {
|
||||||
|
log::info!("Removing output mapping of {}", self.device.name());
|
||||||
|
self.output.take();
|
||||||
|
}
|
||||||
|
Some(o) => {
|
||||||
|
log::info!("Mapping {} to {}", self.device.name(), o.connector.name);
|
||||||
|
self.output.set(Some(o.opt.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_rect(&self, state: &State) -> Rect {
|
||||||
|
if let Some(output) = self.output.get()
|
||||||
|
&& let Some(output) = output.get()
|
||||||
|
{
|
||||||
|
return output.pos.get();
|
||||||
|
}
|
||||||
|
state.root.extents.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_accel_profile(&self, _state: &State, v: InputDeviceAccelProfile) {
|
||||||
|
self.device.set_accel_profile(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_accel_speed(&self, _state: &State, v: f64) {
|
||||||
|
self.device.set_accel_speed(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_tap_enabled(&self, _state: &State, v: bool) {
|
||||||
|
self.device.set_tap_enabled(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_drag_enabled(&self, _state: &State, v: bool) {
|
||||||
|
self.device.set_drag_enabled(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_drag_lock_enabled(&self, _state: &State, v: bool) {
|
||||||
|
self.device.set_drag_lock_enabled(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_left_handed(&self, _state: &State, v: bool) {
|
||||||
|
self.device.set_left_handed(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_natural_scrolling_enabled(&self, _state: &State, v: bool) {
|
||||||
|
self.device.set_natural_scrolling_enabled(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_px_per_scroll_wheel(&self, _state: &State, v: f64) {
|
||||||
|
self.px_per_scroll_wheel.set(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_transform_matrix(&self, _state: &State, v: TransformMatrix) {
|
||||||
|
self.device.set_transform_matrix(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_calibration_matrix(&self, _state: &State, v: [[f32; 3]; 2]) {
|
||||||
|
self.device.set_calibration_matrix(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_click_method(&self, _state: &State, v: InputDeviceClickMethod) {
|
||||||
|
self.device.set_click_method(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_middle_button_emulation_enabled(&self, _state: &State, v: bool) {
|
||||||
|
self.device.set_middle_button_emulation_enabled(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LedsListener for DeviceHandlerData {
|
||||||
|
fn leds(&self, leds: Leds) {
|
||||||
|
self.device.set_enabled_leds(leds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LedsListener for WlSeatGlobal {
|
||||||
|
fn leds(&self, leds: Leds) {
|
||||||
|
self.dispatch_seat_leds_listeners(leds)
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/ifs/wl_seat/position_hint.rs
Normal file
55
src/ifs/wl_seat/position_hint.rs
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
use {super::*, CursorPositionType::Warp};
|
||||||
|
|
||||||
|
pub struct PositionHintRequest {
|
||||||
|
pub(super) seat: Rc<WlSeatGlobal>,
|
||||||
|
pub(super) client_id: ClientId,
|
||||||
|
pub(super) old_pos: (Fixed, Fixed),
|
||||||
|
pub(super) new_pos: (Fixed, Fixed),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn handle_position_hint_requests(state: Rc<State>) {
|
||||||
|
loop {
|
||||||
|
let req = state.position_hint_requests.pop().await;
|
||||||
|
let (x, y) = (req.new_pos.0.round_down(), req.new_pos.1.round_down());
|
||||||
|
if state.node_at(x, y).node.node_client_id() != Some(req.client_id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let current_pos = req.seat.pointer_cursor.position();
|
||||||
|
let (x, y) = (
|
||||||
|
req.new_pos.0 + (current_pos.0 - req.old_pos.0),
|
||||||
|
req.new_pos.1 + (current_pos.1 - req.old_pos.1),
|
||||||
|
);
|
||||||
|
req.seat.motion_event_abs(state.now_usec(), x, y, Warp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn handle_warp_mouse_to_focus(state: Rc<State>) {
|
||||||
|
loop {
|
||||||
|
state.pending_warp_mouse_to_focus.non_empty().await;
|
||||||
|
state.eng.yield_now().await;
|
||||||
|
while let Some(seat) = state.pending_warp_mouse_to_focus.try_pop() {
|
||||||
|
seat.warp_mouse_to_focus_scheduled.set(false);
|
||||||
|
let skip_target_check = seat.warp_mouse_to_focus_skip_target_check.take();
|
||||||
|
let Some(tl) = seat.keyboard_node.get().node_toplevel() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let (x, y) = tl.node_absolute_position().center();
|
||||||
|
if !skip_target_check {
|
||||||
|
let Some(target) = state.node_at(x, y).node.node_toplevel() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if target.node_id() != tl.node_id() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let (x, y) = (Fixed::from_int(x), Fixed::from_int(y));
|
||||||
|
seat.motion_event_abs(state.now_usec(), x, y, Warp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum CursorPositionType {
|
||||||
|
Motion,
|
||||||
|
Warp,
|
||||||
|
}
|
||||||
143
src/ifs/wl_seat/seat_object.rs
Normal file
143
src/ifs/wl_seat/seat_object.rs
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const READ_ONLY_KEYMAP_SINCE: Version = Version(7);
|
||||||
|
|
||||||
|
impl WlSeat {
|
||||||
|
pub(super) fn send_capabilities(self: &Rc<Self>) {
|
||||||
|
self.client.event(Capabilities {
|
||||||
|
self_id: self.id,
|
||||||
|
capabilities: self.global.capabilities.get(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn send_name(self: &Rc<Self>, name: &str) {
|
||||||
|
self.client.event(Name {
|
||||||
|
self_id: self.id,
|
||||||
|
name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keymap_fd(&self, state: &KeyboardState) -> Result<KeymapFd, WlKeyboardError> {
|
||||||
|
let fd = match self.client.is_xwayland {
|
||||||
|
true => &state.map.xwayland_map,
|
||||||
|
_ => &state.map.map,
|
||||||
|
};
|
||||||
|
if self.version >= READ_ONLY_KEYMAP_SINCE {
|
||||||
|
return Ok(fd.clone());
|
||||||
|
}
|
||||||
|
Ok(fd.create_unprotected_fd()?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WlSeatRequestHandler for WlSeat {
|
||||||
|
type Error = WlSeatError;
|
||||||
|
|
||||||
|
fn get_pointer(&self, req: GetPointer, slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let p = Rc::new(WlPointer::new(req.id, slf));
|
||||||
|
track!(self.client, p);
|
||||||
|
self.client.add_client_obj(&p)?;
|
||||||
|
self.pointers.set(req.id, p.clone());
|
||||||
|
let surface = self
|
||||||
|
.global
|
||||||
|
.pointer_node()
|
||||||
|
.and_then(|n| n.node_into_surface());
|
||||||
|
if let Some(surface) = surface
|
||||||
|
&& surface.client.id == self.client.id
|
||||||
|
{
|
||||||
|
let (x, y) = self.global.pointer_cursor.position();
|
||||||
|
let (x_int, y_int) = surface
|
||||||
|
.buffer_abs_pos
|
||||||
|
.get()
|
||||||
|
.translate(x.round_down(), y.round_down());
|
||||||
|
p.send_enter(
|
||||||
|
self.client.next_serial(),
|
||||||
|
surface.id,
|
||||||
|
x.apply_fract(x_int),
|
||||||
|
y.apply_fract(y_int),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_keyboard(&self, req: GetKeyboard, slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let p = Rc::new(WlKeyboard::new(req.id, slf));
|
||||||
|
track!(self.client, p);
|
||||||
|
self.client.add_client_obj(&p)?;
|
||||||
|
self.keyboards.set(req.id, p.clone());
|
||||||
|
if let Some(surface) = self.global.keyboard_node.get().node_into_surface()
|
||||||
|
&& surface.client.id == self.client.id
|
||||||
|
{
|
||||||
|
p.enter(
|
||||||
|
self.client.next_serial(),
|
||||||
|
surface.id,
|
||||||
|
&self.global.seat_kb_state.get().borrow().kb_state,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if self.version >= REPEAT_INFO_SINCE {
|
||||||
|
let (rate, delay) = self.global.repeat_rate.get();
|
||||||
|
p.send_repeat_info(rate, delay);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_touch(&self, req: GetTouch, slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let p = Rc::new(WlTouch::new(req.id, slf));
|
||||||
|
track!(self.client, p);
|
||||||
|
self.client.add_client_obj(&p)?;
|
||||||
|
self.touches.set(req.id, p);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn release(&self, _req: Release, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
{
|
||||||
|
let mut bindings = self.global.bindings.borrow_mut();
|
||||||
|
if let Entry::Occupied(mut hm) = bindings.entry(self.client.id) {
|
||||||
|
hm.get_mut().remove(&self.id);
|
||||||
|
if hm.get().is_empty() {
|
||||||
|
hm.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = WlSeat;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for WlSeat {
|
||||||
|
fn break_loops(&self) {
|
||||||
|
{
|
||||||
|
let mut bindings = self.global.bindings.borrow_mut();
|
||||||
|
if let Entry::Occupied(mut hm) = bindings.entry(self.client.id) {
|
||||||
|
hm.get_mut().remove(&self.id);
|
||||||
|
if hm.get().is_empty() {
|
||||||
|
hm.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.pointers.clear();
|
||||||
|
self.relative_pointers.clear();
|
||||||
|
self.keyboards.clear();
|
||||||
|
self.touches.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dedicated_add_obj!(WlSeat, WlSeatId, seats);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum WlSeatError {
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
#[error(transparent)]
|
||||||
|
TransferError(#[from] TransferError),
|
||||||
|
#[error(transparent)]
|
||||||
|
WlKeyboardError(Box<WlKeyboardError>),
|
||||||
|
#[error("Data source has a toplevel attached")]
|
||||||
|
OfferHasDrag,
|
||||||
|
}
|
||||||
|
efrom!(WlSeatError, ClientError);
|
||||||
|
efrom!(WlSeatError, WlKeyboardError);
|
||||||
Loading…
Add table
Add a link
Reference in a new issue