use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::atomic::{AtomicU32, Ordering};
mod app;
pub mod apps;
pub mod capture;
#[path = "../linux/chord_capture.rs"]
pub mod chord_capture;
pub mod clipboard;
pub mod emit;
mod ffi;
pub mod focus;
pub mod hotkey;
mod keymap;
pub mod tray;
pub use app::bootstrap_main;
pub(crate) struct MainState {
pub hotkeys: HashMap<u32, hotkey::HotkeyResources>,
pub carbon_handler_installed: bool,
pub tray: Option<tray::TrayResources>,
}
impl MainState {
fn new() -> Self {
Self {
hotkeys: HashMap::new(),
carbon_handler_installed: false,
tray: None,
}
}
}
thread_local! {
static MAIN_STATE_TLS: RefCell<Option<MainState>> = const { RefCell::new(None) };
}
pub(crate) fn with_main_state<R>(f: impl FnOnce(&mut MainState) -> R) -> R {
MAIN_STATE_TLS.with(|cell| {
let mut borrow = cell.borrow_mut();
let state = borrow
.as_mut()
.expect("macOS main-thread state not initialised; was bootstrap_main called?");
f(state)
})
}
pub(crate) fn install_main_state() {
MAIN_STATE_TLS.with(|cell| {
let mut borrow = cell.borrow_mut();
if borrow.is_none() {
*borrow = Some(MainState::new());
}
});
}
static NEXT_ID: AtomicU32 = AtomicU32::new(1);
pub(crate) fn next_id() -> u32 {
NEXT_ID.fetch_add(1, Ordering::Relaxed)
}
pub fn primary_screen_size() -> (f32, f32) {
app::run_on_main_sync(|| {
use objc2::MainThreadMarker;
use objc2_app_kit::NSScreen;
let Some(mtm) = MainThreadMarker::new() else {
return (0.0, 0.0);
};
let Some(screen) = NSScreen::mainScreen(mtm) else {
return (0.0, 0.0);
};
let frame = screen.frame();
(frame.size.width as f32, frame.size.height as f32)
})
}
pub fn show_in_dock() {
use objc2::MainThreadMarker;
use objc2_app_kit::{NSApplication, NSApplicationActivationPolicy};
let Some(mtm) = MainThreadMarker::new() else {
return;
};
NSApplication::sharedApplication(mtm)
.setActivationPolicy(NSApplicationActivationPolicy::Regular);
}
pub fn activate() {
use objc2::MainThreadMarker;
use objc2_app_kit::NSApplication;
let Some(mtm) = MainThreadMarker::new() else {
return;
};
NSApplication::sharedApplication(mtm).activate();
}