Skip to content

macOS Rework: App Icon - #32361

Draft
iccir wants to merge 22 commits into
matplotlib:mainfrom
iccir:macos-pr-appicon
Draft

iccir wants to merge 22 commits into
matplotlib:mainfrom
iccir:macos-pr-appicon

Conversation

@iccir

@iccir iccir commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

PR summary

Important

This PR depends on #32161 and will appear larger than it really is until #32161 is merged. To view the actual changes in this PR, compare macos-staging → macos-pr-appicon.

This PR matches the app icon of the macOS backend to the shape and style of other system icons. To help with visual accessibility, the user can choose either a light icon or a dark icon.

Due to limitations in Apple's API, we cannot match "clear" or "tinted" app icons, nor can we automatically match the user's selected icon appearance preference.

Closes #31895

Overview

Starting in macOS 26, developers are suppose to use Icon Composer to create app icons. When an app is built, Xcode uses the Icon Composer document to generate and bundle rasterized images. At runtime, these images are layered and tinted to match the user's icon appearance preference.

This approach is not an option for us:

  • We do not want to add a dependency on Icon Composer and Xcode.
  • The macOS backend is a loadable Mach-O binary, not an app bundle. We have no "Info.plist" file and cannot specify an icon.
  • Even if we could, using the Icon Composer and Xcode approach would add several megabytes to our distribution size.

Apple only provides one other option: use -[NSApplication setApplicationIconImage:] and provide an image at runtime.

What's In-Scope and Out-of-Scope

I believe that:

  • We should match the overall shape of other icons in the system.
  • We should try to match the user's icon appearance preference for visual accessibility reasons. Some users are sensitive to bright colors and may choose to use dark icons to prevent sudden flashes of light when switching apps.

However:

  • There is no API to determine the user's icon appearance preference.
  • There is no API to create the "clear" or "tinted" appearances. These are not static images – they heavily use the GPU to mimic the effect of a curved glass bead bending light.

Thus, the "clear" and "tinted" styles are impossible to match. We also cannot query the system to see if the user prefers "light" or "dark".

To compensate, I've added a new macos.app_icon rcparam. This defaults to light but can be set to dark if a user is sensitive to bright content. If Apple ever adds the relevant API, we could someday have a system option.

Reverse-engineering the Icon Metrics

Apple provides no documentation on the exact metrics used by their icons. I had to create AppIconReverser to figure these out:

macOS 11-15 macOS 26 - 27
Squircle Length 206 208
Squircle Radius 45.5 54.5
Shadow Opacity 30 25
Shadow Offset 3 3
Shadow Blur 3 4.8

This app also exports the dark background which macOS 26 and 27 programmatically generate. While not specifically needed for accessibility, we should match the other icons as much as possible.

Variants

The permutation of shape and appearance results in five icon variants:

Screenshot of all five icon variants.

If we stored each variant as a composited PNG, they would be 35-50KB each (175-250KB total). Instead, we build them at runtime from separate files:

Filename Size Description
macos_appicon_light.png 30KB Light logo
macos_appicon_dark.png 30KB Dark logo
macos_appicon_bgdark26.png 4KB macOS 26 dark background
macos_appicon_bgdark26.png 4KB macOS 27 dark background
macos_appicon_shadow11.png 2KB macOS 11-15 shadow
macos_appicon_shadow26.png 3KB macOS 26-27 shadow
macos_appicon_mask11.png 1KB macOS 11-15 mask
macos_appicon_mask26.png 1KB macOS 26-27 mask

Together, these total 75KB. There is very little performance penalty with compositing them together at launch. If Apple changes the icon size or dark background style in a future version of macOS, we only suffer a small size penalty.

Note

My hope is that the macOS icon design will stabilize with macOS 27. We can always switch to a dark gradient if it becomes a burden - it won't perfectly match, but it will still help with visual accessibility.

Making the Icon Pieces

Except for *_bgdark*.png, the above files are generated via two tools:

python tools/make_macos_svgs.py /tmp/macos_svgs
python tools/make_icons.py \
    --macos \
    --source-dir=/tmp/macos_svgs

Originally, I intended for the logo PNG files to be generated from a source SVG with tweakable colors via CSS variables and color-mix(). Unfortunately, Inkscape and other SVG renderers provide very little support for modern SVG features. Only a real web browser engine like headless Chromium can pull this off. I didn't want to add another dependency, so I opted to have the Python script generate Inkscape-compatible SVG files.

Compositing the Icon

  • _init_macos() gathers all paths in "mpl-data" which match macos_*.png. It sends these along with a use_dark_appicon boolean to the Objective-C layer.
  • This are passed into our MPLAppDelegate (if we decide to create one).
  • After app launch, we call -[MPLAppDelegate _buildAppIcon] to build the actual icon. The actual compositing process is as follows:
    • Determine the exact images to use based on macOS version and color variant.
    • Call CGContextDrawImage() with the shadow.
    • Call CGContextClipToMask() with the mask.
    • If dark, either call CGContextDrawImage() with the background or draw a dark gradient.
    • If light, the background is baked into the content image to save disk space.
    • Call CGContextDrawImage() with the content image.
    • Send the result to -[NSApplication setApplicationIconImage:].

AI Disclosure

  • I use AI for web search due to search engines becoming less reliable.
  • I used AI to help generate portions of "make_macos_svgs.py" and review the final result.
  • All remaining work is my own.

PR quality check

  • Use an expressive title, e.g. "Fix title font property precedence"
  • [N/A] New and changed code is tested (Tested manually)
  • [N/A] Plotting related features are demonstrated in an example
  • [N/A] New features and API changes have release notes
  • [N/A] Documentation complies with general and docstring guidelines

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ENH]: macOS backend should match system app icons

2 participants