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,
|
||||
options: Option<String>, repeat_delay: i32, repeat_rate: i32,
|
||||
logger: ::slog::Logger)
|
||||
-> Result<KbdHandle, Error> {
|
||||
-> Result<KeyboardHandle, Error> {
|
||||
let log = logger.new(o!("smithay_module" => "xkbcommon_handler"));
|
||||
info!(log, "Initializing a xkbcommon handler with keymap query";
|
||||
"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()
|
||||
);
|
||||
|
||||
Ok(KbdHandle {
|
||||
Ok(KeyboardHandle {
|
||||
arc: Arc::new(KbdArc {
|
||||
internal: Mutex::new(internal),
|
||||
keymap_file: keymap_file,
|
||||
|
@ -230,20 +230,19 @@ struct KbdArc {
|
|||
/// It can be cloned and all clones manipulate the same internal state. Clones
|
||||
/// 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
|
||||
/// 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
|
||||
/// 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.
|
||||
#[derive(Clone)]
|
||||
pub struct KbdHandle {
|
||||
pub struct KeyboardHandle {
|
||||
arc: Arc<KbdArc>,
|
||||
}
|
||||
|
||||
impl KbdHandle {
|
||||
impl KeyboardHandle {
|
||||
/// Handle a keystroke
|
||||
///
|
||||
/// All keystrokes from the input backend should be fed _in order_ to this method of the
|
||||
|
|
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 pointer;
|
||||
|
||||
pub use self::keyboard::{Error as KbdError, KbdHandle};
|
||||
pub use self::keyboard::{Error as KeyboardError, KeyboardHandle};
|
||||
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};
|
||||
|
||||
/// 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 {
|
||||
log: ::slog::Logger,
|
||||
name: String,
|
||||
pointer: Option<PointerHandle>,
|
||||
keyboard: Option<KbdHandle>,
|
||||
keyboard: Option<KeyboardHandle>,
|
||||
known_seats: Vec<wl_seat::WlSeat>,
|
||||
}
|
||||
|
||||
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)
|
||||
-> (StateToken<Seat>, Global<wl_seat::WlSeat, StateToken<Seat>>)
|
||||
where
|
||||
|
@ -34,8 +106,25 @@ impl Seat {
|
|||
(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 {
|
||||
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());
|
||||
let caps = self.compute_caps();
|
||||
for seat in &self.known_seats {
|
||||
|
@ -44,9 +133,34 @@ impl Seat {
|
|||
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>,
|
||||
repeat_delay: i32, repeat_rate: i32)
|
||||
-> Result<KbdHandle, KbdError> {
|
||||
-> Result<KeyboardHandle, KeyboardError> {
|
||||
let keyboard = self::keyboard::create_keyboard_handler(
|
||||
"evdev", // we need this one
|
||||
model,
|
||||
|
@ -57,6 +171,15 @@ impl Seat {
|
|||
repeat_rate,
|
||||
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());
|
||||
let caps = self.compute_caps();
|
||||
for seat in &self.known_seats {
|
||||
|
@ -65,6 +188,35 @@ impl Seat {
|
|||
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 {
|
||||
let mut caps = wl_seat::Capability::empty();
|
||||
if self.pointer.is_some() {
|
||||
|
@ -80,7 +232,7 @@ impl Seat {
|
|||
fn seat_global_bind(evlh: &mut EventLoopHandle, token: &mut StateToken<Seat>, _: &Client,
|
||||
seat: wl_seat::WlSeat) {
|
||||
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.capabilities(seat_mgr.compute_caps());
|
||||
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>> {
|
||||
wl_seat::Implementation {
|
||||
get_pointer: |evlh, token, _, seat, pointer| {
|
||||
get_pointer: |evlh, token, _, _, pointer| {
|
||||
evlh.register(&pointer, pointer_implementation(), (), None);
|
||||
if let Some(ref ptr_handle) = evlh.state().get(token).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);
|
||||
if let Some(ref kbd_handle) = evlh.state().get(token).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
|
||||
},
|
||||
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)]
|
||||
pub struct PointerHandle {
|
||||
inner: Arc<Mutex<PointerInternal>>,
|
||||
|
@ -42,6 +49,16 @@ impl PointerHandle {
|
|||
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) {
|
||||
let mut guard = self.inner.lock().unwrap();
|
||||
// do we leave a surface ?
|
||||
|
@ -69,15 +86,19 @@ impl PointerHandle {
|
|||
})
|
||||
} else {
|
||||
// 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);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
let mut guard = self.inner.lock().unwrap();
|
||||
let guard = self.inner.lock().unwrap();
|
||||
guard.with_focused_pointers(|pointer, _| {
|
||||
pointer.button(serial, time, button, state);
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue