seat: add a keyboard focus hook

This commit is contained in:
Victor Berger 2018-11-18 10:58:04 +01:00
parent afd92d0a3d
commit 5e9ad96b0f
4 changed files with 55 additions and 14 deletions

View File

@ -111,7 +111,7 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger
let pointer = w_seat.add_pointer(); let pointer = w_seat.add_pointer();
let keyboard = w_seat let keyboard = w_seat
.add_keyboard(XkbConfig::default(), 1000, 500) .add_keyboard(XkbConfig::default(), 1000, 500, |_, _| {})
.expect("Failed to initialize the keyboard"); .expect("Failed to initialize the keyboard");
let (output, _output_global) = Output::new( let (output, _output_global) = Output::new(

View File

@ -57,7 +57,7 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop<()>, log: Log
let pointer = seat.add_pointer(); let pointer = seat.add_pointer();
let keyboard = seat let keyboard = seat
.add_keyboard(XkbConfig::default(), 1000, 500) .add_keyboard(XkbConfig::default(), 1000, 500, |_, _| {})
.expect("Failed to initialize the keyboard"); .expect("Failed to initialize the keyboard");
let (output, _) = Output::new( let (output, _) = Output::new(

View File

@ -112,6 +112,7 @@ struct KbdInternal {
state: xkb::State, state: xkb::State,
repeat_rate: i32, repeat_rate: i32,
repeat_delay: i32, repeat_delay: i32,
focus_hook: Box<FnMut(Option<&Resource<WlSurface>>)>,
} }
// This is OK because all parts of `xkb` will remain on the // This is OK because all parts of `xkb` will remain on the
@ -119,7 +120,12 @@ struct KbdInternal {
unsafe impl Send for KbdInternal {} unsafe impl Send for KbdInternal {}
impl KbdInternal { impl KbdInternal {
fn new(xkb_config: XkbConfig, repeat_rate: i32, repeat_delay: i32) -> Result<KbdInternal, ()> { fn new(
xkb_config: XkbConfig,
repeat_rate: i32,
repeat_delay: i32,
focus_hook: Box<FnMut(Option<&Resource<WlSurface>>)>,
) -> Result<KbdInternal, ()> {
// we create a new contex for each keyboard because libxkbcommon is actually NOT threadsafe // we create a new contex for each keyboard because libxkbcommon is actually NOT threadsafe
// so confining it inside the KbdInternal allows us to use Rusts mutability rules to make // so confining it inside the KbdInternal allows us to use Rusts mutability rules to make
// sure nothing goes wrong. // sure nothing goes wrong.
@ -146,6 +152,7 @@ impl KbdInternal {
state, state,
repeat_rate, repeat_rate,
repeat_delay, repeat_delay,
focus_hook,
}) })
} }
@ -219,18 +226,23 @@ pub enum Error {
} }
/// Create a keyboard handler from a set of RMLVO rules /// Create a keyboard handler from a set of RMLVO rules
pub(crate) fn create_keyboard_handler( pub(crate) fn create_keyboard_handler<F>(
xkb_config: XkbConfig, xkb_config: XkbConfig,
repeat_delay: i32, repeat_delay: i32,
repeat_rate: i32, repeat_rate: i32,
logger: &::slog::Logger, logger: &::slog::Logger,
) -> Result<KeyboardHandle, Error> { focus_hook: F,
) -> Result<KeyboardHandle, Error>
where
F: FnMut(Option<&Resource<WlSurface>>) + 'static,
{
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" => xkb_config.rules, "model" => xkb_config.model, "layout" => xkb_config.layout, "rules" => xkb_config.rules, "model" => xkb_config.model, "layout" => xkb_config.layout,
"variant" => xkb_config.variant, "options" => &xkb_config.options "variant" => xkb_config.variant, "options" => &xkb_config.options
); );
let internal = KbdInternal::new(xkb_config, repeat_rate, repeat_delay).map_err(|_| { let internal =
KbdInternal::new(xkb_config, repeat_rate, repeat_delay, Box::new(focus_hook)).map_err(|_| {
debug!(log, "Loading keymap failed"); debug!(log, "Loading keymap failed");
Error::BadKeymap Error::BadKeymap
})?; })?;
@ -382,6 +394,14 @@ impl KeyboardHandle {
keys: keys.clone(), keys: keys.clone(),
}); });
}); });
{
let KbdInternal {
ref focus,
ref mut focus_hook,
..
} = *guard;
focus_hook(focus.as_ref());
}
if guard.focus.is_some() { if guard.focus.is_some() {
trace!(self.arc.logger, "Focus set to new surface"); trace!(self.arc.logger, "Focus set to new surface");
} else { } else {

View File

@ -64,7 +64,10 @@ pub use self::{
pointer::{AxisFrame, PointerGrab, PointerHandle, PointerInnerHandle}, pointer::{AxisFrame, PointerGrab, PointerHandle, PointerInnerHandle},
}; };
use wayland_server::{protocol::wl_seat, Display, Global, NewResource, Resource}; use wayland_server::{
protocol::{wl_seat, wl_surface},
Display, Global, NewResource, Resource,
};
struct Inner { struct Inner {
log: ::slog::Logger, log: ::slog::Logger,
@ -101,7 +104,11 @@ impl Inner {
/// ///
/// It is directly inserted in the event loop by its `new` method. /// It is directly inserted in the event loop by its `new` method.
/// ///
/// This is an handle to the inner logic, it can be cloned and shared accross
/// threads.
///
/// See module-level documentation for details of use. /// See module-level documentation for details of use.
#[derive(Clone)]
pub struct Seat { pub struct Seat {
inner: Arc<Mutex<Inner>>, inner: Arc<Mutex<Inner>>,
} }
@ -217,18 +224,32 @@ impl Seat {
/// }, /// },
/// 1000, /// 1000,
/// 500, /// 500,
/// |seat, focus| {
/// /* This closure is called whenever the keyboard focus
/// * changes, with the new focus as argument */
/// }
/// ) /// )
/// .expect("Failed to initialize the keyboard"); /// .expect("Failed to initialize the keyboard");
/// ``` /// ```
pub fn add_keyboard( pub fn add_keyboard<F>(
&mut self, &mut self,
xkb_config: keyboard::XkbConfig, xkb_config: keyboard::XkbConfig,
repeat_delay: i32, repeat_delay: i32,
repeat_rate: i32, repeat_rate: i32,
) -> Result<KeyboardHandle, KeyboardError> { mut focus_hook: F,
) -> Result<KeyboardHandle, KeyboardError>
where
F: FnMut(&Seat, Option<&Resource<wl_surface::WlSurface>>) + 'static,
{
let me = self.clone();
let mut inner = self.inner.lock().unwrap(); let mut inner = self.inner.lock().unwrap();
let keyboard = let keyboard = self::keyboard::create_keyboard_handler(
self::keyboard::create_keyboard_handler(xkb_config, repeat_delay, repeat_rate, &inner.log)?; xkb_config,
repeat_delay,
repeat_rate,
&inner.log,
move |focus| focus_hook(&me, focus),
)?;
if inner.keyboard.is_some() { if inner.keyboard.is_some() {
// there is already a keyboard, remove it and notify the clients // there is already a keyboard, remove it and notify the clients
// of the change // of the change