use std::sync::Mutex;
use std::sync::atomic::{AtomicBool, Ordering};
use winit::event_loop::EventLoopProxy;
use crate::access_bridge::UserEvent;
static PROXY: Mutex<Option<EventLoopProxy<UserEvent>>> = Mutex::new(None);
static PENDING: AtomicBool = AtomicBool::new(false);
pub fn watch(proxy: EventLoopProxy<UserEvent>) {
*PROXY.lock().unwrap_or_else(|e| e.into_inner()) = Some(proxy);
#[cfg(target_os = "macos")]
macos::observe();
}
#[cfg_attr(not(any(target_os = "macos", target_os = "windows")), allow(dead_code))]
pub fn changed() {
if PENDING.swap(true, Ordering::AcqRel) {
return;
}
let sent = PROXY
.lock()
.unwrap_or_else(|e| e.into_inner())
.as_ref()
.is_some_and(|proxy| proxy.send_event(UserEvent::FontsChanged).is_ok());
if !sent {
PENDING.store(false, Ordering::Release);
}
}
pub fn handled() {
PENDING.store(false, Ordering::Release);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_signal_with_nowhere_to_go_does_not_block_the_next() {
*PROXY.lock().unwrap() = None;
changed();
assert!(!PENDING.load(Ordering::Acquire));
PENDING.store(true, Ordering::Release);
handled();
assert!(!PENDING.load(Ordering::Acquire));
}
}
#[cfg(target_os = "macos")]
mod macos {
use std::ffi::c_void;
use std::sync::Once;
type CFNotificationCenterRef = *mut c_void;
type CFStringRef = *const c_void;
type Callback = extern "C" fn(
center: CFNotificationCenterRef,
observer: *mut c_void,
name: CFStringRef,
object: *const c_void,
user_info: *const c_void,
);
const DELIVER_IMMEDIATELY: isize = 4;
#[link(name = "CoreFoundation", kind = "framework")]
unsafe extern "C" {
fn CFNotificationCenterGetLocalCenter() -> CFNotificationCenterRef;
fn CFNotificationCenterAddObserver(
center: CFNotificationCenterRef,
observer: *const c_void,
callback: Callback,
name: CFStringRef,
object: *const c_void,
behavior: isize,
);
}
#[link(name = "CoreText", kind = "framework")]
unsafe extern "C" {
static kCTFontManagerRegisteredFontsChangedNotification: CFStringRef;
}
extern "C" fn fonts_changed(
_center: CFNotificationCenterRef,
_observer: *mut c_void,
_name: CFStringRef,
_object: *const c_void,
_user_info: *const c_void,
) {
super::changed();
}
pub fn observe() {
static ONCE: Once = Once::new();
ONCE.call_once(|| unsafe {
CFNotificationCenterAddObserver(
CFNotificationCenterGetLocalCenter(),
c"kui.system-fonts".as_ptr().cast(),
fonts_changed,
kCTFontManagerRegisteredFontsChangedNotification,
std::ptr::null(),
DELIVER_IMMEDIATELY,
);
});
}
}