Desktop
Tray icon, close to tray and autostart
Add a tray icon and menu, hide the window on close, start with the computer and allow only one copy per user.
Available since 0.3.0. A mail client or chat app usually lives in the tray, hides instead of quitting when its window is closed, and can start with the computer. These are separate pieces, so you choose which to use, and each can be changed while the app runs.
Tray icon and menu
Application app = ...;
WebWindow main = ...;
if (app.isTraySupported()) { // Windows: always. Linux: needs a tray host
Tray tray = app.createTray(iconBytes, "Parsel"); // call on the UI thread
tray.onClick(main::focus); // primary click: bring the window back
tray.setMenu(TrayMenu.of(
TrayMenu.action("Open Parsel", main::focus),
TrayMenu.separator(),
TrayMenu.check("Close to tray", closeToTray, on -> setCloseToTray(on)),
TrayMenu.check("Start with the computer", autostart, on -> setAutostart(on)),
TrayMenu.separator(),
TrayMenu.action("Quit", app::quit)));
}- Menus are immutable. To tick a box or change a label, build the menu again and call
tray.setMenu(...).tray.setIconandtray.setTooltipwork the same way, for example for "3 unread". Menu callbacks run on the UI thread. - Windows: the tray menu is a native menu, drawn in dark mode when the system is dark. It supports checks, disabled entries, separators and submenus. If Explorer restarts, the icon is put back.
- Linux: the tray is a StatusNotifierItem with a
dbusmenumenu, which KDE Plasma, XFCE, Cinnamon, MATE, Budgie and others show. Stock GNOME needs the AppIndicator extension, otherwiseisTraySupported()isfalse.
Close to tray and autostart
main.setCloseBehavior(closeToTray ? CloseBehavior.HIDE : CloseBehavior.CLOSE); // takes effect on the next click of the close button
Autostart autostart = app.autostart();
autostart.enable(List.of(exePath, "--minimized")); // start with the computer, minimized...
autostart.enable(List.of(exePath)); // ...or not: calling it again replaces the entry
autostart.disable(); autostart.isEnabled();- Start minimized is an argument you choose: put
--minimizedin the autostart command, and inmaincreate the window withwithVisible(false)(and a tray) whenargscontains it. Only hide at startup ifapp.isTraySupported(). - Close to tray needs a tray.
CloseBehavior.HIDEonly hides the window;focus()orshow()brings it back, whileclose()andapp.quit()still really close it. - The command: give the launcher of your installed or packaged app (on Windows a quoted path in the Run key, on Linux the
Exec=line of~/.config/autostart/<appId>.desktop).Autostart.currentCommand(extraArgs)describes the running process, which is fine forjava -jarwhile developing.
One copy only
A tray app that starts at sign-in should not start twice.
public static void main(String[] args) {
AppOptions options = AppOptions.of("com.example.parsel");
SingleInstance instance = SingleInstance.acquire(options, List.of(args), otherArgs -> app.dispatch(() -> main.focus()));
if (!instance.isPrimary()) {
return; // the running copy was told (and receives this copy's arguments)
}
...
}SingleInstance takes a lock file in the data directory (released by the system if the app dies) and talks to the running copy over a Unix domain socket that only the same user can reach. The callback runs on a thread of its own, so use app.dispatch.