AWT Desktop Properties (Java SE 21 & JDK 21)

# AWT Desktop Properties

The following refers to standard AWT desktop properties that may be obtained via the `Toolkit.getDesktopProperty` method.

Each desktop property is named by a unique string, which is the "name" of that property.

Desktop properties supported by the AWT but not documented elsewhere - typically because there is no suitable method or class - are documented here.

Desktop properties documented elsewhere are those which are tightly coupled with a method or class which documents them.

Since desktop properties abstract an underlying platform setting, they may not be available in environments that do not support them. In the event that a desktop property is unavailable for any reason, the implementation will return `null`.

The following table summarizes the desktop properties documented here, and their value types.
Property Name | Value Type | Summary Description
--- | --- | ---
awt.font.desktophints | `java.util.Map` | Font smoothing (text antialiasing) settings.
sun.awt.enableExtraMouseButtons | `java.lang.Boolean` | Controls if mouse events from extra buttons are to be generated or not

## Desktop Font Rendering Hints

Desktop Property: "awt.font.desktophints"

Modern desktops support various forms of text antialiasing (font smoothing).

These are applied by platform-specific heavyweight components. However an application may want to render text using the same text antialiasing on a drawing surface or lightweight (non-platform) component using `Graphics2D` methods. This is particularly important when creating `Swing components` which are required to appear consistent with native desktop components or other Swing components.

### Basic Usage

The standard desktop property named "awt.font.desktophints" can be used to obtain the rendering hints that best match the desktop settings. The return value is a `Map` of `RenderingHints` which can be directly applied to a `Graphics2D`.

It is a `Map` as more than one hint may be needed. If non-null this can be directly applied to the `Graphics2D`.

    Toolkit tk = Toolkit.getDefaultToolkit();
    Map map = (Map)(tk.getDesktopProperty("awt.font.desktophints"));
    if (map != null) {
        graphics2D.addRenderingHints(map);
    }

### Advanced Usage Tips

#### Listening for changes

An application can listen for changes in the property using a `PropertyChangeListener`:

    tk.addPropertyChangeListener("awt.font.desktophints", pcl);

Listening for changes is recommended as users can, on rare occasions, reconfigure a desktop environment whilst applications are running in a way that may affect the selection of these hints, and furthermore many desktop environments support dynamic reconfiguration of these running applications to conform to the new settings.

There is no direct way to discover if dynamic reconfiguration is expected of running applications but the default assumption should be that it is expected, since most modern desktop environments do provide this capability.

#### Text Measurement

Text always needs to be measured using the same `FontRenderContext` as used for rendering. The text anti-aliasing hint is a component of the `FontRenderContext`. A `FontMetrics` obtained from the `Graphics` object on which the hint has been set will measure text appropriately. This is not a unique requirement for clients that specify this hint directly, since the value of the `FontRenderContext` should never be assumed, so is discussed here principally as a reminder.

#### Saving and restoring Graphics State

Sometimes an application may need to apply these hints on a shared Graphics only temporarily, restoring the previous values after they have been applied to text rendering operations. The following sample code shows one way to do this.

    /**
      * Get rendering hints from a Graphics instance.
      * "hintsToSave" is a Map of RenderingHint key-values.
      * For each hint key present in that map, the value of that
      * hint is obtained from the Graphics and stored as the value
      * for the key in savedHints.
      */
    RenderingHints getRenderingHints(Graphics2D g2d,
                                      RenderingHints hintsToSave,
                                      RenderingHints savedHints) {
         if (savedHints == null) {
             savedHints = new RenderingHints(null);
         } else {
             savedHints.clear();
         }
         if (hintsToSave.size() == 0) {
             return savedHints;
         }
         /* RenderingHints.keySet() returns Set<Object> */
         for (Object o : hintsToSave.keySet()) {
             RenderingHints.Key key = (RenderingHints.Key)o;
             Object value = g2d.getRenderingHint(key);
             savedHints.put(key, value);
         }
         return savedHints;
    }

    Toolkit tk = Toolkit.getDefaultToolkit();
    Map map = (Map)(tk.getDesktopProperty("awt.font.desktophints"));
    Map oldHints;
    if (map != null) {
         oldHints = getRenderingHints(graphic2D, map, null);
         graphics2D.addRenderingHints(map);
         ..
         graphics2D.addRenderingHints(oldHints);
    }

### Details

- The return value will always be null or a `Map`
- If the return value is null, then no desktop properties are available, and dynamic updates will not be available. This is a typical behaviour if the JDK does not recognise the desktop environment, or it is one which has no such settings. The Headless toolkit is one such example. Therefore it is important to test against null before using the map.
- If non-null the value will be a `Map` of `RenderingHints` such that every key is an instance of `RenderingHints.Key` and the value is a legal value for that key.
- The map may contain the default value for a hint. This is needed in the event there is a previously a non-default value for the hint set on the `Graphics2D`. If the map did not contain the default value, then `addRenderingHints(Map)` would leave the previous hint which may not correspond to the desktop setting.

  An application can use `setRenderingHints(Map)` to reinitialise all hints, but this would affect unrelated hints too.

- A multi-screen desktop may support per-screen device settings in which case the returned value is for the default screen of the desktop. An application may want to use the settings for the screen on which they will be applied. The per-screen device hints may be obtained by per-device property names which are constructed as the String concatenation

      "awt.font.desktophints" + "." + GraphicsDevice.getIDstring();

  An application can also listen for changes on these properties.

  However this is an extremely unlikely configuration, so to help ease of development, if only a single, desktop-wide setting is supported, then querying each of these per-device settings will return null. So to determine if there are per-device settings it is sufficient to determine that there is a non-null return for any screen device using the per-device property name.

## Mouse Functionality

Desktop Property: "sun.awt.enableExtraMouseButtons"

This property determines if events from extra mouse buttons (if they are exist and are enabled by the underlying operating system) are allowed to be processed and posted into `EventQueue`.
The value could be changed by passing "sun.awt.enableExtraMouseButtons" property value into java before application starts. This could be done with the following command:

    java -Dsun.awt.enableExtraMouseButtons=false Application

Once set on application startup, it is impossible to change this value after.
Current value could also be queried using getDesktopProperty("sun.awt.enableExtraMouseButtons") method.
If the property is set to `true` then

- it is still legal to create `MouseEvent` objects with standard buttons and, if the mouse has more then three buttons, it is also legal to use buttons from the range started from 0 up to `getNumberOfButtons()`.
- it is legal to use standard button masks when using `Robot.mousePress()` and `Robot.mouseRelease()` methods and, if the mouse has more then three buttons, it is also legal to use masks for existing extended mouse buttons. That way, if there are more then three buttons on the mouse then it is allowed to use button masks corresponding to the buttons in the range from 1 up to `getNumberOfButtons()`

If the property is set to `false` then

- it is legal to create `MouseEvent` objects with standard buttons only: `NOBUTTON`, `BUTTON1`, `BUTTON2` and `BUTTON3`
- it is legal to use standard button masks only: `InputEvent.BUTTON1_DOWN_MASK`, `InputEvent.BUTTON2_DOWN_MASK`, `InputEvent.BUTTON3_DOWN_MASK`

This property should be used when there is no need in listening mouse events fired as a result of activity with extra mouse button. By default this property is set to `true`.