eclipse.platform.swt icon indicating copy to clipboard operation
eclipse.platform.swt copied to clipboard

[macOS] Decorations#setImage() overwrites Dock icon specified in App Bundle

Open sratz opened this issue 1 month ago • 10 comments

Describe the bug

Currently, there are three possible sources for the Dock icon on macOS in the order of precedence:

  1. An explicitly set icon via -Xdock:icon=/path/to/icon.icns which calls NSApp setApplicationIconImage

  2. An implicitly set icon via org.eclipse.swt.widgets.Decorations.setImage(Image) org.eclipse.swt.widgets.Decorations.setImages(Image[]) which in passed down to the Dock also via NSApp setApplicationIconImage

  3. An implicitly set icon in a Bundled.app distrubution via CFBundleIconName / CFBundleIconFile in the Info.plist file

1 and 2 use legacy API NSApp setApplicationIconImage which only supports a single fixed NSImage, i.e. there is no support for dark/light mode and or modern look & feel such as Liquid Glass.

Only 3 (app bundle) supports dynamic icons.

The problem is that 2) currently overwrites whatever 3) has set. On top of that, the Decorations are typically cross-platform, so in fact this will prevents using a macOS-specific icon at all.

We want to prefer 3) over 2), i.e. only pass down the decorations whenever we are not an app bundle with a declared image.

Similar coding also exists in the JVM, where the dock icon is only set if we are not in an app bundle that specifies an icon:

https://github.com/openjdk/jdk21u/blob/8c322f5953ae161d793213f92d13a1f53d995883/src/java.desktop/macosx/native/libosxapp/NSApplicationAWT.m#L280-L290

To Reproduce

Build an RCP product as a macOS Product.App, which defines a macOS-specific icon in the .product configuration and also launches a branded RCP product.

When the product launches, it shortly shows the icon defined in the Product.app/Info.plist file.

As soon as SWT initializes it overwrites the icon with whatever platform-agnostic icon is set in the product branding.

Expected behavior

The icon specified in the Product.App should be shown in the Dock.

Screenshots

During launcher:

Image

After SWT initialization:

Image

Environment:

  1. Select the platform(s) on which the behavior is seen:
    • [ ] All OS
    • [ ] Windows
    • [ ] Linux
    • [X] macOS

Workaround (or) Additional context

Specifying -Xdock:icon=/path/to/static/image.icns prevents SWT from changing the Dock image, but this is legacy API and does not support modern / dynamic icon features

sratz avatar Oct 14 '25 15:10 sratz

Our RCP app (and Eclipse itself) seems to need option 1 (-Xdock:icon=/path/to/icon.icns) more than it does 3.

We have both, and removing option 1 leads to the wrong icon but removing option 3 doesn't seem to make any difference.

Phillipus avatar Oct 14 '25 16:10 Phillipus

Our RCP app (and Eclipse itself) seems to need option 1 (-Xdock:icon=/path/to/icon.icns) more than it does 3.

We have both, and removing option 1 leads to the wrong icon but removing option 3 doesn't seem to make any difference.

The proposed change does not touch 1). If you set -Xdock:icon=/path/to/icon.icns, it will still have priority.

The proposal is to prefer 3) over 2), i.e. prefer a bundled (Assets.car) icon over icon set via SWT Decorations.

Assets.car is the only solution that supports dynamic icons (liquid glass, dark/light, ...)

sratz avatar Oct 15 '25 09:10 sratz

How does an Assets.car file work? Is this created in Xcode and declared in the Info.plist file?

Phillipus avatar Oct 15 '25 09:10 Phillipus

How does an Assets.car file work? Is this created in Xcode and declared in the Info.plist file?

See for example here: https://www.hendrik-erz.de/post/supporting-liquid-glass-icons-in-apps-without-xcode

Basically you create an ".icon" file with "Icon Composer" on macOS. Then use use XCode or "actool" command line tool to create a the .car file that is then referenced in the info.plist file.

BeckerWdf avatar Oct 15 '25 09:10 BeckerWdf

When materializing products with P2 (PDE/Tycho), the .product configuration:

   <launcher name="Foo">
      <macosx icon="icons/AppIcon.icns"/>
   </launcher>

currently creates the following Info.plist:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<plist version="1.0">
  <dict>
    <!-- ... -->
    <key>CFBundleIconFile</key>
    <string>AppIcon.icns</string>
    <!-- ... -->
  </dict>
</plist>

This is legacy as well. To fully make use of Assets.car, you'd need an CfBundleIconName entry:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<plist version="1.0">
  <dict>
    <!-- ... -->
    <key>CFBundleIconName</key> <!-- priority over CFBundleIconFile, if supported by OS -->
    <string>AppIcon</string> <!-- name of a resource inside Resources/Assets.car -->

    <key>CFBundleIconFile</key>
    <string>AppIcon.icns</string>
    <!-- ... -->
  </dict>
</plist>

This currently cannot be auto-generated by P2's publisher, but you can fiddle around with that, e.g. with maven-antrun-plugin which adds the Resources/Assets.car file to the binary artifact and updates the Info.plist accordingly.

sratz avatar Oct 15 '25 09:10 sratz

How does an Assets.car file work? Is this created in Xcode and declared in the Info.plist file?

See for example here: https://www.hendrik-erz.de/post/supporting-liquid-glass-icons-in-apps-without-xcode

Basically you create an ".icon" file with "Icon Composer" on macOS. Then use use XCode or "actool" command line tool to create a the .car file that is then referenced in the info.plist file.

Thanks.

Note that the old icon file needs to be kept:

Don’t just throw out your existing .icns-file. There are still many out there with Macs that don’t run the newest macOS, and if you remove the .icns-file, the app will break for all of these people. For the coming years, be prepared to ship both the .icns-file and the new Liquid Glass version.

Phillipus avatar Oct 15 '25 10:10 Phillipus

This currently cannot be auto-generated by P2's publisher,

Can the publisher be enhanced in a way that for ".car" files a CFBundleIconName entry is created?

BeckerWdf avatar Oct 15 '25 10:10 BeckerWdf

When materializing products with P2 (PDE/Tycho), the .product configuration:

How can we handle compatibility with older macOS versions. That means how can we provide details in the product file so that both CFBundleIconName and CFBundleIconFile are created in the info.plist ?

BeckerWdf avatar Oct 15 '25 10:10 BeckerWdf

Can the publisher be enhanced in a way that for ".car" files a CFBundleIconName entry is created?

The icon handling is done in https://github.com/eclipse-equinox/p2/blob/cc3868542ee18f101b56a5a02916b148ad13819f/bundles/org.eclipse.equinox.p2.publisher.eclipse/src/org/eclipse/equinox/internal/p2/publisher/eclipse/BrandingIron.java This would have to be enhanced accordingly and the model of the .product configuration as well - similar to what we did when we added support for CfBundleUrlType entries for the link handlers.

How can we handle compatibility with older macOS versions. That means how can we provide details in the product file so that both CFBundleIconName and CFBundleIconFile are created in the info.plist ?

I think we should allow to configure both:

  • The legacy icon via the existing syntax in
    <launcher name="Foo">
       <macosx icon="icons/AppIcon.icns"/>
    </launcher>
    
  • Maybe add a more general syntax here, something like
    <launcher name="Foo">
       <macosx>
         <icon>iconsAppIcon.icns</icon>
         <additionalResources>resources</additionalResources> <!-- local folder whichs is copied to the Bundle under Resources during publishing -->
         <additionalPlistConfigurations>
            <!-- ... -->
         </additionalPlistConfigurations>
       </macosx>
    </launcher>
    

sratz avatar Oct 15 '25 11:10 sratz

  • Maybe add a more general syntax here, something like

That sounds reasonable to me...

BeckerWdf avatar Oct 15 '25 12:10 BeckerWdf