use std::{
cell::{LazyCell, RefCell},
collections::HashMap,
error::Error,
sync::Arc,
};
use tokio::runtime::Handle;
use tracing::info;
use crate::feature::FeatureManager;
extern "C" {
pub fn register_callback_for_clamshell_change(callback: extern "C" fn(bool));
fn unregister_callback_for_clamshell_change();
}
struct Registry {
callbacks: HashMap<u32, Box<dyn Fn(bool)>>,
next_id: u32,
activated: bool,
}
static mut REGISTRY: LazyCell<RefCell<Registry>> = LazyCell::new(|| RefCell::new(Registry::new()));
#[no_mangle]
extern "C" fn on_receive_laptoplid_change(open: bool) {
let r = unsafe { REGISTRY.borrow() };
if !r.activated {
return;
}
r.callbacks.values().for_each(|f| f(open))
}
impl Registry {
fn new() -> Self {
return Self {
callbacks: HashMap::new(),
next_id: 0,
activated: false,
};
}
pub fn register(&mut self, callback: Box<dyn Fn(bool)>) -> u32 {
let id = self.next_id;
self.callbacks.insert(id, callback);
self.next_id += 1;
return id;
}
pub fn unregister(&mut self, id: u32) -> Result<(), Box<dyn Error>> {
self.callbacks.remove(&id);
Ok(())
}
}
pub fn turn_on_laptoplid_change(
fm: Arc<dyn FeatureManager>,
runtime: Handle,
) -> Result<(), String> {
info!("turn on laptoplid change detection");
unsafe {
if REGISTRY.borrow().activated {
return Ok(());
}
REGISTRY.borrow_mut().activated = true;
if REGISTRY.borrow().callbacks.len() == 0 {
REGISTRY.borrow_mut().register(Box::new(move |open| {
let runtime = runtime.clone();
let fm = fm.clone();
runtime.spawn(async move {
fm.lid_change(open).await;
});
}));
}
register_callback_for_clamshell_change(on_receive_laptoplid_change);
}
return Ok(());
}
pub fn turn_off_laptoplid_change() -> Result<(), String> {
info!("turn off laptoplid change detection");
unsafe {
REGISTRY.borrow_mut().activated = false;
unregister_callback_for_clamshell_change();
}
return Ok(());
}