Files
Graphite/desktop/ui/src/platform/mac.rs
Timon ba0a97aefe Desktop: Isolate CEF-rendered UI into separate crate and process (#4321)
* Extract CEF rendered UI into a separate process and crate

* Review

* Review

* Review

* Review

* Remove necessary workarounds

* Block on frame copy ack

* Crop and resample frames correctly

* Skip blank frames

* Fix deps

* Fix fmt

* Fix clippy warning

* Review

* Fix todo
2026-07-14 14:51:20 -07:00

64 lines
2.1 KiB
Rust

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<NSApplication> = 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}");
}
}