Skip to content

macOS: the app's icon in the Dock and the app switcher for a build outside a bundle - #3

Merged
kylekz merged 1 commit into
kylekz:mainfrom
Method-es:feat/macos-dev-icon
Oct 29, 2026
Merged

kylekz merged 1 commit into
kylekz:mainfrom
Method-es:feat/macos-dev-icon

Conversation

@Method-es

Copy link
Copy Markdown

Summary

On macOS, AppKit takes an app's Dock and app-switcher icon from its bundle's CFBundleIconFile. Only the packaged app (script/package) has a bundle, so a development build (cargo run -p dv, target/release/dv, script/check-mac runs) shows the generic executable icon in the Dock and ⌘Tab.

At startup, a build that isn't running from an .app now hands AppKit the bundle's own icon: crates/dv/resources/macos/dv.icns, embedded with include_bytes! and set through -[NSApplication setApplicationIconImage:]. A bundled app keeps its own and is left alone.

How

  • crates/dv/src/dock_icon.rs (macOS, gui only): checks -[NSBundle mainBundle] bundlePath for .app, else builds an NSImage from the icon's bytes and sets it. Every returned object is checked for nil, and it does nothing if AppKit can't read the image. Raw msg_send!, as gpui_automation does, so no AppKit bindings crate.
  • app.rs calls it after startup, before activation.
  • objc2 (the workspace's 0.6) joins dv's macOS dependencies, optional with gui, so the headless build doesn't get it. cargo tree -p dv --no-default-features lists the same objc2-* crates as before, from notify's file watcher.
  • PLAN §13.1 says so.

Testing

  • Unit tests: is_app_bundle on bundle and plain paths, and that the embedded bytes are an icns file.
  • On macOS (Apple silicon): clippy clean in all three shapes; cargo test -p dv -p dv_ui passes. Checked by hand that a release build outside a bundle shows the dv mark in the Dock and ⌘Tab. The e2e runner's background mode makes the app an accessory (no Dock icon), so no scenario can show it.
  • Not run: the packaged .pkg (needs .NET); dock_icon returns early there because its main bundle is the .app.

Independent of #1 and #2.

…tside a bundle

AppKit takes an app's icon from its bundle, which only the packaged app has, so a
development build (cargo run, target/release/dv) showed the generic executable icon in the
Dock and the app switcher. At startup such a build now hands AppKit the bundle's own
resources/macos/dv.icns (-[NSApplication setApplicationIconImage:], dock_icon.rs); a
bundled app keeps its own. objc2 joins dv's macOS dependencies, with gui only. PLAN §13.1.
@kylekz

kylekz commented Oct 29, 2026

Copy link
Copy Markdown
Owner

thanks for all three of these :)

@kylekz
kylekz merged commit 0e786b8 into kylekz:main Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants