Merge pull request #440 from Smithay/fix/x11_device_events

x11: add virtual device events
This commit is contained in:
Victoria Brekenfeld 2021-12-22 20:04:51 +01:00 committed by GitHub
commit 9bf4dc5f3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 176 additions and 61 deletions

View File

@ -166,13 +166,13 @@ pub fn run_x11(log: Logger) {
event_loop event_loop
.handle() .handle()
.insert_source(backend, |event, _window, state| match event { .insert_source(backend, |event, _, state| match event {
X11Event::CloseRequested => { X11Event::CloseRequested { .. } => {
state.running.store(false, Ordering::SeqCst); state.running.store(false, Ordering::SeqCst);
} }
X11Event::Resized(size) => { X11Event::Resized { new_size, .. } => {
let size = { (size.w as i32, size.h as i32).into() }; let size = { (new_size.w as i32, new_size.h as i32).into() };
state.backend_data.mode = Mode { state.backend_data.mode = Mode {
size, size,
@ -193,7 +193,7 @@ pub fn run_x11(log: Logger) {
state.backend_data.render = true; state.backend_data.render = true;
} }
X11Event::PresentCompleted | X11Event::Refresh => { X11Event::PresentCompleted { .. } | X11Event::Refresh { .. } => {
state.backend_data.render = true; state.backend_data.render = true;
} }

View File

@ -1,5 +1,6 @@
//! Input backend implementation for the X11 backend. //! Input backend implementation for the X11 backend.
use super::{window_inner::WindowInner, Window, WindowTemporary};
use crate::{ use crate::{
backend::input::{ backend::input::{
self, Axis, AxisSource, ButtonState, Device, DeviceCapability, InputBackend, KeyState, self, Axis, AxisSource, ButtonState, Device, DeviceCapability, InputBackend, KeyState,
@ -7,6 +8,7 @@ use crate::{
}, },
utils::{Logical, Size}, utils::{Logical, Size},
}; };
use std::sync::Weak;
/// Marker used to define the `InputBackend` types for the X11 backend. /// Marker used to define the `InputBackend` types for the X11 backend.
#[derive(Debug)] #[derive(Debug)]
@ -43,12 +45,22 @@ impl Device for X11VirtualDevice {
/// X11-Backend internal event wrapping `X11`'s types into a [`KeyboardKeyEvent`]. /// X11-Backend internal event wrapping `X11`'s types into a [`KeyboardKeyEvent`].
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone)]
pub struct X11KeyboardInputEvent { pub struct X11KeyboardInputEvent {
pub(crate) time: u32, pub(crate) time: u32,
pub(crate) key: u32, pub(crate) key: u32,
pub(crate) count: u32, pub(crate) count: u32,
pub(crate) state: KeyState, pub(crate) state: KeyState,
pub(crate) window: Weak<WindowInner>,
}
impl X11KeyboardInputEvent {
/// Returns a temporary reference to the window belonging to this event.
///
/// Returns None if the window is not alive anymore.
pub fn window(&self) -> Option<impl AsRef<Window> + '_> {
self.window.upgrade().map(Window).map(WindowTemporary)
}
} }
impl input::Event<X11Input> for X11KeyboardInputEvent { impl input::Event<X11Input> for X11KeyboardInputEvent {
@ -77,11 +89,21 @@ impl KeyboardKeyEvent<X11Input> for X11KeyboardInputEvent {
/// X11-Backend internal event wrapping `X11`'s types into a [`PointerAxisEvent`] /// X11-Backend internal event wrapping `X11`'s types into a [`PointerAxisEvent`]
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone)]
pub struct X11MouseWheelEvent { pub struct X11MouseWheelEvent {
pub(crate) time: u32, pub(crate) time: u32,
pub(crate) axis: Axis, pub(crate) axis: Axis,
pub(crate) amount: f64, pub(crate) amount: f64,
pub(crate) window: Weak<WindowInner>,
}
impl X11MouseWheelEvent {
/// Returns a temporary reference to the window belonging to this event.
///
/// Returns None if the window is not alive anymore.
pub fn window(&self) -> Option<impl AsRef<Window> + '_> {
self.window.upgrade().map(Window).map(WindowTemporary)
}
} }
impl input::Event<X11Input> for X11MouseWheelEvent { impl input::Event<X11Input> for X11MouseWheelEvent {
@ -115,11 +137,21 @@ impl PointerAxisEvent<X11Input> for X11MouseWheelEvent {
/// X11-Backend internal event wrapping `X11`'s types into a [`PointerButtonEvent`] /// X11-Backend internal event wrapping `X11`'s types into a [`PointerButtonEvent`]
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone)]
pub struct X11MouseInputEvent { pub struct X11MouseInputEvent {
pub(crate) time: u32, pub(crate) time: u32,
pub(crate) raw: u32, pub(crate) raw: u32,
pub(crate) state: ButtonState, pub(crate) state: ButtonState,
pub(crate) window: Weak<WindowInner>,
}
impl X11MouseInputEvent {
/// Returns a temporary reference to the window belonging to this event.
///
/// Returns None if the window is not alive anymore.
pub fn window(&self) -> Option<impl AsRef<Window> + '_> {
self.window.upgrade().map(Window).map(WindowTemporary)
}
} }
impl input::Event<X11Input> for X11MouseInputEvent { impl input::Event<X11Input> for X11MouseInputEvent {
@ -144,12 +176,22 @@ impl PointerButtonEvent<X11Input> for X11MouseInputEvent {
/// X11-Backend internal event wrapping `X11`'s types into a [`PointerMotionAbsoluteEvent`] /// X11-Backend internal event wrapping `X11`'s types into a [`PointerMotionAbsoluteEvent`]
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone)]
pub struct X11MouseMovedEvent { pub struct X11MouseMovedEvent {
pub(crate) time: u32, pub(crate) time: u32,
pub(crate) x: f64, pub(crate) x: f64,
pub(crate) y: f64, pub(crate) y: f64,
pub(crate) size: Size<u16, Logical>, pub(crate) size: Size<u16, Logical>,
pub(crate) window: Weak<WindowInner>,
}
impl X11MouseMovedEvent {
/// Returns a temporary reference to the window belonging to this event.
///
/// Returns None if the window is not alive anymore.
pub fn window(&self) -> Option<impl AsRef<Window> + '_> {
self.window.upgrade().map(Window).map(WindowTemporary)
}
} }
impl input::Event<X11Input> for X11MouseMovedEvent { impl input::Event<X11Input> for X11MouseMovedEvent {

View File

@ -129,21 +129,35 @@ pub use self::surface::*;
#[derive(Debug)] #[derive(Debug)]
pub enum X11Event { pub enum X11Event {
/// The X server has required the compositor to redraw the contents of window. /// The X server has required the compositor to redraw the contents of window.
Refresh, Refresh {
/// XID of the window
window_id: u32,
},
/// An input event occurred. /// An input event occurred.
Input(InputEvent<X11Input>), Input(InputEvent<X11Input>),
/// The window was resized. /// The window was resized.
Resized(Size<u16, Logical>), Resized {
/// The new size of the window
new_size: Size<u16, Logical>,
/// XID of the window
window_id: u32,
},
/// The last buffer presented to the window has been displayed. /// The last buffer presented to the window has been displayed.
/// ///
/// When this event is scheduled, the next frame may be rendered. /// When this event is scheduled, the next frame may be rendered.
PresentCompleted, PresentCompleted {
/// XID of the window
window_id: u32,
},
/// The window has received a request to be closed. /// The window has received a request to be closed.
CloseRequested, CloseRequested {
/// XID of the window
window_id: u32,
},
} }
/// Represents an active connection to the X to manage events on the Window provided by the backend. /// Represents an active connection to the X to manage events on the Window provided by the backend.
@ -241,6 +255,7 @@ impl X11Backend {
atoms, atoms,
depth, depth,
visual_id, visual_id,
devices: false,
}; };
Ok(X11Backend { Ok(X11Backend {
@ -376,6 +391,14 @@ impl X11Handle {
resize: recv, resize: recv,
}) })
} }
/// Get a temporary reference to a window by its XID
pub fn window_ref_from_id(&self, id: u32) -> Option<impl AsRef<Window> + '_> {
X11Inner::window_ref_from_id(&self.inner, &id)
.and_then(|w| w.upgrade())
.map(Window)
.map(WindowTemporary)
}
} }
/// Builder used to construct a window. /// Builder used to construct a window.
@ -498,11 +521,19 @@ impl PartialEq for Window {
} }
} }
struct WindowTemporary(Window);
impl AsRef<Window> for WindowTemporary {
fn as_ref(&self) -> &Window {
&self.0
}
}
impl EventSource for X11Backend { impl EventSource for X11Backend {
type Event = X11Event; type Event = X11Event;
/// The window the incoming events are applicable to. /// The window the incoming events are applicable to.
type Metadata = Window; type Metadata = ();
type Ret = (); type Ret = ();
@ -565,30 +596,48 @@ pub(crate) struct X11Inner {
atoms: Atoms, atoms: Atoms,
depth: x11::xproto::Depth, depth: x11::xproto::Depth,
visual_id: u32, visual_id: u32,
devices: bool,
} }
impl X11Inner { impl X11Inner {
fn window_ref_from_id(inner: &Arc<Mutex<X11Inner>>, id: &u32) -> Option<Weak<WindowInner>> {
let mut inner = inner.lock().unwrap();
inner.windows.retain(|_, weak| weak.upgrade().is_some());
inner.windows.get(id).cloned()
}
fn process_event<F>(inner: &Arc<Mutex<X11Inner>>, log: &Logger, event: x11::Event, callback: &mut F) fn process_event<F>(inner: &Arc<Mutex<X11Inner>>, log: &Logger, event: x11::Event, callback: &mut F)
where where
F: FnMut(X11Event, &mut Window), F: FnMut(X11Event, &mut ()),
{ {
use self::X11Event::Input; {
let mut inner = inner.lock().unwrap();
fn window_from_id(inner: &Arc<Mutex<X11Inner>>, id: &u32) -> Option<Arc<WindowInner>> { if !inner.windows.is_empty() && !inner.devices {
inner callback(
.lock() Input(InputEvent::DeviceAdded {
.unwrap() device: X11VirtualDevice,
.windows }),
.get(id) &mut (),
.cloned() );
.and_then(|weak| weak.upgrade()) inner.devices = true;
} else if inner.windows.is_empty() && inner.devices {
callback(
Input(InputEvent::DeviceRemoved {
device: X11VirtualDevice,
}),
&mut (),
);
inner.devices = false;
}
} }
use self::X11Event::Input;
// If X11 is deadlocking somewhere here, make sure you drop your mutex guards. // If X11 is deadlocking somewhere here, make sure you drop your mutex guards.
match event { match event {
x11::Event::ButtonPress(button_press) => { x11::Event::ButtonPress(button_press) => {
if let Some(window) = window_from_id(inner, &button_press.event) { if let Some(window) = X11Inner::window_ref_from_id(inner, &button_press.event) {
// X11 decided to associate scroll wheel with a button, 4, 5, 6 and 7 for // X11 decided to associate scroll wheel with a button, 4, 5, 6 and 7 for
// up, down, right and left. For scrolling, a press event is emitted and a // up, down, right and left. For scrolling, a press event is emitted and a
// release is them immediately followed for scrolling. This means we can // release is them immediately followed for scrolling. This means we can
@ -631,9 +680,10 @@ impl X11Inner {
_ => unreachable!(), _ => unreachable!(),
}, },
window,
}, },
}), }),
&mut Window(window), &mut (),
) )
} else { } else {
callback( callback(
@ -642,9 +692,10 @@ impl X11Inner {
time: button_press.time, time: button_press.time,
raw: button_press.detail as u32, raw: button_press.detail as u32,
state: ButtonState::Pressed, state: ButtonState::Pressed,
window,
}, },
}), }),
&mut Window(window), &mut (),
) )
} }
} }
@ -658,22 +709,23 @@ impl X11Inner {
return; return;
} }
if let Some(window) = window_from_id(inner, &button_release.event) { if let Some(window) = X11Inner::window_ref_from_id(inner, &button_release.event) {
callback( callback(
Input(InputEvent::PointerButton { Input(InputEvent::PointerButton {
event: X11MouseInputEvent { event: X11MouseInputEvent {
time: button_release.time, time: button_release.time,
raw: button_release.detail as u32, raw: button_release.detail as u32,
state: ButtonState::Released, state: ButtonState::Released,
window,
}, },
}), }),
&mut Window(window), &mut (),
); );
} }
} }
x11::Event::KeyPress(key_press) => { x11::Event::KeyPress(key_press) => {
if let Some(window) = window_from_id(inner, &key_press.event) { if let Some(window) = X11Inner::window_ref_from_id(inner, &key_press.event) {
// Do not hold the lock. // Do not hold the lock.
let count = { inner.lock().unwrap().key_counter.fetch_add(1, Ordering::SeqCst) + 1 }; let count = { inner.lock().unwrap().key_counter.fetch_add(1, Ordering::SeqCst) + 1 };
@ -689,15 +741,16 @@ impl X11Inner {
key: key_press.detail as u32 - 8, key: key_press.detail as u32 - 8,
count, count,
state: KeyState::Pressed, state: KeyState::Pressed,
window,
}, },
}), }),
&mut Window(window), &mut (),
) )
} }
} }
x11::Event::KeyRelease(key_release) => { x11::Event::KeyRelease(key_release) => {
if let Some(window) = window_from_id(inner, &key_release.event) { if let Some(window) = X11Inner::window_ref_from_id(inner, &key_release.event) {
let count = { let count = {
let key_counter = inner.lock().unwrap().key_counter.clone(); let key_counter = inner.lock().unwrap().key_counter.clone();
@ -721,15 +774,18 @@ impl X11Inner {
key: key_release.detail as u32 - 8, key: key_release.detail as u32 - 8,
count, count,
state: KeyState::Released, state: KeyState::Released,
window,
}, },
}), }),
&mut Window(window), &mut (),
); );
} }
} }
x11::Event::MotionNotify(motion_notify) => { x11::Event::MotionNotify(motion_notify) => {
if let Some(window) = window_from_id(inner, &motion_notify.event) { if let Some(window) =
X11Inner::window_ref_from_id(inner, &motion_notify.event).and_then(|w| w.upgrade())
{
// Use event_x/y since those are relative the the window receiving events. // Use event_x/y since those are relative the the window receiving events.
let x = motion_notify.event_x as f64; let x = motion_notify.event_x as f64;
let y = motion_notify.event_y as f64; let y = motion_notify.event_y as f64;
@ -743,15 +799,18 @@ impl X11Inner {
x, x,
y, y,
size: window_size, size: window_size,
window: Arc::downgrade(&window),
}, },
}), }),
&mut Window(window), &mut (),
) )
} }
} }
x11::Event::ConfigureNotify(configure_notify) => { x11::Event::ConfigureNotify(configure_notify) => {
if let Some(window) = window_from_id(inner, &configure_notify.window) { if let Some(window) =
X11Inner::window_ref_from_id(inner, &configure_notify.window).and_then(|w| w.upgrade())
{
let previous_size = { *window.size.lock().unwrap() }; let previous_size = { *window.size.lock().unwrap() };
// Did the size of the window change? // Did the size of the window change?
@ -768,8 +827,11 @@ impl X11Inner {
} }
(callback)( (callback)(
X11Event::Resized(configure_notify_size), X11Event::Resized {
&mut Window(window.clone()), new_size: configure_notify_size,
window_id: configure_notify.window,
},
&mut (),
); );
if let Some(resize_sender) = window.resize.lock().unwrap().as_ref() { if let Some(resize_sender) = window.resize.lock().unwrap().as_ref() {
@ -780,40 +842,61 @@ impl X11Inner {
} }
x11::Event::EnterNotify(enter_notify) => { x11::Event::EnterNotify(enter_notify) => {
if let Some(window) = window_from_id(inner, &enter_notify.event) { if let Some(window) =
X11Inner::window_ref_from_id(inner, &enter_notify.event).and_then(|w| w.upgrade())
{
window.cursor_enter(); window.cursor_enter();
} }
} }
x11::Event::LeaveNotify(leave_notify) => { x11::Event::LeaveNotify(leave_notify) => {
if let Some(window) = window_from_id(inner, &leave_notify.event) { if let Some(window) =
X11Inner::window_ref_from_id(inner, &leave_notify.event).and_then(|w| w.upgrade())
{
window.cursor_leave(); window.cursor_leave();
} }
} }
x11::Event::ClientMessage(client_message) => { x11::Event::ClientMessage(client_message) => {
if let Some(window) = window_from_id(inner, &client_message.window) { if let Some(window) =
X11Inner::window_ref_from_id(inner, &client_message.window).and_then(|w| w.upgrade())
{
if client_message.data.as_data32()[0] == window.atoms.WM_DELETE_WINDOW if client_message.data.as_data32()[0] == window.atoms.WM_DELETE_WINDOW
// Destroy the window? // Destroy the window?
{ {
(callback)(X11Event::CloseRequested, &mut Window(window)); (callback)(
X11Event::CloseRequested {
window_id: client_message.window,
},
&mut (),
);
} }
} }
} }
x11::Event::Expose(expose) => { x11::Event::Expose(expose) => {
if let Some(window) = window_from_id(inner, &expose.window) { if expose.count == 0 {
if expose.count == 0 { (callback)(
(callback)(X11Event::Refresh, &mut Window(window)); X11Event::Refresh {
} window_id: expose.window,
},
&mut (),
);
} }
} }
x11::Event::PresentCompleteNotify(complete_notify) => { x11::Event::PresentCompleteNotify(complete_notify) => {
if let Some(window) = window_from_id(inner, &complete_notify.window) { if let Some(window) =
X11Inner::window_ref_from_id(inner, &complete_notify.window).and_then(|w| w.upgrade())
{
window.last_msc.store(complete_notify.msc, Ordering::SeqCst); window.last_msc.store(complete_notify.msc, Ordering::SeqCst);
(callback)(X11Event::PresentCompleted, &mut Window(window)); (callback)(
X11Event::PresentCompleted {
window_id: complete_notify.window,
},
&mut (),
);
} }
} }

View File

@ -19,7 +19,7 @@ use crate::{
utils::{Logical, Size}, utils::{Logical, Size},
}; };
use super::X11Error; use super::{WindowTemporary, X11Error};
/// An error that may occur when presenting. /// An error that may occur when presenting.
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
@ -55,17 +55,7 @@ impl X11Surface {
/// ///
/// This will return [`None`] if the window has been destroyed. /// This will return [`None`] if the window has been destroyed.
pub fn window(&self) -> Option<impl AsRef<Window> + '_> { pub fn window(&self) -> Option<impl AsRef<Window> + '_> {
let window = self.window.upgrade().map(Window).map(WindowTemporary); self.window.upgrade().map(Window).map(WindowTemporary)
struct WindowTemporary(Window);
impl AsRef<Window> for WindowTemporary {
fn as_ref(&self) -> &Window {
&self.0
}
}
window
} }
/// Returns a handle to the GBM device used to allocate buffers. /// Returns a handle to the GBM device used to allocate buffers.