On X11, store window target on EventProcessor

Remove the redundant `Rc` to access the window target.
This commit is contained in:
Kirill Chibisov 2024-02-09 05:52:09 +04:00
parent d1902aa15a
commit dbe0f852da
5 changed files with 584 additions and 475 deletions

View file

@ -498,7 +498,7 @@ impl<'a> KeyEventResults<'a> {
} }
} }
fn physical_key(&mut self) -> PhysicalKey { fn physical_key(&self) -> PhysicalKey {
keymap::raw_keycode_to_physicalkey(self.keycode) keymap::raw_keycode_to_physicalkey(self.keycode)
} }
@ -553,6 +553,7 @@ impl<'a> KeyEventResults<'a> {
} else { } else {
0 0
}; };
self.keysym_to_key(keysym) self.keysym_to_key(keysym)
.unwrap_or_else(|(key, location)| { .unwrap_or_else(|(key, location)| {
( (
@ -565,7 +566,7 @@ impl<'a> KeyEventResults<'a> {
}) })
} }
fn keysym_to_key(&mut self, keysym: u32) -> Result<(Key, KeyLocation), (Key, KeyLocation)> { fn keysym_to_key(&self, keysym: u32) -> Result<(Key, KeyLocation), (Key, KeyLocation)> {
let location = super::keymap::keysym_location(keysym); let location = super::keymap::keysym_location(keysym);
let key = super::keymap::keysym_to_key(keysym); let key = super::keymap::keysym_to_key(keysym);
if matches!(key, Key::Unidentified(_)) { if matches!(key, Key::Unidentified(_)) {

File diff suppressed because it is too large Load diff

View file

@ -1,72 +1,33 @@
#![cfg(x11_platform)] #![cfg(x11_platform)]
mod activation; use std::cell::{Cell, RefCell};
mod atoms; use std::collections::{HashMap, HashSet};
mod dnd; use std::ffi::CStr;
mod event_processor; use std::fmt;
pub mod ffi; use std::marker::PhantomData;
mod ime; use std::mem::MaybeUninit;
mod monitor; use std::ops::Deref;
pub mod util; use std::os::raw::*;
mod window; use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
mod xdisplay; use std::sync::mpsc::{self, Receiver, Sender, TryRecvError};
mod xsettings; use std::sync::{Arc, Weak};
use std::time::{Duration, Instant};
pub(crate) use self::{ use std::{ptr, slice, str};
monitor::{MonitorHandle, VideoModeHandle},
window::UnownedWindow,
xdisplay::{XConnection, XError, XNotSupported},
};
use calloop::generic::Generic; use calloop::generic::Generic;
use calloop::EventLoop as Loop; use calloop::EventLoop as Loop;
use calloop::{ping::Ping, Readiness}; use calloop::{ping::Ping, Readiness};
use libc::{self, setlocale, LC_CTYPE};
use log::warn; use log::warn;
use std::{ use x11rb::connection::RequestConnection;
cell::{Cell, RefCell}, use x11rb::errors::{ConnectError, ConnectionError, IdsExhausted, ReplyError};
collections::{HashMap, HashSet}, use x11rb::protocol::xinput::{self, ConnectionExt as _};
ffi::CStr, use x11rb::protocol::xkb;
fmt, use x11rb::protocol::xproto::{self, ConnectionExt as _};
marker::PhantomData,
mem::MaybeUninit,
ops::Deref,
os::{
raw::*,
unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd},
},
ptr,
rc::Rc,
slice, str,
sync::mpsc::{Receiver, Sender, TryRecvError},
sync::{mpsc, Arc, Weak},
time::{Duration, Instant},
};
use libc::{self, setlocale, LC_CTYPE};
use atoms::*;
use x11rb::x11_utils::X11Error as LogicalError; use x11rb::x11_utils::X11Error as LogicalError;
use x11rb::{ use x11rb::xcb_ffi::ReplyOrIdError;
connection::RequestConnection,
protocol::{
xinput::{self, ConnectionExt as _},
xkb,
xproto::{self, ConnectionExt as _},
},
};
use x11rb::{
errors::{ConnectError, ConnectionError, IdsExhausted, ReplyError},
xcb_ffi::ReplyOrIdError,
};
pub(super) use self::util::CustomCursor;
use self::{
dnd::{Dnd, DndState},
event_processor::EventProcessor,
ime::{Ime, ImeCreationError, ImeReceiver, ImeRequest, ImeSender},
};
use super::{common::xkb_state::KbdState, ControlFlow, OsError}; use super::{common::xkb_state::KbdState, ControlFlow, OsError};
use crate::{ use crate::{
error::{EventLoopError, OsError as RootOsError}, error::{EventLoopError, OsError as RootOsError},
@ -77,6 +38,28 @@ use crate::{
window::WindowAttributes, window::WindowAttributes,
}; };
mod activation;
mod atoms;
mod dnd;
mod event_processor;
pub mod ffi;
mod ime;
mod monitor;
mod util;
mod window;
mod xdisplay;
mod xsettings;
use atoms::*;
use dnd::{Dnd, DndState};
use event_processor::EventProcessor;
use ime::{Ime, ImeCreationError, ImeReceiver, ImeRequest, ImeSender};
pub(crate) use monitor::{MonitorHandle, VideoModeHandle};
use window::UnownedWindow;
pub(crate) use xdisplay::{XConnection, XError, XNotSupported};
pub use util::CustomCursor;
// Xinput constants not defined in x11rb // Xinput constants not defined in x11rb
const ALL_DEVICES: u16 = 0; const ALL_DEVICES: u16 = 0;
const ALL_MASTER_DEVICES: u16 = 1; const ALL_MASTER_DEVICES: u16 = 1;
@ -166,7 +149,6 @@ pub struct EventLoop<T: 'static> {
user_receiver: PeekableReceiver<T>, user_receiver: PeekableReceiver<T>,
activation_receiver: PeekableReceiver<ActivationToken>, activation_receiver: PeekableReceiver<ActivationToken>,
user_sender: Sender<T>, user_sender: Sender<T>,
target: Rc<RootELW>,
/// The current state of the event loop. /// The current state of the event loop.
state: EventLoopState, state: EventLoopState,
@ -324,13 +306,13 @@ impl<T: 'static> EventLoop<T> {
// Set initial device event filter. // Set initial device event filter.
window_target.update_listen_device_events(true); window_target.update_listen_device_events(true);
let target = Rc::new(RootELW { let root_window_target = RootELW {
p: super::EventLoopWindowTarget::X(window_target), p: super::EventLoopWindowTarget::X(window_target),
_marker: PhantomData, _marker: PhantomData,
}); };
let event_processor = EventProcessor { let event_processor = EventProcessor {
target: target.clone(), target: root_window_target,
dnd, dnd,
devices: Default::default(), devices: Default::default(),
randr_event_offset, randr_event_offset,
@ -349,8 +331,9 @@ impl<T: 'static> EventLoop<T> {
// Register for device hotplug events // Register for device hotplug events
// (The request buffer is flushed during `init_device`) // (The request buffer is flushed during `init_device`)
get_xtarget(&target) let xconn = &EventProcessor::window_target(&event_processor.target).xconn;
.xconn
xconn
.select_xinput_events( .select_xinput_events(
root, root,
ALL_DEVICES, ALL_DEVICES,
@ -358,8 +341,7 @@ impl<T: 'static> EventLoop<T> {
) )
.expect_then_ignore_error("Failed to register for XInput2 device hotplug events"); .expect_then_ignore_error("Failed to register for XInput2 device hotplug events");
get_xtarget(&target) xconn
.xconn
.select_xkb_events( .select_xkb_events(
0x100, // Use the "core keyboard device" 0x100, // Use the "core keyboard device"
xkb::EventType::NEW_KEYBOARD_NOTIFY xkb::EventType::NEW_KEYBOARD_NOTIFY
@ -379,7 +361,6 @@ impl<T: 'static> EventLoop<T> {
activation_receiver: PeekableReceiver::from_recv(activation_token_channel), activation_receiver: PeekableReceiver::from_recv(activation_token_channel),
user_receiver: PeekableReceiver::from_recv(user_channel), user_receiver: PeekableReceiver::from_recv(user_channel),
user_sender, user_sender,
target,
state: EventLoopState { state: EventLoopState {
x11_readiness: Readiness::EMPTY, x11_readiness: Readiness::EMPTY,
}, },
@ -396,7 +377,7 @@ impl<T: 'static> EventLoop<T> {
} }
pub(crate) fn window_target(&self) -> &RootELW { pub(crate) fn window_target(&self) -> &RootELW {
&self.target &self.event_processor.target
} }
pub fn run_on_demand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError> pub fn run_on_demand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
@ -421,7 +402,7 @@ impl<T: 'static> EventLoop<T> {
// `run_on_demand` calls but if they have only just dropped their // `run_on_demand` calls but if they have only just dropped their
// windows we need to make sure those last requests are sent to the // windows we need to make sure those last requests are sent to the
// X Server. // X Server.
let wt = get_xtarget(&self.target); let wt = EventProcessor::window_target(&self.event_processor.target);
wt.x_connection().sync_with_server().map_err(|x_err| { wt.x_connection().sync_with_server().map_err(|x_err| {
EventLoopError::Os(os_error!(OsError::XError(Arc::new(X11Error::Xlib(x_err))))) EventLoopError::Os(os_error!(OsError::XError(Arc::new(X11Error::Xlib(x_err)))))
})?; })?;
@ -544,12 +525,12 @@ impl<T: 'static> EventLoop<T> {
where where
F: FnMut(Event<T>, &RootELW), F: FnMut(Event<T>, &RootELW),
{ {
callback(crate::event::Event::NewEvents(cause), &self.target); callback(Event::NewEvents(cause), &self.event_processor.target);
// NB: For consistency all platforms must emit a 'resumed' event even though X11 // NB: For consistency all platforms must emit a 'resumed' event even though X11
// applications don't themselves have a formal suspend/resume lifecycle. // applications don't themselves have a formal suspend/resume lifecycle.
if cause == StartCause::Init { if cause == StartCause::Init {
callback(crate::event::Event::Resumed, &self.target); callback(Event::Resumed, &self.event_processor.target);
} }
// Process all pending events // Process all pending events
@ -564,16 +545,16 @@ impl<T: 'static> EventLoop<T> {
}); });
match token { match token {
Some(Ok(token)) => callback( Some(Ok(token)) => {
crate::event::Event::WindowEvent { let event = Event::WindowEvent {
window_id: crate::window::WindowId(window_id), window_id: crate::window::WindowId(window_id),
event: crate::event::WindowEvent::ActivationTokenDone { event: WindowEvent::ActivationTokenDone {
serial, serial,
token: crate::window::ActivationToken::_new(token), token: crate::window::ActivationToken::_new(token),
}, },
}, };
&self.target, callback(event, &self.event_processor.target)
), }
Some(Err(e)) => { Some(Err(e)) => {
log::error!("Failed to get activation token: {}", e); log::error!("Failed to get activation token: {}", e);
} }
@ -584,7 +565,7 @@ impl<T: 'static> EventLoop<T> {
// Empty the user event buffer // Empty the user event buffer
{ {
while let Ok(event) = self.user_receiver.try_recv() { while let Ok(event) = self.user_receiver.try_recv() {
callback(crate::event::Event::UserEvent(event), &self.target); callback(Event::UserEvent(event), &self.event_processor.target);
} }
} }
@ -603,14 +584,14 @@ impl<T: 'static> EventLoop<T> {
window_id, window_id,
event: WindowEvent::RedrawRequested, event: WindowEvent::RedrawRequested,
}, },
&self.target, &self.event_processor.target,
); );
} }
} }
// This is always the last event we dispatch before poll again // This is always the last event we dispatch before poll again
{ {
callback(crate::event::Event::AboutToWait, &self.target); callback(Event::AboutToWait, &self.event_processor.target);
} }
} }
@ -618,40 +599,44 @@ impl<T: 'static> EventLoop<T> {
where where
F: FnMut(Event<T>, &RootELW), F: FnMut(Event<T>, &RootELW),
{ {
let target = &self.target;
let mut xev = MaybeUninit::uninit(); let mut xev = MaybeUninit::uninit();
let wt = get_xtarget(&self.target);
while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } { while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } {
let mut xev = unsafe { xev.assume_init() }; let mut xev = unsafe { xev.assume_init() };
self.event_processor.process_event(&mut xev, |event| { self.event_processor
if let Event::WindowEvent { .process_event(&mut xev, |window_target, event| {
window_id: crate::window::WindowId(wid), if let Event::WindowEvent {
event: WindowEvent::RedrawRequested, window_id: crate::window::WindowId(wid),
} = event event: WindowEvent::RedrawRequested,
{ } = event
wt.redraw_sender.send(wid).unwrap(); {
} else { let window_target = EventProcessor::window_target(window_target);
callback(event, target); window_target.redraw_sender.send(wid).unwrap();
} } else {
}); callback(event, window_target);
}
});
} }
} }
fn control_flow(&self) -> ControlFlow { fn control_flow(&self) -> ControlFlow {
self.target.p.control_flow() let window_target = EventProcessor::window_target(&self.event_processor.target);
window_target.control_flow()
} }
fn exiting(&self) -> bool { fn exiting(&self) -> bool {
self.target.p.exiting() let window_target = EventProcessor::window_target(&self.event_processor.target);
window_target.exiting()
} }
fn set_exit_code(&self, code: i32) { fn set_exit_code(&self, code: i32) {
self.target.p.set_exit_code(code) let window_target = EventProcessor::window_target(&self.event_processor.target);
window_target.set_exit_code(code);
} }
fn exit_code(&self) -> Option<i32> { fn exit_code(&self) -> Option<i32> {
self.target.p.exit_code() let window_target = EventProcessor::window_target(&self.event_processor.target);
window_target.exit_code()
} }
} }
@ -667,14 +652,6 @@ impl<T> AsRawFd for EventLoop<T> {
} }
} }
pub(crate) fn get_xtarget(target: &RootELW) -> &EventLoopWindowTarget {
match target.p {
super::EventLoopWindowTarget::X(ref target) => target,
#[cfg(wayland_platform)]
_ => unreachable!(),
}
}
impl EventLoopWindowTarget { impl EventLoopWindowTarget {
/// Returns the `XConnection` of this events loop. /// Returns the `XConnection` of this events loop.
#[inline] #[inline]

View file

@ -123,7 +123,7 @@ impl SharedState {
unsafe impl Send for UnownedWindow {} unsafe impl Send for UnownedWindow {}
unsafe impl Sync for UnownedWindow {} unsafe impl Sync for UnownedWindow {}
pub(crate) struct UnownedWindow { pub struct UnownedWindow {
pub(crate) xconn: Arc<XConnection>, // never changes pub(crate) xconn: Arc<XConnection>, // never changes
xwindow: xproto::Window, // never changes xwindow: xproto::Window, // never changes
#[allow(dead_code)] #[allow(dead_code)]

View file

@ -22,7 +22,7 @@ use x11rb::{
}; };
/// A connection to an X server. /// A connection to an X server.
pub(crate) struct XConnection { pub struct XConnection {
pub xlib: ffi::Xlib, pub xlib: ffi::Xlib,
pub xcursor: ffi::Xcursor, pub xcursor: ffi::Xcursor,
@ -309,7 +309,7 @@ impl fmt::Display for XError {
/// Error returned if this system doesn't have XLib or can't create an X connection. /// Error returned if this system doesn't have XLib or can't create an X connection.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) enum XNotSupported { pub enum XNotSupported {
/// Failed to load one or several shared libraries. /// Failed to load one or several shared libraries.
LibraryOpenError(ffi::OpenError), LibraryOpenError(ffi::OpenError),