fix(desktop): set macOS dock / Cmd+Tab icon via Taskbar API

Window(icon = ...) only sets the in-title-bar proxy icon — it does NOT
drive the Cmd+Tab app switcher on macOS. That reads java.awt.Taskbar's
iconImage, which was never set, so gradle-run sessions showed the
generic Java coffee-cup square.

Load the PNG via ImageIO (preserves alpha), then set Taskbar.iconImage
before the application{} block starts. Guarded by isTaskbarSupported +
Feature.ICON_IMAGE so the call is a no-op on platforms without it.

Applies on all OSes that support the Taskbar API — macOS gets the dock
icon, GNOME/KDE get the task-switcher thumbnail, Windows gets the
taskbar icon.

https://claude.ai/code/session_01NufduPfZvYQVYwLkbCjCUo
This commit is contained in:
Claude
2026-04-24 13:47:30 +00:00
parent 6edc432377
commit 9769bec472
@@ -196,6 +196,26 @@ fun main() {
System.setProperty("apple.awt.application.appearance", "system")
}
// Set the dock / taskbar icon image before any window is shown.
//
// On macOS the Cmd+Tab app switcher and the dock use the Taskbar API's
// iconImage, NOT the Window(icon=) composable parameter (which only sets
// the in-title-bar proxy icon). Without this, a JVM launched via gradle
// shows the generic Java coffee-cup square in Cmd+Tab. ImageIO preserves
// the PNG alpha channel so the dock renders the logo with transparency.
try {
val bytes = Unit::class.java.getResourceAsStream("/icon.png")!!.readBytes()
val awtImage = javax.imageio.ImageIO.read(java.io.ByteArrayInputStream(bytes))
if (awtImage != null && java.awt.Taskbar.isTaskbarSupported()) {
val taskbar = java.awt.Taskbar.getTaskbar()
if (taskbar.isSupported(java.awt.Taskbar.Feature.ICON_IMAGE)) {
taskbar.iconImage = awtImage
}
}
} catch (e: Exception) {
Log.w("Main") { "Failed to set dock icon: ${e.message}" }
}
Log.minLevel = LogLevel.DEBUG
DesktopImageLoaderSetup.setup()
Runtime.getRuntime().addShutdownHook(