seat: doc & warnings & fmt & cleanup methods
This commit is contained in:
parent
4b01b55f75
commit
532cb6b78e
|
@ -174,7 +174,7 @@ pub enum Error {
|
||||||
pub(crate) fn create_keyboard_handler(rules: &str, model: &str, layout: &str, variant: &str,
|
pub(crate) fn create_keyboard_handler(rules: &str, model: &str, layout: &str, variant: &str,
|
||||||
options: Option<String>, repeat_delay: i32, repeat_rate: i32,
|
options: Option<String>, repeat_delay: i32, repeat_rate: i32,
|
||||||
logger: ::slog::Logger)
|
logger: ::slog::Logger)
|
||||||
-> Result<KbdHandle, Error> {
|
-> Result<KeyboardHandle, Error> {
|
||||||
let log = logger.new(o!("smithay_module" => "xkbcommon_handler"));
|
let log = logger.new(o!("smithay_module" => "xkbcommon_handler"));
|
||||||
info!(log, "Initializing a xkbcommon handler with keymap query";
|
info!(log, "Initializing a xkbcommon handler with keymap query";
|
||||||
"rules" => rules, "model" => model, "layout" => layout, "variant" => variant,
|
"rules" => rules, "model" => model, "layout" => layout, "variant" => variant,
|
||||||
|
@ -208,7 +208,7 @@ pub(crate) fn create_keyboard_handler(rules: &str, model: &str, layout: &str, va
|
||||||
"fd" => keymap_file.as_raw_fd(), "len" => keymap_data.as_bytes().len()
|
"fd" => keymap_file.as_raw_fd(), "len" => keymap_data.as_bytes().len()
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(KbdHandle {
|
Ok(KeyboardHandle {
|
||||||
arc: Arc::new(KbdArc {
|
arc: Arc::new(KbdArc {
|
||||||
internal: Mutex::new(internal),
|
internal: Mutex::new(internal),
|
||||||
keymap_file: keymap_file,
|
keymap_file: keymap_file,
|
||||||
|
@ -230,20 +230,19 @@ struct KbdArc {
|
||||||
/// It can be cloned and all clones manipulate the same internal state. Clones
|
/// It can be cloned and all clones manipulate the same internal state. Clones
|
||||||
/// can also be sent across threads.
|
/// can also be sent across threads.
|
||||||
///
|
///
|
||||||
/// This handle gives you 3 main ways to interact with the keymap handling:
|
/// This handle gives you 2 main ways to interact with the keyboard handling:
|
||||||
///
|
///
|
||||||
/// - register new `wl_keyboard` instances to it with the `new_kbd` method.
|
|
||||||
/// - set the current focus for this keyboard: designing the surface that will receive the key inputs
|
/// - set the current focus for this keyboard: designing the surface that will receive the key inputs
|
||||||
/// using the `KbdHandle::set_focus` method.
|
/// using the `KeyboardHandle::set_focus` method.
|
||||||
/// - process key inputs from the input backend, allowing them to be catched at the compositor-level
|
/// - process key inputs from the input backend, allowing them to be catched at the compositor-level
|
||||||
/// or forwarded to the client. See the documentation of the `KbdHandle::input` method for
|
/// or forwarded to the client. See the documentation of the `KeyboardHandle::input` method for
|
||||||
/// details.
|
/// details.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct KbdHandle {
|
pub struct KeyboardHandle {
|
||||||
arc: Arc<KbdArc>,
|
arc: Arc<KbdArc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KbdHandle {
|
impl KeyboardHandle {
|
||||||
/// Handle a keystroke
|
/// Handle a keystroke
|
||||||
///
|
///
|
||||||
/// All keystrokes from the input backend should be fed _in order_ to this method of the
|
/// All keystrokes from the input backend should be fed _in order_ to this method of the
|
||||||
|
@ -265,7 +264,7 @@ impl KbdHandle {
|
||||||
|
|
||||||
// Offset the keycode by 8, as the evdev XKB rules reflect X's
|
// Offset the keycode by 8, as the evdev XKB rules reflect X's
|
||||||
// broken keycode system, which starts at 8.
|
// broken keycode system, which starts at 8.
|
||||||
let sym = guard.state.key_get_one_sym(keycode+8);
|
let sym = guard.state.key_get_one_sym(keycode + 8);
|
||||||
|
|
||||||
let mods_changed = guard.key_input(keycode, state);
|
let mods_changed = guard.key_input(keycode, state);
|
||||||
|
|
||||||
|
|
175
src/seat/mod.rs
175
src/seat/mod.rs
|
@ -1,20 +1,92 @@
|
||||||
|
//! Seat global utilities
|
||||||
|
//!
|
||||||
|
//! This module provides you with utilities for handling the seat globals
|
||||||
|
//! and the associated input wayland objects.
|
||||||
|
//!
|
||||||
|
//! ## How to use it
|
||||||
|
//!
|
||||||
|
//! ### Initialization
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # extern crate wayland_server;
|
||||||
|
//! # #[macro_use] extern crate smithay;
|
||||||
|
//!
|
||||||
|
//! use smithay::seat::Seat;
|
||||||
|
//!
|
||||||
|
//! # fn main(){
|
||||||
|
//! # let (_display, mut event_loop) = wayland_server::create_display();
|
||||||
|
//! // insert the seat:
|
||||||
|
//! let (seat_state_token, seat_global) = Seat::new(
|
||||||
|
//! &mut event_loop,
|
||||||
|
//! "seat-0".into(), // the name of the seat, will be advertize to clients
|
||||||
|
//! None /* insert a logger here*/
|
||||||
|
//! );
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ### Run usage
|
||||||
|
//!
|
||||||
|
//! Once the seat is initialized, you can add capabilities to it.
|
||||||
|
//!
|
||||||
|
//! Currently, only pointer and keyboard capabilities are supported by
|
||||||
|
//! smithay.
|
||||||
|
//!
|
||||||
|
//! You can add these capabilities via methods of the `Seat` struct that was
|
||||||
|
//! inserted in the event loop, that you can retreive via its token:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # extern crate wayland_server;
|
||||||
|
//! # #[macro_use] extern crate smithay;
|
||||||
|
//! #
|
||||||
|
//! # use smithay::seat::Seat;
|
||||||
|
//! #
|
||||||
|
//! # fn main(){
|
||||||
|
//! # let (_display, mut event_loop) = wayland_server::create_display();
|
||||||
|
//! # let (seat_state_token, seat_global) = Seat::new(
|
||||||
|
//! # &mut event_loop,
|
||||||
|
//! # "seat-0".into(), // the name of the seat, will be advertize to clients
|
||||||
|
//! # None /* insert a logger here*/
|
||||||
|
//! # );
|
||||||
|
//! let pointer_handle = event_loop.state().get_mut(&seat_state_token).add_pointer();
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! These handles can be cloned and sent accross thread, so you can keep one around
|
||||||
|
//! in your event-handling code to forward inputs to your clients.
|
||||||
|
|
||||||
mod keyboard;
|
mod keyboard;
|
||||||
mod pointer;
|
mod pointer;
|
||||||
|
|
||||||
pub use self::keyboard::{Error as KbdError, KbdHandle};
|
pub use self::keyboard::{Error as KeyboardError, KeyboardHandle};
|
||||||
pub use self::pointer::PointerHandle;
|
pub use self::pointer::PointerHandle;
|
||||||
use wayland_server::{Client, EventLoop, EventLoopHandle, Global, StateToken};
|
use wayland_server::{Client, EventLoop, EventLoopHandle, Global, Liveness, Resource, StateToken};
|
||||||
use wayland_server::protocol::{wl_keyboard, wl_pointer, wl_seat};
|
use wayland_server::protocol::{wl_keyboard, wl_pointer, wl_seat};
|
||||||
|
|
||||||
|
/// Internal data of a seat global
|
||||||
|
///
|
||||||
|
/// This struct gives you access to the control of the
|
||||||
|
/// capabilities of the associated seat.
|
||||||
|
///
|
||||||
|
/// It is directly inserted in the event loop by its `new` method.
|
||||||
|
///
|
||||||
|
/// See module-level documentation for details of use.
|
||||||
pub struct Seat {
|
pub struct Seat {
|
||||||
log: ::slog::Logger,
|
log: ::slog::Logger,
|
||||||
name: String,
|
name: String,
|
||||||
pointer: Option<PointerHandle>,
|
pointer: Option<PointerHandle>,
|
||||||
keyboard: Option<KbdHandle>,
|
keyboard: Option<KeyboardHandle>,
|
||||||
known_seats: Vec<wl_seat::WlSeat>,
|
known_seats: Vec<wl_seat::WlSeat>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Seat {
|
impl Seat {
|
||||||
|
/// Create a new seat global
|
||||||
|
///
|
||||||
|
/// A new seat global is created with given name and inserted
|
||||||
|
/// into this event loop.
|
||||||
|
///
|
||||||
|
/// You are provided with the state token to retrieve it (allowing
|
||||||
|
/// you to add or remove capabilities from it), and the global handle,
|
||||||
|
/// in case you want to remove it.
|
||||||
pub fn new<L>(evl: &mut EventLoop, name: String, logger: L)
|
pub fn new<L>(evl: &mut EventLoop, name: String, logger: L)
|
||||||
-> (StateToken<Seat>, Global<wl_seat::WlSeat, StateToken<Seat>>)
|
-> (StateToken<Seat>, Global<wl_seat::WlSeat, StateToken<Seat>>)
|
||||||
where
|
where
|
||||||
|
@ -34,8 +106,25 @@ impl Seat {
|
||||||
(token, global)
|
(token, global)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds the pointer capability to this seat
|
||||||
|
///
|
||||||
|
/// You are provided a `PointerHandle`, which allows you to send input events
|
||||||
|
/// to this keyboard. This handle can be cloned and sent accross threads.
|
||||||
|
///
|
||||||
|
/// Calling this method on a seat that already has a pointer capability
|
||||||
|
/// will overwrite it, and will be seen by the clients as if the
|
||||||
|
/// mouse was unplugged and a new one was plugged.
|
||||||
pub fn add_pointer(&mut self) -> PointerHandle {
|
pub fn add_pointer(&mut self) -> PointerHandle {
|
||||||
let pointer = self::pointer::create_pointer_handler();
|
let pointer = self::pointer::create_pointer_handler();
|
||||||
|
if self.pointer.is_some() {
|
||||||
|
// there is already a pointer, remove it and notify the clients
|
||||||
|
// of the change
|
||||||
|
self.pointer = None;
|
||||||
|
let caps = self.compute_caps();
|
||||||
|
for seat in &self.known_seats {
|
||||||
|
seat.capabilities(caps);
|
||||||
|
}
|
||||||
|
}
|
||||||
self.pointer = Some(pointer.clone());
|
self.pointer = Some(pointer.clone());
|
||||||
let caps = self.compute_caps();
|
let caps = self.compute_caps();
|
||||||
for seat in &self.known_seats {
|
for seat in &self.known_seats {
|
||||||
|
@ -44,9 +133,34 @@ impl Seat {
|
||||||
pointer
|
pointer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove the pointer capability from this seat
|
||||||
|
///
|
||||||
|
/// Clients will be appropriately notified.
|
||||||
|
pub fn remove_pointer(&mut self) {
|
||||||
|
if self.pointer.is_some() {
|
||||||
|
self.pointer = None;
|
||||||
|
let caps = self.compute_caps();
|
||||||
|
for seat in &self.known_seats {
|
||||||
|
seat.capabilities(caps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the keyboard capability to this seat
|
||||||
|
///
|
||||||
|
/// You are provided a `KbdHandle`, which allows you to send input events
|
||||||
|
/// to this keyboard. This handle can be cloned and sent accross threads.
|
||||||
|
///
|
||||||
|
/// You also provide a Model/Layout/Variant/Options specification of the
|
||||||
|
/// keymap to be used for this keyboard, as well as any repeat-info that
|
||||||
|
/// will be forwarded to the clients.
|
||||||
|
///
|
||||||
|
/// Calling this method on a seat that already has a keyboard capability
|
||||||
|
/// will overwrite it, and will be seen by the clients as if the
|
||||||
|
/// keyboard was unplugged and a new one was plugged.
|
||||||
pub fn add_keyboard(&mut self, model: &str, layout: &str, variant: &str, options: Option<String>,
|
pub fn add_keyboard(&mut self, model: &str, layout: &str, variant: &str, options: Option<String>,
|
||||||
repeat_delay: i32, repeat_rate: i32)
|
repeat_delay: i32, repeat_rate: i32)
|
||||||
-> Result<KbdHandle, KbdError> {
|
-> Result<KeyboardHandle, KeyboardError> {
|
||||||
let keyboard = self::keyboard::create_keyboard_handler(
|
let keyboard = self::keyboard::create_keyboard_handler(
|
||||||
"evdev", // we need this one
|
"evdev", // we need this one
|
||||||
model,
|
model,
|
||||||
|
@ -57,6 +171,15 @@ impl Seat {
|
||||||
repeat_rate,
|
repeat_rate,
|
||||||
self.log.clone(),
|
self.log.clone(),
|
||||||
)?;
|
)?;
|
||||||
|
if self.keyboard.is_some() {
|
||||||
|
// there is already a keyboard, remove it and notify the clients
|
||||||
|
// of the change
|
||||||
|
self.keyboard = None;
|
||||||
|
let caps = self.compute_caps();
|
||||||
|
for seat in &self.known_seats {
|
||||||
|
seat.capabilities(caps);
|
||||||
|
}
|
||||||
|
}
|
||||||
self.keyboard = Some(keyboard.clone());
|
self.keyboard = Some(keyboard.clone());
|
||||||
let caps = self.compute_caps();
|
let caps = self.compute_caps();
|
||||||
for seat in &self.known_seats {
|
for seat in &self.known_seats {
|
||||||
|
@ -65,6 +188,35 @@ impl Seat {
|
||||||
Ok(keyboard)
|
Ok(keyboard)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove the keyboard capability from this seat
|
||||||
|
///
|
||||||
|
/// Clients will be appropriately notified.
|
||||||
|
pub fn remove_keyboard(&mut self) {
|
||||||
|
if self.keyboard.is_some() {
|
||||||
|
self.keyboard = None;
|
||||||
|
let caps = self.compute_caps();
|
||||||
|
for seat in &self.known_seats {
|
||||||
|
seat.capabilities(caps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cleanup internal states from old resources
|
||||||
|
///
|
||||||
|
/// Deletes all remnnant of ressources from clients that
|
||||||
|
/// are now disconnected.
|
||||||
|
///
|
||||||
|
/// It can be wise to run this from time to time.
|
||||||
|
pub fn cleanup(&mut self) {
|
||||||
|
if let Some(ref pointer) = self.pointer {
|
||||||
|
pointer.cleanup_old_pointers();
|
||||||
|
}
|
||||||
|
if let Some(ref kbd) = self.keyboard {
|
||||||
|
kbd.cleanup_old_kbds();
|
||||||
|
}
|
||||||
|
self.known_seats.retain(|s| s.status() == Liveness::Alive);
|
||||||
|
}
|
||||||
|
|
||||||
fn compute_caps(&self) -> wl_seat::Capability {
|
fn compute_caps(&self) -> wl_seat::Capability {
|
||||||
let mut caps = wl_seat::Capability::empty();
|
let mut caps = wl_seat::Capability::empty();
|
||||||
if self.pointer.is_some() {
|
if self.pointer.is_some() {
|
||||||
|
@ -80,7 +232,7 @@ impl Seat {
|
||||||
fn seat_global_bind(evlh: &mut EventLoopHandle, token: &mut StateToken<Seat>, _: &Client,
|
fn seat_global_bind(evlh: &mut EventLoopHandle, token: &mut StateToken<Seat>, _: &Client,
|
||||||
seat: wl_seat::WlSeat) {
|
seat: wl_seat::WlSeat) {
|
||||||
evlh.register(&seat, seat_implementation(), token.clone(), None);
|
evlh.register(&seat, seat_implementation(), token.clone(), None);
|
||||||
let mut seat_mgr = evlh.state().get_mut(token);
|
let seat_mgr = evlh.state().get_mut(token);
|
||||||
seat.name(seat_mgr.name.clone());
|
seat.name(seat_mgr.name.clone());
|
||||||
seat.capabilities(seat_mgr.compute_caps());
|
seat.capabilities(seat_mgr.compute_caps());
|
||||||
seat_mgr.known_seats.push(seat);
|
seat_mgr.known_seats.push(seat);
|
||||||
|
@ -88,21 +240,24 @@ fn seat_global_bind(evlh: &mut EventLoopHandle, token: &mut StateToken<Seat>, _:
|
||||||
|
|
||||||
fn seat_implementation() -> wl_seat::Implementation<StateToken<Seat>> {
|
fn seat_implementation() -> wl_seat::Implementation<StateToken<Seat>> {
|
||||||
wl_seat::Implementation {
|
wl_seat::Implementation {
|
||||||
get_pointer: |evlh, token, _, seat, pointer| {
|
get_pointer: |evlh, token, _, _, pointer| {
|
||||||
evlh.register(&pointer, pointer_implementation(), (), None);
|
evlh.register(&pointer, pointer_implementation(), (), None);
|
||||||
if let Some(ref ptr_handle) = evlh.state().get(token).pointer {
|
if let Some(ref ptr_handle) = evlh.state().get(token).pointer {
|
||||||
ptr_handle.new_pointer(pointer);
|
ptr_handle.new_pointer(pointer);
|
||||||
|
} else {
|
||||||
|
// we should send a protocol error... but the protocol does not allow
|
||||||
|
// us, so this pointer will just remain inactive ¯\_(ツ)_/¯
|
||||||
}
|
}
|
||||||
// TODO: protocol error ?
|
|
||||||
},
|
},
|
||||||
get_keyboard: |evlh, token, _, seat, keyboard| {
|
get_keyboard: |evlh, token, _, _, keyboard| {
|
||||||
evlh.register(&keyboard, keyboard_implementation(), (), None);
|
evlh.register(&keyboard, keyboard_implementation(), (), None);
|
||||||
if let Some(ref kbd_handle) = evlh.state().get(token).keyboard {
|
if let Some(ref kbd_handle) = evlh.state().get(token).keyboard {
|
||||||
kbd_handle.new_kbd(keyboard);
|
kbd_handle.new_kbd(keyboard);
|
||||||
|
} else {
|
||||||
|
// same, should error but cant
|
||||||
}
|
}
|
||||||
// TODO: protocol error ?
|
|
||||||
},
|
},
|
||||||
get_touch: |evlh, token, _, seat, touch| {
|
get_touch: |_evlh, _token, _, _, _touch| {
|
||||||
// TODO
|
// TODO
|
||||||
},
|
},
|
||||||
release: |_, _, _, _| {},
|
release: |_, _, _, _| {},
|
||||||
|
|
|
@ -31,6 +31,13 @@ impl PointerInternal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An handle to a keyboard handler
|
||||||
|
///
|
||||||
|
/// It can be cloned and all clones manipulate the same internal state. Clones
|
||||||
|
/// can also be sent across threads.
|
||||||
|
///
|
||||||
|
/// This handle gives you access to an interface to send pointer events to your
|
||||||
|
/// clients.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct PointerHandle {
|
pub struct PointerHandle {
|
||||||
inner: Arc<Mutex<PointerInternal>>,
|
inner: Arc<Mutex<PointerInternal>>,
|
||||||
|
@ -42,6 +49,16 @@ impl PointerHandle {
|
||||||
guard.known_pointers.push(pointer);
|
guard.known_pointers.push(pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Notify that the pointer moved
|
||||||
|
///
|
||||||
|
/// You provide the new location of the pointer, in the form of:
|
||||||
|
///
|
||||||
|
/// - `None` if the pointer is not on top of a client surface
|
||||||
|
/// - `Some(surface, x, y)` if the pointer is focusing surface `surface`,
|
||||||
|
/// at location `(x, y)` relative to this surface
|
||||||
|
///
|
||||||
|
/// This will internally take care of notifying the appropriate client objects
|
||||||
|
/// of enter/motion/leave events.
|
||||||
pub fn motion(&self, location: Option<(&wl_surface::WlSurface, f64, f64)>, serial: u32, time: u32) {
|
pub fn motion(&self, location: Option<(&wl_surface::WlSurface, f64, f64)>, serial: u32, time: u32) {
|
||||||
let mut guard = self.inner.lock().unwrap();
|
let mut guard = self.inner.lock().unwrap();
|
||||||
// do we leave a surface ?
|
// do we leave a surface ?
|
||||||
|
@ -69,15 +86,19 @@ impl PointerHandle {
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// we were on top of a surface and remained on it
|
// we were on top of a surface and remained on it
|
||||||
guard.with_focused_pointers(|pointer, surface| {
|
guard.with_focused_pointers(|pointer, _| {
|
||||||
pointer.motion(time, x, y);
|
pointer.motion(time, x, y);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Notify that a button was pressed
|
||||||
|
///
|
||||||
|
/// This will internally send the appropriate button event to the client
|
||||||
|
/// objects matching with the currently focused surface.
|
||||||
pub fn button(&self, button: u32, state: wl_pointer::ButtonState, serial: u32, time: u32) {
|
pub fn button(&self, button: u32, state: wl_pointer::ButtonState, serial: u32, time: u32) {
|
||||||
let mut guard = self.inner.lock().unwrap();
|
let guard = self.inner.lock().unwrap();
|
||||||
guard.with_focused_pointers(|pointer, _| {
|
guard.with_focused_pointers(|pointer, _| {
|
||||||
pointer.button(serial, time, button, state);
|
pointer.button(serial, time, button, state);
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue