use objc2::rc::Retained; use objc2::runtime::Bool; use objc2::{ClassType, define_class, msg_send}; use objc2_app_kit::{NSApplication, NSApplicationActivationPolicy, NSEvent, NSResponder}; use objc2_foundation::NSObject; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::Duration; use cef::application_mac::{CefAppProtocol, CrAppControlProtocol, CrAppProtocol}; static HANDLING_SEND_EVENT: AtomicBool = AtomicBool::new(false); define_class!( #[unsafe(super(NSApplication, NSResponder, NSObject))] #[name = "GraphiteCefHostApplication"] struct CefHostApplication; unsafe impl CrAppProtocol for CefHostApplication { #[unsafe(method(isHandlingSendEvent))] fn is_handling_send_event(&self) -> Bool { Bool::new(HANDLING_SEND_EVENT.load(Ordering::Relaxed)) } } unsafe impl CrAppControlProtocol for CefHostApplication { #[unsafe(method(setHandlingSendEvent:))] fn set_handling_send_event(&self, handling: Bool) { HANDLING_SEND_EVENT.store(handling.as_bool(), Ordering::Relaxed); } } unsafe impl CefAppProtocol for CefHostApplication {} impl CefHostApplication { #[unsafe(method(sendEvent:))] fn send_event(&self, event: &NSEvent) { let was_handling = HANDLING_SEND_EVENT.swap(true, Ordering::Relaxed); let _: () = unsafe { msg_send![super(self), sendEvent: event] }; HANDLING_SEND_EVENT.store(was_handling, Ordering::Relaxed); } } ); pub(crate) fn install_application() { let app: Retained = unsafe { msg_send![CefHostApplication::class(), sharedApplication] }; app.setActivationPolicy(NSApplicationActivationPolicy::Prohibited); } pub(crate) fn spawn_parent_watchdog(main_pid: u32) { let result = std::thread::Builder::new().name("parent-watchdog".to_string()).spawn(move || { loop { // SAFETY: getppid is always safe to call. if unsafe { libc::getppid() } as u32 != main_pid { tracing::warn!("Parent process is gone, exiting..."); std::process::exit(0); } std::thread::sleep(Duration::from_millis(500)); } }); if let Err(e) = result { tracing::error!("Failed to spawn parent watchdog: {e}"); } }