Detecting a Macintosh Client
Some of the suggestions made in this Technical Note suggest that you make conditional API calls or placement of UI components. The most common (and intuitive) method of finding out the operating system you are running on is checking the
This property is set automatically by the JVM on all Mac OS X systems. The test is simple: if the returned
Additionally, many of the forthcoming suggestions are specific to Apple's Aqua interface. In other words, there are things you are enabling/disabling that you may not want to in the Java (Metal) or Motif look and feel's for Swing. The best way to verify that Aqua is currently the active look and feel is to call
and compare the result to
Combined with the
The quickest and most obvious means of making a Java application as Mac-like as possible is to build your application using Cocoa-Java. This will allow you to employ Interface Builder for quick WYSIWYG design of your UI, complete with recommended component spacing and sizing. Cocoa-Java controls also offer things that Swing or AWT do not, such as quick movie embedding and true "floating" toolbar windows.
Of course, employing Cocoa-Java will remove the portability aspect of your Java application. While this Technical Note is more focused on pure-Java applications, Cocoa-Java is worth mentioning because, if you are choosing to use it for your user interface, it is important to NOT mix Cocoa- and Carbon-based components in your application. Within the scope of Java, this includes:
The main reason for this is that Carbon and Cocoa
use different run-loops, which will conflict with one another if
mixed in the same application. The QuickTime for Java bullet may
seem discouraging at first, but most of the simple QuickTime
functionality required by Macintosh applications (opening and playing
various media files) can be obtained through the
With that said, the remainder of this Technical Note will deal with Swing- and AWT-based "Pure Java" applications.
Pure Java Compatibility Tips
The first half of this Technical Note covers simple changes or decisions you can make in your pure Java application which do not involve Mac-specific APIs or properties, but rather things to keep in mind in order to make your single codebase support Mac OS X just as well as other platforms.
Mac OS X, Swing, and Aqua
The Aqua user interface for Mac OS X is much different from those of other platforms, including Java itself. The presence of an Aqua pluggable look and feel for Swing is obviously a huge step in making your Swing applications more Mac-like. It's also a free one: short of explicit changes in your own code, Mac OS X employs the Aqua look and feel for a Swing application at launch time by default.
The existence of Aqua as a look and feel leads to our first simple guideline: use Swing as the UI for your Java apps! There are many fundamental benefits that Swing provides over AWT as-is: access to Aqua removes nearly the only advantage that AWT could hold. Furthermore, mixing of lightweight and heavyweight components can have undesirable performance and drawing effects in your application.
In addition to modeling your application using
Swing, it is best to avoid explicitly setting the look and feel in
your Java code. If you need to change the look and feel of your
application on different platforms, it would be both more elegant and
simpler to override the
Despite automatic adoption of the Aqua appearance, there are still areas and disciplines that fall in the hands of the developer to provide a full Macintosh experience. Many of the guidelines for this Technical Note were modeled after the Aqua Human Interface Guidelines (PDF) from the Apple Developer web site. Examples of some small but important details covered in the guidelines include:
It is strongly suggested that you review this document for particulars regarding user interface design on the Macintosh. We did!
JDesktopPanes and Multiple Document Interface
Nearly all Macintosh applications are made up of numerous, free-floating, independent windows. While these windows remain within the context of the application, they are not contained within a parent "backing window" that serves as the bounds of the application on the screen. This is something that differentiates the Macintosh from other platforms, and should be considered when designing an application with more than one window.
For this reason, we would recommend against the use of the
If you are bringing your MDI-based application to the Macintosh from another platform, you may find that it is impossible to provide the user experience you've built without a layered-pane structure. In this case, it may be better to keep your UI as-is. The decision will be up to you as a developer.
As a side note, you can implement toolbar- and palette-style controls using Cocoa-Java. However, use of Cocoa-Java would eliminate portability, and prevent you from using Swing or AWT components.
We also understand that
Swing Menus and Menu Items
Another difficulty in cross-platform Java UI development is that shortcuts and appearances for menu items tend to vary between platforms. Unfortunately, many Java programmers write their applications only with the current development platform in mind, and explicitly specify the appropriate modifier or trigger in their code. This provides difficulty in porting your application from platform to platform, as well as risking misinterpretation of what the platform's appropriate triggers are.
Fortunately, there are much more elegant solutions to creating these actions on a given platform, and furthermore, they're portable!
Menu Shortcuts. Menu shortcuts are often
set by a developer with an explicit
When calling this method, the current platform's Toolkit implementation will return the proper mask for you. The work of checking for the current platform and then guessing which key is correct is done for you with this single call! Listing 1 demonstrates this below.
Just about every common action on the Macintosh has a keyboard equivalent that uses the command key as at least one of the modifiers, if not the sole modifier. Unfortunately, other platforms are not as consistent, and you may have some keyboard shortcuts that use the "Alt" key, for example. Since the above call only returns one generalized mask, there may still be a need to do conditional setting of key shortcuts based on the host platform. The fact that most Mac keyboard equivalents use Command will make your life a bit easier if you're bringing your application over to Windows and are worried about representing actions correctly on this platform. For a solid list of the most common and reserved shortcuts, check out the keyboard equivalents section of the Aqua HI Guidelines.
Menu Mnemonics. Unlike other
platforms, Mac OS X (Aqua) does not provide menu mnemonics, or
single-key shortcuts to menus (using the Alt key) and menu items (once the parent menu is opened). Mnemonics usually appear as a single
underlined letter in the menu[item]'s name. Macintosh applications
have never used menu mnemonics, and we suggest applying mnemonics in
a platform-sensitive manner in your code if possible, such as a
Menu Item Icons. Like mnemonics, menu item icons are also available via Swing - and functional on Mac OS X - but not a standard part of Aqua's HI Guidelines. In the interest of making your Macintosh Java application look like a Carbon or Cocoa app, you may also want to apply these icons conditionally based on platform.
For more on checking which platform your application is running on, please see the Detecting a Macintosh Client section.
Since most platforms support contextual menus in one
form or another there should be no problem in putting contextual menus in your Java application (Java refers to them as
These are two very different cases, which could result in fragmented and conditional code like the menu example above. One thing is common, however: a mouse click. To ensure that your program is interpreting the proper contextual menu trigger, regardless of platform, we again turn to the AWT to do the interpreting for us by using the following instance method:
Note that the above example checks
Placing and Painting Components
Swing UIs are constructed by combining often-complicated nestings of containers and components. When working on a single platform, a developer can easily lose sight of what his or her UI design may look like on other platforms. As the term suggests, different look and feel's look and feel differently. Font sizes, button sizes and shapes, background and foreground colors, etc. can all vary differently between different look and feel's on different platforms. It is this fact that makes it extremely important to use abstracted and general methods to place, size, and paint your components.
Layout Managers. Using layout managers may be a no-brainer for many developers, but many programmers do attempt to fine-tune their applications by setting explicit X and Y coordinates for their controls. If, at any point, such an application is run under a new look and feel, and/or on another platform, this can result in a disasterous UI, riddled with components painting on top of each other and running off the edge of a container, among other things. It is generally unsafe to assume that placing buttons and controls at explicit coordinates is portable, as different sizes for controls across look and feel's can cause your UI to suddenly look nothing like what you intended. The use of AWT layout managers solves this problem by making use of abstracted location constants (relative grid coordinates in
Component Sizes. Setting explicit component sizes can also be a dangerous habit. Each look and feel is likely to have different font styles and sizes. These font sizes will most certainly affect the required size of the component containing the text, and moving explicitly-sized components to a new look and feel with a larger font size can cause big problems. The safest means of keeping your UI components a proper, minimal size in a portable manner is to simply call
Component Colors. Since a given look and feel tends to have universal coloring and styling for most, if not all of its controls, developers may be tempted to create custom components which match the look and feel of standard UI classes. This is perfectly legal, but the careless developer may be setting an explicit color which they think matches well with the current look and feel. Changing the look and feel may result in a very odd-looking button somewhere in the container. The best way of ensuring that your custom control matches well with other standard components is to query the
This will return the color appropriate for the current look and feel. The other advantage of using these standard methods is that they will also provide more specialized backgrounds and icons that are not easily reconstructed (such as the striped background used for Aqua containers and windows, which is what the above call will return).
Windows With Scrollbars (Using JScrollPanes)
One specific example of UI design recommended by the Aqua HI Guidelines involves windows that use scrollbars to navigate their contents. By default, a Swing
You can of course choose to do this conditionally based on
the host platform, as the
File Dialogs in Aqua
In the interest of making your application look as "native" as possible, it is typically recommended that developers use the AWT
Handling .pkg and .app files. Handling Mac OS X application bundles and installer packages inside your Java application is an additional concern. Since a .app or a .pkg file is technically a directory, Java applications using
Possible values are
Possible values for these properties are
There are a few known issues that currently exist with using these properties:
In other words, you may currently use these properties to make only .app files, or both .app and .pkg files, navigable.
The next few sections discuss changes or design decisions you can make to your Java application with the specific goal of making it as close as possible to an Aqua-compliant Mac OS X application. Some of these changes will have no effect on other platforms, while others may require conditional packaging or execution of code in your application for multiple platforms.
Using a Macintosh Menubar
One difference between the Java UI model and that of the Macintosh is that in Swing, the application's menubar is applied on a per-frame (window) basis. Similar to the Windows model, the menubar appears directly under the frame's titlebar. This is different from the Macintosh model, where the application has a single "screen" menubar which controls all of the app's windows. To quickly solve this problem, a runtime property has been added:
This property can have a value of
It is important to note that a
If you find the need to attach menus to a dialog window, you may want to reconsider your UI - a dialog should be informational or present the user with a simple decision. A window with enough functionality to necessitate a menubar may be better off existing as a
A quick run-through on enabling the screen menu bar is also available from Q&A 1003.
Unfortunately, this only solves part of the problem (visual placement); the fundamental issue of "one menubar per window" still exists. In other words, the menu will appear at the top of the screen, but only when the specific window it was assigned to is in focus. If your application has multiple windows, and a window other than the one holding the menubar is focused, the menubar will vanish! The Aqua HI Guidelines state that the menubar should always be visible in an application; even an insignificant window such as an alert dialog should still show the menubar (though you may want to disable the menus).
There are a few ways around this problem, but the most popular involves creating and using a menu factory which will generate an identical menubar for each free frame in your application. This way, when focus changes to each frame, it will still have a menubar attached at the top of the screen.
The Window Menu
One of the directives in the Aqua HI Guidelines is
that all Mac OS X applications should provide a Window menu to
keep track of all currently open windows. Implementing such a
feature in Java Swing is not impossible, but it requires, among other
things, making use of the previous two suggestions in this Technical Note
(Macintosh menubar, free-floating frames). While you can implement a
Window menu without these two prerequisites, they all work
hand-in-hand in allowing your Java app to be as Mac-like as possible.
Similar to the "global menubar" issue, Swing's current architecture
makes it difficult to have multiple menus and menu items that are constantly updated and
synched with the current state of the application. Through
the use of
A Window menu should contain a list of currently active (visible) windows, with the corresponding menu item checked if a given window is currently selected to the foreground. Likewise, selection of a given Window menu item should result in the corresponding window being brought to the front. New windows should be added to the menu, while closed windows should be removed. The ordering of the menu items is typically the order in which the windows appeared (See the Aqua HI Guidelines for a full explanation).
The Application Menu
Any Java application that uses AWT/Swing, or is
packaged in a double-clickable .app file, will automatically be
launched with an Application Menu similar to native applications on
Mac OS X. This application menu, by default, contains the full name
of the main class as the title. This name can be changed using the
The next step to customizing your application menu
is to actually have your own handling code called when an item in the application menu is selected. Apple has provided a means for this through special Java interfaces in the
To handle a given application menu item:
To see an example of these implementations, simply open a new Java Swing Application in Project Builder. There is also a Technical Q&A demonstrating proper use of the
Accommodating the Application Menu
We have already discussed the addition of the application menu to Java applications on Mac OS X, and how to take advantages of the menu items within it. If your application is to be deployed on other platforms, where preferences/quit/about access will need to be placed elsewhere on the menubar (in a "File" or "Edit" menu, for example), you may want to make this placement conditionally. While it would not be harmful to have two different "Preferences" menu items, or an "Exit" menu item as well as the MRJ "Quit" item, for example, it may be less confusing to Mac users if the items familiar to the application menu were there and nowhere else. This is a minor change that can make a large difference in the look and feel of your Mac OS X Java application.
Additional MRJ Handlers
In addition to the interfaces provided for handling of the application menu, the current Java release on Mac OS X provides two functional and supported MRJ Handlers:
These handler interfaces are intended to enhance a Java application's behavior in the Mac OS X Finder, and are utilized in the same manner as the application menu interfaces described above. Registering the file types your application can open from the Finder using MRJOpenDocumentHandler is done with additional keys at the top level of the Info.plist file of an application bundle, in the same manner as Cocoa or Carbon applications. Please see the CFBundleDocumentTypes section of the Bundle Keys documentation for more.
Launching Java Applications
Perhaps the most immediate and obvious aspect of the Macintosh experience is that an application should be launched via a double-clickable icon, or package. In the interest of being a "good Mac OS X citizen", a Java application should not require use of the command line to be launched. There are a few ways to make your Java application double-clickable for the end user:
The .app approach, of course, is the most Mac-like means of packaging your Java application.
Setting a Dock Icon
Any application that launches under Mac OS X has a corresponding icon in the Finder Dock. This goes for graphical Java applications on Mac OS X, as well as non-graphical apps which are packaged in a .app bundle. A default Java icon is provided for placement in the Dock, but a developer can specify a custom icon for his/her Java application using one of two methods:
This means that applications deployed using double-clickable jar files cannot customize their Dock icon, which is why it is recommended that the other deployment mechanisms listed above be considered. Unfortunately, because of the way Java Web Start launches its applications, it is currently impossible to do this via Java Web Start as well.
For more on the
This Technical Note has glanced upon the areas in which a developer can bring the user experience advantages of Mac OS X to Java applications running on the platform. From runtime properties, to compatibility best-practices, to Mac-specific tuning and tweaks, we hope developers will be able to take advantage of what's available to make Java applications on Mac OS X look as "at-home" as possible.
Contact ADC | ADC Site Map | ADC Advanced Search
|For information about Apple Products, please visit Apple.com.|
Contact Apple | Privacy Notice
Copyright © 2002 Apple Computer, Inc. All rights reserved.