Merge pull request #125 from mahkoh/jorth/mutable-callbacks
config: accept FnMut instead of Fn for callbacks
This commit is contained in:
commit
0ee539e625
5 changed files with 84 additions and 49 deletions
|
|
@ -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 } => {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue