1
0
Fork 0
forked from wry/wry

Merge pull request #125 from mahkoh/jorth/mutable-callbacks

config: accept FnMut instead of Fn for callbacks
This commit is contained in:
mahkoh 2024-03-06 16:49:03 +01:00 committed by GitHub
commit 0ee539e625
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 84 additions and 49 deletions

View file

@ -28,6 +28,7 @@ use {
future::Future,
mem,
ops::Deref,
panic::{catch_unwind, AssertUnwindSafe},
pin::Pin,
ptr,
rc::Rc,
@ -41,23 +42,42 @@ use {
},
};
type Callback<T = ()> = Rc<RefCell<dyn FnMut(T)>>;
fn cb<T, F: FnMut(T) + 'static>(f: F) -> Callback<T> {
Rc::new(RefCell::new(f))
}
fn run_cb<T>(name: &str, cb: &Callback<T>, t: T) {
match cb.try_borrow_mut() {
Ok(mut cb) => ignore_panic(name, || cb(t)),
Err(_) => log::error!("Cannot invoke {name} callback because it is already running"),
}
}
fn ignore_panic(name: &str, f: impl FnOnce()) {
if catch_unwind(AssertUnwindSafe(f)).is_err() {
log::error!("A panic occurred in a {name} callback");
}
}
pub(crate) struct Client {
configure: extern "C" fn(),
srv_data: *const u8,
srv_unref: unsafe extern "C" fn(data: *const u8),
srv_handler: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
key_handlers: RefCell<HashMap<(Seat, ModifiedKeySym), Rc<dyn Fn()>>>,
timer_handlers: RefCell<HashMap<Timer, Rc<dyn Fn()>>>,
key_handlers: RefCell<HashMap<(Seat, ModifiedKeySym), Callback>>,
timer_handlers: RefCell<HashMap<Timer, Callback>>,
response: RefCell<Vec<Response>>,
on_new_seat: RefCell<Option<Rc<dyn Fn(Seat)>>>,
on_new_input_device: RefCell<Option<Rc<dyn Fn(InputDevice)>>>,
on_connector_connected: RefCell<Option<Rc<dyn Fn(Connector)>>>,
on_new_seat: RefCell<Option<Callback<Seat>>>,
on_new_input_device: RefCell<Option<Callback<InputDevice>>>,
on_connector_connected: RefCell<Option<Callback<Connector>>>,
on_graphics_initialized: Cell<Option<Box<dyn FnOnce()>>>,
on_devices_enumerated: Cell<Option<Box<dyn FnOnce()>>>,
on_new_connector: RefCell<Option<Rc<dyn Fn(Connector)>>>,
on_new_drm_device: RefCell<Option<Rc<dyn Fn(DrmDevice)>>>,
on_del_drm_device: RefCell<Option<Rc<dyn Fn(DrmDevice)>>>,
on_idle: RefCell<Option<Rc<dyn Fn()>>>,
on_new_connector: RefCell<Option<Callback<Connector>>>,
on_new_drm_device: RefCell<Option<Callback<DrmDevice>>>,
on_del_drm_device: RefCell<Option<Callback<DrmDevice>>>,
on_idle: RefCell<Option<Callback>>,
bufs: RefCell<Vec<Vec<u8>>>,
reload: Cell<bool>,
read_interests: RefCell<HashMap<PollableId, Interest>>,
@ -319,8 +339,10 @@ impl Client {
});
}
pub fn on_timer_tick<F: Fn() + 'static>(&self, timer: Timer, f: F) {
self.timer_handlers.borrow_mut().insert(timer, Rc::new(f));
pub fn on_timer_tick<F: FnMut() + 'static>(&self, timer: Timer, mut f: F) {
self.timer_handlers
.borrow_mut()
.insert(timer, cb(move |_| f()));
}
pub fn get_workspace(&self, name: &str) -> Workspace {
@ -496,8 +518,8 @@ impl Client {
devices
}
pub fn on_new_seat<F: Fn(Seat) + 'static>(&self, f: F) {
*self.on_new_seat.borrow_mut() = Some(Rc::new(f));
pub fn on_new_seat<F: FnMut(Seat) + 'static>(&self, f: F) {
*self.on_new_seat.borrow_mut() = Some(cb(f));
}
pub fn quit(&self) {
@ -508,8 +530,8 @@ impl Client {
self.send(&ClientMessage::SwitchTo { vtnr })
}
pub fn on_new_input_device<F: Fn(InputDevice) + 'static>(&self, f: F) {
*self.on_new_input_device.borrow_mut() = Some(Rc::new(f));
pub fn on_new_input_device<F: FnMut(InputDevice) + 'static>(&self, f: F) {
*self.on_new_input_device.borrow_mut() = Some(cb(f));
}
pub fn set_double_click_interval(&self, usec: u64) {
@ -639,24 +661,24 @@ impl Client {
devices
}
pub fn on_new_drm_device<F: Fn(DrmDevice) + 'static>(&self, f: F) {
*self.on_new_drm_device.borrow_mut() = Some(Rc::new(f));
pub fn on_new_drm_device<F: FnMut(DrmDevice) + 'static>(&self, f: F) {
*self.on_new_drm_device.borrow_mut() = Some(cb(f));
}
pub fn on_del_drm_device<F: Fn(DrmDevice) + 'static>(&self, f: F) {
*self.on_del_drm_device.borrow_mut() = Some(Rc::new(f));
pub fn on_del_drm_device<F: FnMut(DrmDevice) + 'static>(&self, f: F) {
*self.on_del_drm_device.borrow_mut() = Some(cb(f));
}
pub fn on_new_connector<F: Fn(Connector) + 'static>(&self, f: F) {
*self.on_new_connector.borrow_mut() = Some(Rc::new(f));
pub fn on_new_connector<F: FnMut(Connector) + 'static>(&self, f: F) {
*self.on_new_connector.borrow_mut() = Some(cb(f));
}
pub fn on_idle<F: Fn() + 'static>(&self, f: F) {
*self.on_idle.borrow_mut() = Some(Rc::new(f));
pub fn on_idle<F: FnMut() + 'static>(&self, mut f: F) {
*self.on_idle.borrow_mut() = Some(cb(move |_| f()));
}
pub fn on_connector_connected<F: Fn(Connector) + 'static>(&self, f: F) {
*self.on_connector_connected.borrow_mut() = Some(Rc::new(f));
pub fn on_connector_connected<F: FnMut(Connector) + 'static>(&self, f: F) {
*self.on_connector_connected.borrow_mut() = Some(cb(f));
}
pub fn on_graphics_initialized<F: FnOnce() + 'static>(&self, f: F) {
@ -742,11 +764,16 @@ impl Client {
keymap
}
pub fn bind<T: Into<ModifiedKeySym>, F: Fn() + 'static>(&self, seat: Seat, mod_sym: T, f: F) {
pub fn bind<T: Into<ModifiedKeySym>, F: FnMut() + 'static>(
&self,
seat: Seat,
mod_sym: T,
mut f: F,
) {
let mod_sym = mod_sym.into();
let register = {
let mut kh = self.key_handlers.borrow_mut();
let f = Rc::new(f);
let f = cb(move |_| f());
match kh.entry((seat, mod_sym)) {
Entry::Occupied(mut o) => {
*o.get_mut() = f;
@ -843,10 +870,18 @@ impl Client {
if let Some(fut) = fut {
let mut fut = fut.borrow_mut();
let fut = &mut *fut;
if let Poll::Ready(()) =
let res = catch_unwind(AssertUnwindSafe(|| {
fut.task.as_mut().poll(&mut Context::from_waker(&fut.waker))
{
futures.tasks.borrow_mut().remove(&id);
}));
match res {
Err(_) => {
log::error!("A task panicked");
futures.tasks.borrow_mut().remove(&id);
}
Ok(Poll::Ready(())) => {
futures.tasks.borrow_mut().remove(&id);
}
Ok(_) => {}
}
}
}
@ -914,39 +949,39 @@ impl Client {
let ms = ModifiedKeySym { mods, sym };
let handler = self.key_handlers.borrow_mut().get(&(seat, ms)).cloned();
if let Some(handler) = handler {
handler();
run_cb("shortcut", &handler, ());
}
}
ServerMessage::NewInputDevice { device } => {
let handler = self.on_new_input_device.borrow_mut().clone();
if let Some(handler) = handler {
handler(device);
run_cb("new input device", &handler, device);
}
}
ServerMessage::DelInputDevice { .. } => {}
ServerMessage::ConnectorConnect { device } => {
let handler = self.on_connector_connected.borrow_mut().clone();
if let Some(handler) = handler {
handler(device);
run_cb("connector connected", &handler, device);
}
}
ServerMessage::ConnectorDisconnect { .. } => {}
ServerMessage::NewConnector { device } => {
let handler = self.on_new_connector.borrow_mut().clone();
if let Some(handler) = handler {
handler(device);
run_cb("new connector", &handler, device);
}
}
ServerMessage::DelConnector { .. } => {}
ServerMessage::TimerExpired { timer } => {
let handler = self.timer_handlers.borrow_mut().get(&timer).cloned();
if let Some(handler) = handler {
handler();
run_cb("timer", &handler, ());
}
}
ServerMessage::GraphicsInitialized => {
if let Some(handler) = self.on_graphics_initialized.take() {
handler();
ignore_panic("graphics initialized", handler);
}
}
ServerMessage::Clear => {
@ -955,24 +990,24 @@ impl Client {
ServerMessage::NewDrmDev { device } => {
let handler = self.on_new_drm_device.borrow_mut();
if let Some(handler) = handler.deref() {
handler(device);
run_cb("new drm device", handler, device);
}
}
ServerMessage::DelDrmDev { device } => {
let handler = self.on_del_drm_device.borrow_mut();
if let Some(handler) = handler.deref() {
handler(device);
run_cb("del drm device", handler, device);
}
}
ServerMessage::Idle => {
let handler = self.on_idle.borrow_mut();
if let Some(handler) = handler.deref() {
handler();
run_cb("idle", handler, ());
}
}
ServerMessage::DevicesEnumerated => {
if let Some(handler) = self.on_devices_enumerated.take() {
handler();
ignore_panic("devices enumerated", handler);
}
}
ServerMessage::InterestReady { id, writable, res } => {

View file

@ -161,7 +161,7 @@ impl Seat {
///
/// CapsLock and NumLock are ignored during modifier evaluation. Therefore, bindings
/// containing these modifiers will never be invoked.
pub fn bind<T: Into<ModifiedKeySym>, F: Fn() + 'static>(self, mod_sym: T, f: F) {
pub fn bind<T: Into<ModifiedKeySym>, F: FnMut() + 'static>(self, mod_sym: T, f: F) {
get!().bind(self, mod_sym, f)
}
@ -324,12 +324,12 @@ pub fn get_seat(name: &str) -> Seat {
}
/// Sets a closure to run when a new seat has been created.
pub fn on_new_seat<F: Fn(Seat) + 'static>(f: F) {
pub fn on_new_seat<F: FnMut(Seat) + 'static>(f: F) {
get!().on_new_seat(f)
}
/// Sets a closure to run when a new input device has been added.
pub fn on_new_input_device<F: Fn(InputDevice) + 'static>(f: F) {
pub fn on_new_input_device<F: FnMut(InputDevice) + 'static>(f: F) {
get!().on_new_input_device(f)
}

View file

@ -185,7 +185,7 @@ impl Display for PciId {
}
/// Sets the callback to be called when the display goes idle.
pub fn on_idle<F: Fn() + 'static>(f: F) {
pub fn on_idle<F: FnMut() + 'static>(f: F) {
get!().on_idle(f)
}

View file

@ -53,7 +53,7 @@ impl Timer {
}
/// Sets the function to be executed when the timer expires.
pub fn on_tick<F: Fn() + 'static>(self, f: F) {
pub fn on_tick<F: FnMut() + 'static>(self, f: F) {
get!().on_timer_tick(self, f);
}
}

View file

@ -220,22 +220,22 @@ pub fn drm_devices() -> Vec<DrmDevice> {
}
/// Sets the callback to be called when a new DRM device appears.
pub fn on_new_drm_device<F: Fn(DrmDevice) + 'static>(f: F) {
pub fn on_new_drm_device<F: FnMut(DrmDevice) + 'static>(f: F) {
get!().on_new_drm_device(f)
}
/// Sets the callback to be called when a DRM device is removed.
pub fn on_drm_device_removed<F: Fn(DrmDevice) + 'static>(f: F) {
pub fn on_drm_device_removed<F: FnMut(DrmDevice) + 'static>(f: F) {
get!().on_del_drm_device(f)
}
/// Sets the callback to be called when a new connector appears.
pub fn on_new_connector<F: Fn(Connector) + 'static>(f: F) {
pub fn on_new_connector<F: FnMut(Connector) + 'static>(f: F) {
get!().on_new_connector(f)
}
/// Sets the callback to be called when a connector becomes connected to an output device.
pub fn on_connector_connected<F: Fn(Connector) + 'static>(f: F) {
pub fn on_connector_connected<F: FnMut(Connector) + 'static>(f: F) {
get!().on_connector_connected(f)
}