use fltk::window::Window;
#[cfg(not(target_os = "macos"))]
const ICON_SVG: &str = include_str!("../assets/icon.svg");
#[cfg(not(target_os = "macos"))]
pub fn set_window_icon(wind: &mut Window) {
use fltk::{image::SvgImage, prelude::*};
if let Ok(mut icon) = SvgImage::from_data(ICON_SVG) {
icon.scale(128, 128, true, true);
wind.set_icon(Some(icon));
}
}
#[cfg(target_os = "macos")]
pub fn set_window_icon(_wind: &mut Window) {}
#[cfg(target_os = "macos")]
pub fn set_macos_app_name(name: &str) {
use objc2::MainThreadMarker;
use objc2::rc::autoreleasepool;
use objc2_app_kit::NSApplication;
use objc2_foundation::NSString;
let Some(mtm) = MainThreadMarker::new() else {
return;
};
autoreleasepool(|_| {
let app = NSApplication::sharedApplication(mtm);
let Some(main_menu) = app.mainMenu() else {
return;
};
if main_menu.numberOfItems() <= 0 {
return;
}
let Some(app_item) = main_menu.itemAtIndex(0) else {
return;
};
let Some(app_menu) = app_item.submenu() else {
return;
};
app_menu.setTitle(&NSString::from_str(name));
for i in 0..app_menu.numberOfItems() {
let Some(item) = app_menu.itemAtIndex(i) else {
continue;
};
let current = item.title().to_string();
if current.contains("piki-gui") {
let replaced = current.replace("piki-gui", name);
item.setTitle(&NSString::from_str(&replaced));
}
}
});
}
#[cfg(not(target_os = "macos"))]
pub fn set_macos_app_name(_name: &str) {}
#[cfg(target_os = "macos")]
pub fn set_macos_dock_icon() {
use objc2::rc::autoreleasepool;
use objc2::{AnyThread, MainThreadMarker};
use objc2_app_kit::{NSApplication, NSImage};
use objc2_foundation::NSData;
const ICON_PNG: &[u8] = include_bytes!("../assets/icon-512.png");
let Some(mtm) = MainThreadMarker::new() else {
return;
};
autoreleasepool(|_| {
let data = NSData::with_bytes(ICON_PNG);
let Some(image) = NSImage::initWithData(NSImage::alloc(), &data) else {
return;
};
let app = NSApplication::sharedApplication(mtm);
unsafe {
app.setApplicationIconImage(Some(&image));
}
});
}
#[cfg(not(target_os = "macos"))]
pub fn set_macos_dock_icon() {}
#[cfg(target_os = "macos")]
pub fn set_macos_about() {
fltk::menu::mac_set_about(show_about_panel);
}
#[cfg(not(target_os = "macos"))]
pub fn set_macos_about() {}
#[cfg(target_os = "macos")]
fn show_about_panel() {
use objc2::rc::autoreleasepool;
use objc2::runtime::AnyObject;
use objc2::{AnyThread, MainThreadMarker, Message, msg_send};
use objc2_app_kit::{
NSApplication, NSColor, NSFont, NSImage, NSMutableParagraphStyle, NSTextAlignment,
};
use objc2_foundation::{
NSAttributedString, NSBundle, NSData, NSDictionary, NSMutableAttributedString,
NSMutableDictionary, NSString, NSURL,
};
const ICON_PNG: &[u8] = include_bytes!("../assets/icon-512.png");
const APP_NAME: &str = "Piki";
const VERSION: &str = env!("CARGO_PKG_VERSION");
const DESCRIPTION: &str = "A personal wiki system for your Markdown files";
const COPYRIGHT: &str = "© 2025–2026 Robert Lillack";
const HOMEPAGE: &str = "https://github.com/roblillack/piki";
fn put<T: Message>(dict: &NSMutableDictionary<NSString, AnyObject>, key: &str, value: &T) {
let key = NSString::from_str(key);
unsafe {
let _: () = msg_send![dict, setObject: value, forKey: &*key];
}
}
let Some(mtm) = MainThreadMarker::new() else {
return;
};
autoreleasepool(|_| {
let app = NSApplication::sharedApplication(mtm);
let options = NSMutableDictionary::<NSString, AnyObject>::new();
put(&options, "ApplicationName", &*NSString::from_str(APP_NAME));
put(
&options,
"ApplicationVersion",
&*NSString::from_str(VERSION),
);
let data = NSData::with_bytes(ICON_PNG);
if let Some(image) = NSImage::initWithData(NSImage::alloc(), &data) {
put(&options, "ApplicationIcon", &*image);
}
let credits = NSMutableAttributedString::new();
let para = NSMutableParagraphStyle::new();
para.setAlignment(NSTextAlignment::Center);
let font = NSFont::systemFontOfSize(11.0);
let color = NSColor::secondaryLabelColor();
let append = |text: &str, attrs: &NSDictionary<NSString, AnyObject>| {
let astr = unsafe {
NSAttributedString::initWithString_attributes(
NSAttributedString::alloc(),
&NSString::from_str(text),
Some(attrs),
)
};
credits.appendAttributedString(&astr);
};
let base_attrs = NSMutableDictionary::<NSString, AnyObject>::new();
put(&base_attrs, "NSFont", &*font);
put(&base_attrs, "NSColor", &*color);
put(&base_attrs, "NSParagraphStyle", &*para);
append(DESCRIPTION, &base_attrs);
let has_bundle_copyright = NSBundle::mainBundle()
.objectForInfoDictionaryKey(&NSString::from_str("NSHumanReadableCopyright"))
.is_some();
if !has_bundle_copyright {
append("\n\n", &base_attrs);
append(COPYRIGHT, &base_attrs);
}
append("\n\n", &base_attrs);
let link_attrs = NSMutableDictionary::<NSString, AnyObject>::new();
put(&link_attrs, "NSFont", &*font);
put(&link_attrs, "NSParagraphStyle", &*para);
if let Some(url) = NSURL::URLWithString(&NSString::from_str(HOMEPAGE)) {
put(&link_attrs, "NSLink", &*url);
}
append(HOMEPAGE, &link_attrs);
put(&options, "Credits", &*credits);
unsafe {
app.orderFrontStandardAboutPanelWithOptions(&options);
}
});
}