use cueward_core::files::{FileError, FileErrorCode};
use objc2::{
msg_send,
rc::{Retained, autoreleasepool},
runtime::{AnyClass, AnyObject},
};
use objc2_foundation::{NSArray, NSString, NSURL};
use std::path::Path;
#[link(name = "AppKit", kind = "framework")]
unsafe extern "C" {}
fn class(name: &'static std::ffi::CStr) -> Result<&'static AnyClass, FileError> {
AnyClass::get(name).ok_or_else(|| {
FileError::new(
FileErrorCode::Unavailable,
"AppKit class is unavailable; action was not submitted",
)
})
}
fn workspace() -> Result<Retained<AnyObject>, FileError> {
let class = class(c"NSWorkspace")?;
Ok(unsafe { msg_send![class, sharedWorkspace] })
}
pub(super) fn finder_pid() -> Result<Option<i32>, FileError> {
autoreleasepool(|_| {
let class = class(c"NSRunningApplication")?;
let id = NSString::from_str("com.apple.finder");
let apps: Retained<NSArray<AnyObject>> =
unsafe { msg_send![class, runningApplicationsWithBundleIdentifier: &*id] };
match apps.count() {
0 => Ok(None),
1 => {
let app = apps.objectAtIndex(0);
let terminated: bool = unsafe { msg_send![&*app, isTerminated] };
let pid: i32 = unsafe { msg_send![&*app, processIdentifier] };
Ok((!terminated && pid > 0).then_some(pid))
}
_ => Err(FileError::new(
FileErrorCode::Unavailable,
"multiple Finder processes are running; observe before retrying",
)),
}
})
}
pub(super) fn foreground_pid() -> Option<i32> {
autoreleasepool(|_| {
let workspace = workspace().ok()?;
let app: Option<Retained<AnyObject>> =
unsafe { msg_send![&*workspace, frontmostApplication] };
let app = app?;
let pid: i32 = unsafe { msg_send![&*app, processIdentifier] };
(pid > 0).then_some(pid)
})
}
pub(super) fn reveal(path: &Path) -> Result<(), FileError> {
let text = path.to_str().ok_or_else(|| {
FileError::new(
FileErrorCode::UnsupportedPathEncoding,
"reveal path must be UTF-8",
)
})?;
autoreleasepool(|_| {
let workspace = workspace()?;
let url = NSURL::fileURLWithPath(&NSString::from_str(text));
let urls = NSArray::from_retained_slice(&[url]);
unsafe {
let _: () = msg_send![&*workspace, activateFileViewerSelectingURLs: &*urls];
}
Ok(())
})
}