macOS
This guide describes how to adapt your Java Swing application to macOS.
Global settings
Screen menu bar
While Windows or Linux applications have there menu bars within the main window, macOS applications show the menu bar on top of the screen.
If your main window is a JFrame
and has a menu bar (set with
JFrame.setJMenuBar(JMenuBar)
), then it looks like this on macOS:
To move the menu bar out of the main window to the top of the screen, add following to the main method of your application (before any UI code):
System.setProperty( "apple.laf.useScreenMenuBar", "true" );
Then it looks like this:
To integrate you application with the application menu in the screen menu bar, see application menu integration.
Application name
The application name shown in the screen menu bar (between the apple and "File") is the name of the main class of your application. This maybe is not equal to your application name. You can fix it with:
System.setProperty( "apple.awt.application.name", "FlatLaf Demo" );
Appearance of window title bars
macOS supports light and dark appearances.
If you enable dark appearance in macOS "System Preferences" and use a dark FlatLaf theme, then the window title bar of the application still has a light color:
To fix this use following:
System.setProperty( "apple.awt.application.appearance", "system" );
Then the window title bars automatically change color when system appearance changes:
Notes:
- available since Java 14; backported to Java 13.0.4, 11.0.8 and 8u322
- must be set on main thread and before AWT/Swing is initialized; setting it on AWT thread does not work
Window settings
Transparent title bar
A nice feature that allows you to give your application a more modern (and flat) look is transparent title bar. (available since Java 12; backported to Java 11.0.8 and 8u292; see JDK-8211301)
To enable transparent title bar for a window, set following client property on the root pane of the window:
if( SystemInfo.isMacFullWindowContentSupported ) frame.getRootPane().putClientProperty( "apple.awt.transparentTitleBar", true );
Dark appearance (with apple.awt.application.appearance=system
):
Unfortunately this behaves different for older Java versions:
- for Java 8 - 15, the background color of the AWT/String window is used as background for the window title bar, but system color is used for the title text, which may result in unreadable title (e.g. when using dark system appearance and light FlatLaf theme; white text and light gray background)
- for Java 16 and later, the macOS system colors are always used for window title bar background and title text
Full window content
Full window content is another nice feature that allows you to extend the content into the window title bar. This means that the root pane of the Swing window is extended into the macOS window title bar. macOS still shows the red/orange/green buttons and the window title. It is possible to drag the window by click-and-drag at the top area of the window. (available since Java 12; backported to Java 11.0.8 and 8u292; see JDK-8211301)
To enable full window content for a window, set following client properties on the root pane of the window:
if( SystemInfo.isMacFullWindowContentSupported ) { frame.getRootPane().putClientProperty( "apple.awt.fullWindowContent", true ); frame.getRootPane().putClientProperty( "apple.awt.transparentTitleBar", true ); }
Note that the red/orange/green buttons and the window title overlap the Swing components (e.g. the toolbar in above screenshots). You have to modify your application and add some empty space to avoid the overlapping. In case of a toolbar, adding a 70px wide horizontal strut works very well:
if( SystemInfo.isMacFullWindowContentSupported ) toolBar.add( Box.createHorizontalStrut( 70 ), 0 );
Note that the window title is painted using the system appearance. So if you use light system appearance but a dark FlatLaf theme, it looks like this:
Dark system appearance and light FlatLaf theme:
Hide window title
To avoid above problem or to avoid that the window title operlaps Swing components, you can hide the window title. (available since Java 17; see JDK-8265005)
frame.getRootPane().putClientProperty( "apple.awt.windowTitleVisible", false );
For older Java versions use:
frame.setTitle( null );
Full screen (pre Java 11)
When running your application on Java 8 - 10, the green button in the window title bar maximizes (zooms) the window. When you place the mouse over the green button, following menu is shown:
If you like to support full screen mode, as many native macOS applications do, set following client property on the root pane of the window:
frame.getRootPane().putClientProperty( "apple.awt.fullscreenable", true );
Then clicking the green button enters full screen mode. You can still maximize
the window by holding down the Alt
key while pressing the green button.
Code Examples
Here are some full examples that you can copy to your application.
For all windows:
- enable screen menu bar
- set application name
- enable dark window title bars
public static void main( String[] args ) { // macOS (see https://www.formdev.com/flatlaf/macos/) if( SystemInfo.isMacOS ) { // enable screen menu bar // (moves menu bar from JFrame window to top of screen) System.setProperty( "apple.laf.useScreenMenuBar", "true" ); // application name used in screen menu bar // (in first menu after the "apple" menu) System.setProperty( "apple.awt.application.name", "My Application" ); // appearance of window title bars // possible values: // - "system": use current macOS appearance (light or dark) // - "NSAppearanceNameAqua": use light appearance // - "NSAppearanceNameDarkAqua": use dark appearance // (must be set on main thread and before AWT/Swing is initialized; // setting it on AWT thread does not work) System.setProperty( "apple.awt.application.appearance", "system" ); } SwingUtilities.invokeLater( () -> { FlatLightLaf.setup(); // create and show UI } ); }
For main frame:
- hide Exit and About menu items from menu because they are in application menu
- in menu items, replace HTML text, because this is not supported in macOS screen menu
- expand window content into window title bar and make title bar transparent
- hide window title
- enable full screen
// macOS (see https://www.formdev.com/flatlaf/macos/) if( SystemInfo.isMacOS ) { // hide menu items that are in macOS application menu aboutMenuItem.setVisible( false ); preferencesMenuItem.setVisible( false ); exitMenuItem.setVisible( false ); // do not use HTML text in menu items because this is not supported in macOS screen menu htmlMenuItem.setText( "some text" ); if( SystemInfo.isMacFullWindowContentSupported ) { // expand window content into window title bar and make title bar transparent frame.getRootPane().putClientProperty( "apple.awt.fullWindowContent", true ); frame.getRootPane().putClientProperty( "apple.awt.transparentTitleBar", true ); // hide window title if( SystemInfo.isJava_17_orLater ) frame.getRootPane().putClientProperty( "apple.awt.windowTitleVisible", false ); else frame.setTitle( null ); // add gap to left side of toolbar toolBar.add( Box.createHorizontalStrut( 70 ), 0 ); } // enable full screen mode for this window (for Java 8 - 10; not necessary for Java 11+) if( !SystemInfo.isJava_11_orLater ) frame.getRootPane().putClientProperty( "apple.awt.fullscreenable", true ); }
Application menu integration
If the screen menu bar is enabled, macOS adds an application menu to the menu bar.
By default, About AppName shows a default about dialog, Preferences is hidden and Quit AppName always quits the application.
Use class java.awt.Desktop
to integrate you application with those three menu
items (requires Java 9 or later):
Desktop desktop = Desktop.getDesktop(); if( desktop.isSupported( Desktop.Action.APP_ABOUT ) ) { desktop.setAboutHandler( e -> { // show about dialog } ); } if( desktop.isSupported( Desktop.Action.APP_PREFERENCES ) ) { desktop.setPreferencesHandler( e -> { // show preferences dialog } ); } if( desktop.isSupported( Desktop.Action.APP_QUIT_HANDLER ) ) { desktop.setQuitHandler( (e, response) -> { boolean canQuit = // TODO if( canQuit ) response.performQuit(); else response.cancelQuit(); } ); }
If your application uses Java 8, then use class
com.formdev.flatlaf.extras.FlatDesktop
from flatlaf-extras library:
FlatDesktop.setAboutHandler( () -> { // show about dialog } ); FlatDesktop.setPreferencesHandler( () -> { // show preferences dialog } ); FlatDesktop.setQuitHandler( response -> { boolean canQuit = // TODO if( canQuit ) response.performQuit(); else response.cancelQuit(); } );
Don't forget to hide the About, Preferences and Exit menu items from the menu.
if( SystemInfo.isMacOS ) { // hide menu items that are in macOS application menu aboutMenuItem.setVisible( false ); preferencesMenuItem.setVisible( false ); exitMenuItem.setVisible( false ); }