#[cfg(feature = "artwork")]
use std::io::Cursor;
use block2::RcBlock;
use objc2::rc::{autoreleasepool, Retained};
#[cfg(feature = "artwork")]
use image::ImageReader;
#[cfg(feature = "artwork")]
use {
objc2::{runtime::AnyObject, AnyThread},
objc2_app_kit::{
NSBitmapImageFileType, NSBitmapImageRep, NSBitmapImageRepPropertyKey, NSWorkspace,
},
objc2_foundation::{
NSDictionary, NSFileManager, NSNotification, NSNotificationCenter, NSString,
},
};
#[cfg(not(feature = "artwork"))]
use {
objc2_app_kit::NSWorkspace,
objc2_foundation::{NSFileManager, NSNotification, NSNotificationCenter, NSString},
};
use std::ptr::NonNull;
#[allow(unused_imports)]
use crate::{register_for_now_playing_notifications, BundleInfo, Notification, Observer};
pub fn get_bundle_info(id: &str) -> Option<BundleInfo> {
autoreleasepool(|_| {
let workspace = NSWorkspace::sharedWorkspace();
let url = workspace.URLForApplicationWithBundleIdentifier(&NSString::from_str(id))?;
let path = &url.path()?;
let file_manager = NSFileManager::defaultManager();
let name = file_manager.displayNameAtPath(path);
#[cfg(feature = "artwork")]
let icon = {
let image = workspace.iconForFile(path);
unsafe {
let cg_image =
image.CGImageForProposedRect_context_hints(std::ptr::null_mut(), None, None)?;
let bitmap_rep = NSBitmapImageRep::alloc();
let bitmap_rep = NSBitmapImageRep::initWithCGImage(bitmap_rep, &cg_image);
let props = NSDictionary::<NSBitmapImageRepPropertyKey, AnyObject>::new();
let data = bitmap_rep
.representationUsingType_properties(NSBitmapImageFileType::PNG, &props)?;
Some(
ImageReader::new(Cursor::new(data.to_vec()))
.with_guessed_format()
.ok()?
.decode()
.ok()?,
)
}
};
Some(BundleInfo {
name: name.to_string(),
#[cfg(feature = "artwork")]
icon,
})
})
}
pub fn add_observer<F: Fn() + 'static>(notification: Notification, closure: F) -> Observer {
unsafe {
let observer = NSNotificationCenter::defaultCenter()
.addObserverForName_object_queue_usingBlock(
Some(NSString::from_str(notification.as_str()).as_ref()),
None,
None,
&RcBlock::new(move |_: NonNull<NSNotification>| closure()),
);
Retained::cast_unchecked(observer)
}
}
pub fn remove_observer(observer: Observer) {
unsafe {
NSNotificationCenter::defaultCenter().removeObserver(&observer);
}
}