diff --git a/standalone/scripts/dogfood.sh b/standalone/scripts/dogfood.sh index 7ada9c75..825db04b 100755 --- a/standalone/scripts/dogfood.sh +++ b/standalone/scripts/dogfood.sh @@ -81,8 +81,20 @@ if [[ "${1:-}" != "--no-install" ]]; then echo "After that, 'dogfood:standalone' will work from then on." exit 1 fi + if pgrep -x dormouse >/dev/null 2>&1; then + osascript -e 'tell application id "sh.dormouse.standalone" to quit' \ + >/dev/null 2>&1 || true + for _ in {1..50}; do + pgrep -x dormouse >/dev/null 2>&1 || break + sleep 0.1 + done + pkill -x dormouse >/dev/null 2>&1 || true + fi rm -rf "$INSTALL_DIR" cp -r "$RELEASE_DIR/bundle/macos/Dormouse Terminal.app" "$INSTALL_DIR" + touch "$INSTALL_DIR" + /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister \ + -f "$INSTALL_DIR" >/dev/null 2>&1 || true echo "✦ Installed to $INSTALL_DIR" ;; *) diff --git a/standalone/src-tauri/Cargo.lock b/standalone/src-tauri/Cargo.lock index 785d9499..2ef33fda 100644 --- a/standalone/src-tauri/Cargo.lock +++ b/standalone/src-tauri/Cargo.lock @@ -662,6 +662,9 @@ name = "dormouse" version = "0.11.0" dependencies = [ "base64 0.22.1", + "objc2", + "objc2-app-kit", + "objc2-foundation", "process-wrap", "serde", "serde_json", diff --git a/standalone/src-tauri/Cargo.toml b/standalone/src-tauri/Cargo.toml index 6474f5ec..70905c75 100644 --- a/standalone/src-tauri/Cargo.toml +++ b/standalone/src-tauri/Cargo.toml @@ -26,6 +26,11 @@ process-wrap = { version = "9", features = ["std"] } [target.'cfg(windows)'.dependencies] windows = { version = "0.62", features = ["Win32_System_Threading"] } +[target.'cfg(target_os = "macos")'.dependencies] +objc2 = "0.6" +objc2-app-kit = { version = "0.3", default-features = false, features = ["NSApplication", "NSImage"] } +objc2-foundation = { version = "0.3", default-features = false, features = ["NSData"] } + [profile.release] strip = true lto = true diff --git a/standalone/src-tauri/icons/dock-icon.png b/standalone/src-tauri/icons/dock-icon.png new file mode 100644 index 00000000..84c94455 Binary files /dev/null and b/standalone/src-tauri/icons/dock-icon.png differ diff --git a/standalone/src-tauri/src/lib.rs b/standalone/src-tauri/src/lib.rs index 21740530..0da077e6 100644 --- a/standalone/src-tauri/src/lib.rs +++ b/standalone/src-tauri/src/lib.rs @@ -115,6 +115,27 @@ fn append_log(message: impl AsRef) { } } +#[cfg(target_os = "macos")] +fn set_macos_dock_icon() { + use objc2::{AllocAnyThread, MainThreadMarker}; + use objc2_app_kit::{NSApplication, NSImage}; + use objc2_foundation::NSData; + + let mtm = unsafe { MainThreadMarker::new_unchecked() }; + let app = NSApplication::sharedApplication(mtm); + // The largest size exploded from icon.icns (1024×1024) — it carries the + // built-in transparent padding the bundle's edge-to-edge 128x128@2x.png lacks. + let data = NSData::with_bytes(include_bytes!("../icons/dock-icon.png")); + let Some(app_icon) = NSImage::initWithData(NSImage::alloc(), &data) else { + append_log("[app] failed to create macOS dock icon image"); + return; + }; + + unsafe { + app.setApplicationIconImage(Some(&app_icon)); + } +} + fn read_log_tail(max_bytes: usize) -> Result { let path = log_path(); let contents = std::fs::read_to_string(path) @@ -991,13 +1012,16 @@ pub fn run() { ]) .build(tauri::generate_context!()) .expect("error while building Dormouse") - .run(|app, event| { - if let RunEvent::Exit = event { + .run(|app, event| match event { + #[cfg(target_os = "macos")] + RunEvent::Ready => set_macos_dock_icon(), + RunEvent::Exit => { if let Some(state) = app.try_state::() { append_log("[app] exit — shutting down sidecar"); shutdown_sidecar_and_wait(&state); } } + _ => {} }); }