Desktop AWT

The quarkus-desktop-awt extension makes AWT GUI applications work in JVM mode and as GraalVM native executables: windows and the native AWT components, Java2D (including the Direct3D, GDI, XRender, Metal and OpenGL pipelines), fonts, images, printing, clipboard and drag and drop, input methods, the desktop integration (Desktop, Taskbar, SystemTray), Robot, Java Sound and accessibility.

How it works

In JVM mode, AWT needs nothing special: the extension adds the application model and its CDI integration (see Application model and CDI) and takes care of dev mode (see Dev mode).

For native executables, the extension builds on the Quarkus core extension io.quarkus:quarkus-awt (it depends on it), which supports headless Java2D, ImageIO and fonts, and adds:

  • The GUI parts of AWT: the metadata (JNI, reflection, resources, resource bundles, service providers) of the windows, the native components, the Java2D surfaces of the screen, printing, data transfer, input methods, the desktop integration, sound and accessibility, for Windows, Linux and macOS (with the Aqua look and feel of Swing, which draws the AWT components on macOS).

  • The parts of Swing that AWT itself uses (the print and page dialogs, the input method windows, and on Linux the text components): AWT applications do not need quarkus-desktop-swing.

  • The removal of the substitutions of quarkus-awt (made for headless Java2D) that break GUI applications or disable an AWT feature: three Windows ones (sun.awt.windows.WObjectPeer, sun.java2d.windows.WindowsFlags and sun.awt.windows.WToolkit, which make every window crash, disable DPI awareness, and disable AWT print jobs), the Type 1 fonts one (sun.font.Type1Font, which rejects Type 1 fonts, see Fonts and languages), and, with the Quarkus versions whose quarkus-awt supports macOS, four macOS ones (sun.awt.PlatformGraphicsInfo, sun.lwawt.macosx.LWCToolkit, sun.awt.CGraphicsEnvironment and sun.print.PlatformPrinterJobProxy, which force headless AWT). The build logs a warning if a quarkus-awt version has other substitutions (for instance renamed ones), or lacks one of the Windows or macOS ones.

  • The JavaBeans API: property editors, XMLEncoder and XMLDecoder, EventHandler, and the bean properties of the AWT classes (see JavaBeans).

  • On macOS: the first thread of the process runs the Cocoa event loop, as with the java launcher (see macOS).

  • Run time initialization of the JDK desktop packages, and of the classes whose static initializer uses them, in the application and in its libraries (whether they are in the Jandex index or not): a class with a static final Color ACCENT = new Color(0x0096c9) (or a Font, an icon, a border…​) is initialized at run time, as in JVM mode, instead of failing the native build.

  • The system properties that the java launcher sets and a native executable does not have (sun.java2d.dpiaware on Windows, apple.awt.application.name on macOS, sun.io.unicode.encoding), and a java.home directory with the files of the JDK that AWT reads there (the font configuration of the JDK on Windows, the Metal shaders of Java2D on macOS).

  • All the charsets of the JDK: the JDK font configuration of Windows uses many of them, and fonts whose names or character maps use a legacy encoding (Shift_JIS, GBK, Big5…​), the text that other applications transfer in their charset and the RTF font charsets of Swing need them on every platform.

  • On Windows: the application manifest of the java launcher (visual styles of the native controls, per monitor DPI awareness), an optional GUI subsystem, and a copy of the Visual C++ runtime next to the executable.

Writing an AWT application

Observe DesktopStartupEvent to create the user interface: the extension fires it on the event dispatch thread once the application started, and the application stops when its last window closes. No @QuarkusMain is needed.

import io.quarkiverse.desktop.awt.DesktopStartupEvent;

@Singleton (1)
public class MainWindow extends Frame {

    @Inject
    Greeting greeting; (2)

    void open(@Observes DesktopStartupEvent event) { (3)
        add(new Label(greeting.text()));
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                dispose(); (4)
            }
        });
        pack();
        setVisible(true);
    }
}
1 A component bean is @Singleton or @Dependent, never @ApplicationScoped (see Components as CDI beans).
2 Any bean can be injected, as well as configuration (@ConfigProperty).
3 Called on the event dispatch thread, after the StartupEvent observers (see Starting the user interface).
4 A java.awt.Frame does nothing on close: dispose it. Closing the last window stops the application (Quarkus.asyncExit()): ShutdownEvent observers and @PreDestroy methods run (see Closing windows and exit).

Application model and CDI describes the application model: the startup of the user interface (and the manual mode, from a @QuarkusMain), the exit, the event dispatch thread (EdtExecutor for CompletableFuture, Mutiny and asynchronous events, Edt, @RunOnEdt), the rules of the component beans and WindowBeans, the application menu, Finder and Dock events of macOS (QuitRequest), dev mode, tests, native executables and Quarkus FX.

Dev mode

In dev mode, the application restarts in the same JVM: the AWT toolkit and its threads stay, and the windows and tray icons of the previous run are disposed when the application stops (in tests too, where several applications run in the same JVM). See Dev mode for the restarts, what they dispose and what stays.

The event dispatch thread stays too, and AWT gives it the class loader of the application that started AWT first. In dev mode and in tests (several applications in the same JVM), the extension makes it dispatch the events with the class loader of the running application, so that the classes loaded by name on the event dispatch thread (for instance a look and feel or an editor kit of the application) are the ones of the running application. For this, the extension starts the AWT toolkit when any application starts in dev mode and tests, with or without a user interface (on macOS, the application then gets a Dock icon).

Native executables

Build a native executable as usual (./mvnw package -Dnative). The JDK AWT libraries are not linked in the executable: they are copied next to it, and the executable needs them at run time.

Windows

The native build needs Visual Studio (the C++ build tools), as any Quarkus native build on Windows, and must run on Windows: a container build produces a Linux executable.

The build output directory contains the executable and the libraries to distribute with it:

  • the JDK libraries it uses: awt.dll, fontmanager.dll, freetype.dll, javajpeg.dll, lcms.dll, mlib_image.dll, jsound.dll, and javaaccessbridge.dll and jawt.dll for the Java Access Bridge;

  • java.dll and jvm.dll, generated by GraalVM for these libraries: they are bound to the name of the executable, so never rename the executable after the build (set quarkus.package.output-name instead);

  • msvcp140.dll, vcruntime140.dll and vcruntime140_1.dll, the Visual C++ runtime (see quarkus.desktop.awt.windows.copy-vc-runtime).

The executable is a console application by default: set quarkus.desktop.awt.windows.subsystem=windows for an application without console window (as javaw).

Linux

The native executable uses the X11 libraries of the system, and the display of the DISPLAY environment variable (Wayland sessions provide it through XWayland; without DISPLAY, the application is headless). The target system needs the runtime libraries of the JDK desktop libraries, for instance on Ubuntu 24.04:

sudo apt-get install libx11-6 libxext6 libxrender1 libxi6 libxtst6 libxrandr2 libfreetype6 libfontconfig1 \
    libasound2t64 libcups2t64 libgtk-3-0t64

GTK is used by the native file dialog, the desktop integration and the GTK look and feel of Swing, CUPS by printing, ALSA by Java Sound. Tests of GUI applications need a display: use a virtual one (xvfb-run), with a window manager (for instance openbox) when they depend on windows kept on top, window activation or frame insets as on a desktop.

The build output directory contains the executable and the JDK libraries to distribute with it: libawt.so, libawt_xawt.so (the X11 toolkit), libawt_headless.so, libfontmanager.so, libjavajpeg.so, liblcms.so, libmlib_image.so, libjsound.so, and libjava.so and libjvm.so, generated by GraalVM for these libraries (fonts use the FreeType library of the system).

macOS

Native executables for macOS need:

  • a quarkus-awt with macOS support: Quarkus 4.0 or later (the pull request "Enable quarkus-awt on macOS", merged for Quarkus 4.0, which is not released yet). Until then, build Quarkus main (./mvnw -Dquickly) and use its 999-SNAPSHOT version;

  • GraalVM 25.1 or later on Apple silicon (for example GraalVM Community 25 Innovation; GraalVM 25.0.x does not support AWT on macOS);

  • the Xcode Command Line Tools.

The native build must run on macOS: a container build produces a Linux executable. JVM mode works with any Quarkus version. With a quarkus-awt without macOS support, the native build fails with a message saying so.

The build output directory contains the executable and the JDK libraries it loads (libawt.dylib, libawt_lwawt.dylib, libosxapp.dylib, libosxui.dylib for the Aqua look and feel, libfontmanager.dylib…​) with the libjava.dylib and libjvm.dylib libraries generated by GraalVM: distribute them together, in the same directory (in an application bundle, all in Contents/MacOS). When you sign the executable with the hardened runtime, sign every library with the same identity. The build fails when some of these libraries are missing.

AppKit, which AWT uses on macOS, only runs on the first thread of the process. As the java launcher does, the extension keeps that thread for the Cocoa event loop and runs the Quarkus application on a new thread named main (see quarkus.desktop.awt.macos.park-main-thread). The first thread is named Cocoa Run Loop, then AppKit Thread once AWT started AppKit on it, and the io.quarkiverse.desktop.main-thread-parked system property is true. In a @QuarkusMain class with its own main method, do not use AWT before calling Quarkus.run (EventQueue.invokeLater is fine, EventQueue.invokeAndWait is not). Quarkus.run never returns there: the first thread stays in the Cocoa event loop, and the process exits when the application ends, as with the java launcher (with an exit handler that does not exit, once the other non daemon threads end). Code after Quarkus.run in main does not run (it does in JVM mode, and on Windows and Linux): keep the default exit handler, and do that work in QuarkusApplication.run or when the application stops (@Observes ShutdownEvent). A native build with -H:+RunMainInNewThread cannot show a user interface: the build logs a warning.

In an application with a user interface, Cmd-Q and the other quit requests fire QuitRequest and stop the application through Quarkus (see Application menu, Finder and Dock events).

AWT components are drawn by the Swing Aqua look and feel on macOS: AWT applications do not need quarkus-desktop-swing for it. The name of the application in the menu bar is quarkus.application.name (see quarkus.desktop.awt.macos.application-name); in JVM mode, pass -Dapple.awt.application.name=…​. Java2D uses Metal: -Dsun.java2d.metal=True prints the pipeline in use (the extension extracts the Metal shaders of the JDK used for the native build to the java.home directory of the executable).

quarkus.desktop.awt.macos.info-plist=true embeds an information property list in the executable, as the java launcher has one (bundle identifier, name and version, high resolution capability, and the text macOS shows when the application asks for the microphone).

The executable declares the minimum macOS version and the SDK version of the java launcher of the JDK used for the native build (otool -l shows them in LC_BUILD_VERSION, for instance minos 11.0 and sdk 14.5): it starts on the macOS versions the JDK supports, and AppKit gives its windows the same look as in JVM mode (AppKit chooses the height of the title bars, for instance, from the SDK version of the executable). Without it, the linker writes the version of the SDK of the Xcode tools as both, and the executable only starts on that macOS version and later (quarkus.desktop.awt.macos.jdk-build-version=false).

Troubleshooting:

  • No window, and the process is idle: the first thread does not run the Cocoa event loop. sample <pid> 3 shows the threads: the main thread (com.apple.main-thread) must be in CFRunLoopRun, then in -[NSApplication run] once a window exists. Check that the build log contains -J-Dio.quarkiverse.desktop.awt.macos.park-main-thread=true.

  • Bad JNI lookup messages, or exceptions in AppKit call backs: run with the JNU_APPKIT_TRACE=1 environment variable, and report the missing registration (the native image tracing agent gives it, see Limitations).

  • The application does not exit: the process is halted when System.exit does not complete within quarkus.desktop.awt.macos.exit-halt-timeout, with a message.

  • Robot and screen capture need the Screen Recording and Accessibility permissions (System Settings, Privacy & Security) of the application that starts the executable (for instance the terminal). Without Accessibility, macOS drops the input events of Robot without an error. Robot reads the screen through the color profile of the display: a pixel may read one or two levels away from the color painted, compare with a tolerance. As in JVM mode, do not call Robot.waitForIdle() from two threads at the same time: the macOS toolkit waits on a lock of the application that each call replaces, and the process may crash.

HiDPI displays (Windows)

Native executables are DPI aware by default, as a JVM started by the java launcher: they scale their user interface to the scale factor of the display (sun.java2d.dpiaware defaults to true, and the manifest declares per monitor DPI awareness). Set quarkus.desktop.awt.windows.dpi-aware=false to let Windows stretch the windows instead.

Java2D pipelines

Native executables render with the same Java2D pipelines as the JDK, selected with the same system properties (on the command line of the executable, or with System.setProperty before AWT starts):

  • Windows: Direct3D by default, GDI with -Dsun.java2d.d3d=false, OpenGL (WGL) with -Dsun.java2d.opengl=true (-Dsun.java2d.opengl=True prints whether it is enabled);

  • Linux: XRender by default, X11 with -Dsun.java2d.xrender=false, OpenGL (GLX) with -Dsun.java2d.opengl=true;

  • macOS: Metal by default, OpenGL with -Dsun.java2d.metal=false.

The pipeline in use is the class of the default graphics configuration (GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(): D3DGraphicsConfig, Win32GraphicsConfig, WGLGraphicsConfig, XRGraphicsConfig…​). The showcase compares JVM mode and native executables with another pipeline (--pipeline=gdi|opengl on Windows, --pipeline=x11|opengl on Linux, -- -Dsun.java2d.metal=false on macOS).

Fonts and languages

On Windows, the logical fonts (Dialog, SansSerif, Serif, Monospaced, DialogInput) use the font configuration of the JDK used for the native build, as in JVM mode: they display Arabic, Hebrew, Chinese, Japanese, Korean, Thai and Indic text. It is extracted to the temporary directory at startup. quarkus.desktop.awt.windows.font-configuration=minimal selects the Latin only font configuration of quarkus-awt. On Linux, fonts come from fontconfig.

The resource bundles of AWT (key names, print dialog…​) are included for the locales of the native executable: set quarkus.locales (and quarkus.default-locale) to the languages of the application.

Type 1 fonts (.pfa, .pfb files, Font.createFont(Font.TYPE1_FONT, …​)) work as in JVM mode: native executables read them with the FreeType library of the JDK (freetype.dll on Windows), which supports them. quarkus-awt disables them (its substitution of sun.font.Type1Font rejects every Type 1 font): the extension removes that substitution.

Accessibility (Windows)

Screen readers (JAWS, NVDA…​) access Java applications through the Java Access Bridge, which users enable with jabswitch -enable. Native executables include it by default. Set quarkus.desktop.awt.windows.access-bridge=false to leave it out: the executable then ignores the assistive technologies configured by the user, instead of failing to start the AWT toolkit. On Linux, the executable always ignores them (the Java ATK wrapper cannot be loaded in a native executable).

JavaBeans

The JavaBeans API (java.beans) works with reflection. Native executables always support its core:

  • the property editors of the JDK (PropertyEditorManager.findEditor for the primitive types, String, Color and Font), and the bean info of java.awt.Component;

  • XMLEncoder and XMLDecoder with the persistence delegates of the JDK: the java.lang values, enumerations, classes and arrays, the java.util collections and dates, and the AWT values (Color, Font, Insets, Point, Dimension, Rectangle, Cursor, MenuShortcut, AWTKeyStroke, strokes and paints, TextAttribute, the java.awt.geom points, dimensions, rectangles and transforms);

  • EventHandler listeners on property change events.

The application classes are registered by the application, as usual: @RegisterForReflection for the beans, their bean info, editors and persistence delegates, and @RegisterForProxy for the listener interfaces of EventHandler (one annotation per interface: @RegisterForProxy(targets = {A.class, B.class}) registers a single proxy class that implements both).

The bean properties of the AWT components, menus, layouts, events and listeners are registered too, unless quarkus.desktop.awt.java-beans.jdk-classes is false: the public constructors, methods and fields of these classes. The Introspector finds the properties and event sets of the AWT components (Introspector.getBeanInfo(Button.class) finds the label property), XMLEncoder and XMLDecoder write and read AWT forms (a Panel with its layout, components and constraints, menu bars), EventHandler.create(ActionListener.class, label, "text", "source.label") reads the source of an ActionEvent, and Beans.instantiate(loader, "java.awt.Button") creates a button. The Swing extension has the same property for the Swing classes, disabled by default (see JavaBeans).

This registration makes a native executable about 0.3 MB larger: 0.29 MB for the showcase application (127.3 MB without it, and 106.2 MB for its AWT only variant), 0.34 MB for the Swing integration test application (109.4 MB without it).

Headless mode

quarkus.native.headless (true by default) only applies to the native image builder: it has no effect on the native executable, which is headless only when there is no display. Keep the default.

Exact reachability metadata

With the GraalVM option --exact-reachability-metadata (-Dquarkus.native.additional-build-args=--exact-reachability-metadata), a native executable is strict: a reflection, resource or JNI lookup that its metadata does not register fails with a MissingReflectionRegistrationError (or a MissingResourceRegistrationError, a MissingJNIRegistrationError), instead of answering as if the class, member or resource did not exist. It validates the metadata of an application: run the executable with -XX:MissingRegistrationReportingMode=Warn to get every missing registration in the output (with the stack of the lookup) instead of the first error.

The JDK desktop code looks up many things that usually do not exist, and expects not to find them: the JavaBeans API probes java.awt.ButtonBeanInfo, java.awt.ButtonCustomizer, java.awt.ButtonPersistenceDelegate, java.beans.MetaData$java_awt_Button_PersistenceDelegate and java.awt.ButtonEditor for the classes it handles, Component checks whether each component class of the application declares coalesceEvents, Nimbus probes a class for each region name, ResourceBundle looks for .properties files next to the bundle classes of the JDK, ImageIO, printing, Java Sound, accessibility and input methods look for META-INF/services files of the application…​ With exact metadata, each of these lookups fails with an error that the JDK does not expect. The extensions register them, so that an application can use exact metadata:

  • the lookups of the JDK desktop code expected to fail, for the features that the extensions support, and the JavaBeans probes of the JDK classes that they register for the JavaBeans API (with their supertypes, whose members the JavaBeans API queries);

  • for the application, the icons of its look and feels (computed from its classes in the Jandex index);

  • for every class of the application and of its libraries that the native image analysis reaches, whether it is in the Jandex index or not, the methods whose declaration AWT and Swing check with reflection: coalesceEvents in the components, processInputMethodEvent in the text components, the drawing methods of the plain text views (registered without exact metadata too: a library component and the application classes that extend it work as in JVM mode);

  • the var handles that Java2D and the fonts use to access native memory (Foreign Function and Memory API).

These registrations are added when quarkus.native.additional-build-args or quarkus.native.additional-build-args-append contains --exact-reachability-metadata (or -H:ThrowMissingRegistrationErrors), or with quarkus.desktop.awt.exact-reachability-metadata=true when the option is given another way. They make a native executable about 0.3 MB larger, and are useless without the option.

The application registers its own lookups, as it registers its own classes, in a src/main/resources/META-INF/native-image/<group>/<artifact>/reachability-metadata.json file: a class that does not exist is registered as a type, and the lookup then fails with a ClassNotFoundException as without exact metadata. For instance, for a bean com.example.Ticket that XMLEncoder writes and the Introspector reads, and the configuration files that Quarkus looks up at run time:

{
  "reflection": [
    { "type": "com.example.Ticket" },
    { "type": "com.example.TicketBeanInfo" },
    { "type": "com.example.TicketCustomizer" },
    { "type": "com.example.TicketPersistenceDelegate" },
    { "type": "java.beans.MetaData$com_example_Ticket_PersistenceDelegate" }
  ],
  "resources": [
    { "glob": "application.properties" },
    { "glob": "application-prod.properties" },
    { "glob": "META-INF/microprofile-config.properties" }
  ]
}

The showcase (see Verification) runs all its pages with exact metadata and no missing registration on Windows, Linux and macOS, in both of its variants (on Windows also with the GDI and OpenGL pipelines and at the scale of the display), with its own application registrations in its reachability-metadata.json. The integration tests of the extensions, which keep the default configuration (without the JavaBeans registration of the Swing classes), pass with exact metadata on Windows and Linux, with the application registrations of their reachability-metadata.json: the configuration files that Quarkus looks up, the persistence delegate of an enumeration value that XMLEncoder writes, and the URL stream handler providers that a URL created from a text looks up. GraalVM 25.0.0 note: with -XX:MissingRegistrationReportingMode=Warn, opening the URL of a resource that is not registered (for instance an image of an HTML page that does not exist) fails with a ClassCastException after the warning, instead of a FileNotFoundException: register such resources.

Limitations

Native executables differ from JVM mode where GraalVM or the java launcher make the difference:

  • SplashScreen.getSplashScreen() returns null: the splash screen is shown by the java launcher (-splash:, SplashScreen-Image).

  • java.home is a directory that the extension creates in the temporary directory (with the font configuration and the PostScript font names of the JDK), java.class.path is empty, sun.boot.library.path and sun.java.launcher are not set, and sun.java2d.dpiaware is true on Windows (see quarkus.desktop.awt.windows.dpi-aware).

  • Class path resources have resource: URLs instead of jar: or file: URLs.

  • The locales are those of quarkus.locales (all of them in JVM mode): the texts of AWT and Swing, and the number and date formats of the other languages, need their locale there.

  • BreakIterator returns the break iterators of the default locale of the build, whatever the locale: the dictionary based line and word breaks of Thai (and of the other languages that need a dictionary) are not available.

  • java.lang.reflect.Array.get boxes the elements of primitive arrays with Integer.valueOf (and the other valueOf methods), which returns cached instances for small values, where the JVM creates new ones: code that compares these values by identity behaves differently (for instance XMLEncoder writing an int[] whose elements equal a constant that it already wrote).

  • Classes loaded by name that the extension does not know (third party look and feels, image readers, custom accessibility providers…​) need their own native image metadata, for instance with @RegisterForReflection. The providers of the application and of its libraries for the desktop services of the JDK (ImageIO plugins, print services, sound providers, input methods, accessibility providers) found in META-INF/services files are registered.

  • Please report the features that fail in a native executable. The native image tracing agent gives the missing metadata: java -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image/<group>/<artifact> -jar target/quarkus-app/quarkus-run.jar, and a native executable built with exact metadata and run with -XX:MissingRegistrationReportingMode=Warn lists them (see Exact reachability metadata).

Verification

The integration tests of the extension build a native executable that shows a window with components and checks fonts, ImageIO plugins, print services and printing to a PostScript stream, data flavors, text attributes, Java Sound, the JavaBeans API, the desktop integration and the Java Access Bridge (Windows), on Windows, Linux and macOS (with the libraries and frameworks of the macOS executable, its main thread and the Metal pipeline). They also pass when they are built with exact reachability metadata (-Dquarkus.native.additional-build-args=--exact-reachability-metadata, verified on Windows and Linux). The Quarkus Desktop showcase compares JVM mode and native executables page by page (see Verification).

Configuration

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

Whether the native executable is DPI aware, as a JVM started by the java launcher is.

When enabled, the sun.java2d.dpiaware system property defaults to true in the native executable (a -Dsun.java2d.dpiaware=false command line option still overrides it), and the application manifest (see quarkus.desktop.awt.windows.manifest) declares per monitor DPI awareness. Windows then lets the application scale itself to the display scale factor (crisp text and images). When disabled, Windows stretches the windows of the application as bitmaps (blurry) on displays with a scale factor above 100 %.

Environment variable: QUARKUS_DESKTOP_AWT_WINDOWS_DPI_AWARE

boolean

true

Whether to embed an application manifest in the native executable, as the java launcher has one.

The manifest selects the version 6 of the Windows common controls (the visual styles of the native AWT components and dialogs; without it they look like Windows 2000 controls), declares the DPI awareness of the application (see quarkus.desktop.awt.windows.dpi-aware) and the supported Windows versions. It is embedded by the linker, through -H:NativeLinkerOption options that the extension adds to the native build.

Environment variable: QUARKUS_DESKTOP_AWT_WINDOWS_MANIFEST

boolean

true

The Windows subsystem of the native executable.

console, the default, is the subsystem of the java launcher : started from Explorer, the application gets a console window, which shows its log. windows is the subsystem of the javaw launcher : no console window (the standard output and error streams of the application are lost unless they are redirected, so configure a log file).

Environment variable: QUARKUS_DESKTOP_AWT_WINDOWS_SUBSYSTEM

console, windows

console

Whether to copy the Microsoft Visual C++ runtime libraries (msvcp140.dll, vcruntime140.dll and vcruntime140_1.dll) of the GraalVM used for the native build next to the native executable, when the native executable uses the AWT libraries.

The JDK AWT library awt.dll needs msvcp140.dll, which a Windows installation does not always have (it comes with the Visual C++ Redistributable). With a local copy, the native executable and its libraries can be distributed as they are, as the JDK does.

Environment variable: QUARKUS_DESKTOP_AWT_WINDOWS_COPY_VC_RUNTIME

boolean

true

Whether the native executable supports the Java Access Bridge, which screen readers such as JAWS or NVDA use to access the user interface of Java applications.

Users enable the Java Access Bridge with jabswitch -enable (or in the Windows accessibility settings), which configures the assistive_technologies of every Java application in %USERPROFILE%\.accessibility.properties. When enabled, the Java Access Bridge is included in the native executable, as it is in the JDK (javaaccessbridge.dll and jawt.dll are copied next to the native executable), and it is loaded when the user enabled it. When disabled, the javax.accessibility.assistive_technologies system property defaults to an empty value in the native executable, so that the native executable ignores the user setting, instead of failing to start with a java.awt.AWTError: Could not load or activate service provider.

Environment variable: QUARKUS_DESKTOP_AWT_WINDOWS_ACCESS_BRIDGE

boolean

true

The logical font configuration (the physical fonts behind the Dialog, SansSerif, Serif, Monospaced and DialogInput logical fonts, used by AWT components and by default in Swing).

jdk, the default, is the font configuration of the JDK used for the native build (its lib/fontconfig.properties.src file, embedded in the native executable and extracted to the temporary directory at startup) : the logical fonts display the same scripts as in JVM mode (Arabic, Hebrew, Chinese, Japanese, Korean, Thai, Indic scripts…​), and all the charsets of the JDK are included in the native executable, since the font configuration uses many of them. minimal is the minimal font configuration of the Quarkus AWT extension (Latin scripts only) : a slightly smaller native executable, with the standard charsets only (fonts whose names or character maps use a legacy encoding such as Shift_JIS or GBK, and RTF text in other charsets, are then not read as in JVM mode). On Linux and macOS, all the charsets are always included.

Environment variable: QUARKUS_DESKTOP_AWT_WINDOWS_FONT_CONFIGURATION

jdk, minimal

jdk

Whether the JDK AWT classes support the JavaBeans API in native executables : their public constructors, methods and fields are registered for reflection, so that the Introspector finds their bean properties and event sets, and that XMLEncoder, XMLDecoder, Statement, Expression, EventHandler and Beans.instantiate work with them, as in JVM mode.

The classes are the AWT components and menu components, the layouts (GridBagConstraints included), the values of their properties (Color, Font, Insets, Point, Rectangle, Cursor, MenuShortcut…​), the AWT events, listeners and adapters. For instance Introspector.getBeanInfo(Button.class) finds the label property, XMLEncoder writes a Panel with its layout and components, and EventHandler.create(ActionListener.class, target, "text", "source.label") reads the label of the source of an ActionEvent.

It makes a native executable about 0.3 MB larger. When disabled, the Introspector finds no bean property of these classes (other than those that the extensions register for their own needs) and XMLEncoder cannot write them. The same property of the Desktop Swing extension, quarkus.desktop.swing.java-beans.jdk-classes (disabled by default), registers the Swing classes, and the AWT classes that they extend whatever the value of this property.

Environment variable: QUARKUS_DESKTOP_AWT_JAVA_BEANS_JDK_CLASSES

boolean

true

Whether the native build registers what the JDK desktop code looks up and may not find, for native executables built with --exact-reachability-metadata (GraalVM : a lookup that is not registered then fails with a missing registration error instead of answering "not found", even when "not found" is the expected answer).

The registered lookups are those of the JDK expected to fail (the BeanInfo, Customizer, PersistenceDelegate and Editor classes that the JavaBeans API probes for the JDK classes that the extensions register for it, the region names that Nimbus probes, the .properties files next to the resource bundles of the JDK, the META-INF/services files of the desktop services, the processInputMethodEvent methods that the text components of the JDK do not declare…​), the types whose members the JavaBeans API queries, and the var handles of the native memory accesses of Java2D and fonts. They make a native executable about 0.3 MB larger, and are useless without exact reachability metadata. The methods that AWT and Swing look up in the classes of the application and of its libraries (coalesceEvents in the components…​) are registered for every native executable, declared or not.

By default, they are registered when quarkus.native.additional-build-args or quarkus.native.additional-build-args-append contains --exact-reachability-metadata (or -H:ThrowMissingRegistrationErrors). Set this property when the option is given another way.

Environment variable: QUARKUS_DESKTOP_AWT_EXACT_REACHABILITY_METADATA

boolean

Whether the first thread of the process runs the Cocoa event loop, as with the java launcher, the Quarkus application running on a new thread named main.

AppKit, which AWT, Swing and JavaFX use on macOS, only runs on the first thread of the process : without this, the first window of an AWT or Swing application never shows. Disable it only with the Quarkus FX launcher, which then runs JavaFX on the first thread itself (AWT then runs embedded in JavaFX), or with a GraalVM version that keeps the first thread in the Cocoa event loop itself.

Environment variable: QUARKUS_DESKTOP_AWT_MACOS_PARK_MAIN_THREAD

boolean

true

The stack size of the thread that runs the Quarkus application (the first thread of a macOS process has 8 MiB, the other threads 512 KiB by default).

Environment variable: QUARKUS_DESKTOP_AWT_MACOS_MAIN_THREAD_STACK_SIZE

MemorySize 

8M

How long System.exit may take once the application has stopped before the process is halted, 0 to wait for ever. A safety net against an exit that never completes while AppKit runs on the first thread.

Environment variable: QUARKUS_DESKTOP_AWT_MACOS_EXIT_HALT_TIMEOUT

Duration 

10S

The name of the application in the menu bar and the Dock : the default value of the apple.awt.application.name system property in the native executable (the java launcher sets it to the simple name of the main class). The Quarkus application name (quarkus.application.name) by default.

Environment variable: QUARKUS_DESKTOP_AWT_MACOS_APPLICATION_NAME

string

Whether to embed an information property list (Info.plist) in the native executable, as the java launcher has one : bundle identifier, name and versions of the application, high resolution capability, and the description of the microphone use (Java Sound capture) that macOS shows when it asks the user for the permission.

Environment variable: QUARKUS_DESKTOP_AWT_MACOS_INFO_PLIST

boolean

false

Whether the native executable declares the minimum macOS version and the SDK version of the java launcher of the JDK that builds it (its LC_BUILD_VERSION load command), as a JVM application does.

macOS does not start an executable on a version older than its minimum version, and AppKit chooses the look of the windows (the height of the title bars for instance) and its compatibility behaviors from its SDK version. When disabled, the linker writes the version of the SDK of the Xcode tools as both : the executable then only starts on that macOS version and later, and gets the look of that version.

Environment variable: QUARKUS_DESKTOP_AWT_MACOS_JDK_BUILD_VERSION

boolean

true

Whether the event is fired. By default it is, except in tests (@QuarkusTest, where it would open the windows of the application) : set %test.quarkus.desktop.awt.startup-event.enabled=true for user interface tests. In tests, quarkus.arc.test.disable-application-lifecycle-observers=true disables it too.

Environment variable: QUARKUS_DESKTOP_AWT_STARTUP_EVENT_ENABLED

boolean

When the event is fired : auto during the startup of the application (queued on the event dispatch thread after the StartupEvent observers : its observers may run while a @QuarkusMain runs), manual when the application calls DesktopLifecycle.start() (from its @QuarkusMain once its work before the user interface is done, or from a StartupEvent observer).

Environment variable: QUARKUS_DESKTOP_AWT_STARTUP_EVENT_MODE

auto, manual

auto

Whether the application stops (Quarkus.asyncExit()) when its last visible window is closed or hidden, once a first window opened. Only for an application observing DesktopStartupEvent, never in tests, nor with Quarkus FX. Disable it for an application that stays alive without windows (a tray icon, the macOS convention), or that closes a window before showing the next one (a splash screen closed before the main window shows).

Environment variable: QUARKUS_DESKTOP_AWT_EXIT_ON_LAST_WINDOW_CLOSED

boolean

true

About the Duration format

To write duration values, use the standard java.time.Duration format. See the Duration#parse() Java API documentation for more information.

You can also use a simplified format, starting with a number:

  • If the value is only a number, it represents time in seconds.

  • If the value is a number followed by ms, it represents time in milliseconds.

In other cases, the simplified format is translated to the java.time.Duration format for parsing:

  • If the value is a number followed by h, m, or s, it is prefixed with PT.

  • If the value is a number followed by d, it is prefixed with P.

About the MemorySize format

A size configuration option recognizes strings in this format (shown as a regular expression): [0-9]+[KkMmGgTtPpEeZzYy]?.

If no suffix is given, assume bytes.