Package limn.desktop

Class Tray

java.lang.Object
limn.desktop.Tray

public final class Tray extends Object
An icon an application keeps in the system's tray: the notification area on Windows, the menu bar's status items on macOS, the panel's tray on a Linux desktop. It has a title, a tooltip, a menu and, if the application wants one, an activation.

 Tray tray = Tray.create(backend, "orders");
 tray.setIcon(icon);
 tray.setTooltip("Orders: 3 waiting");
 tray.setMenu(new Menu()
         .addItem("Open", () -> window.show())
         .addSeparator()
         .addItem("Quit", backend::requestQuit));
 tray.onActivate(() -> window.show());
 

The system draws the menu, from the same Menu a window's menu bar takes. It is read each time it is about to open, so an application changes its menu, an item's check mark or whether it is enabled as it does anywhere, and the next opening shows it. Of an item the system shows its label, its icon, whether it is enabled and checked, a separator, a submenu and its accelerator, which macOS also runs while the menu is open and the other systems only show, where their menu shows one.

What a click does. With no onActivate(java.lang.Runnable), any click on the icon opens the menu. With one, the click that means "this application" on that system runs it and the other click opens the menu: the left click on Windows and on most Linux panels, a double click on some. There are panels that never send an activation, so what the listener does should also be an item of the menu.

A desktop may have no tray. isAvailable() says whether the system took the icon, and onAvailabilityChange(java.lang.Runnable) when that changes; it does not say that somebody sees the icon, which no system tells an application. An application that hides its window "to the tray" should minimize it instead where this is false.

An animated icon plays (Icon.isAnimated()), in each of the tray's pictures: the icon, the monochrome one and the one that asks for attention, the dot laid on every frame. The tray swaps the frames on the UI thread at the icon's own times, as many turns as it asks for, and plays only the picture shown. While macOS holds the application's loop with a menu open, the icon waits with it and goes on at the frame that is due when the menu closes. A menu's icons show their first frame, as every system's menu does.

A tray does not keep an application running. An application whose windows may all be hidden or closed while its icon stays sets LoopLifetime.UNTIL_QUIT. Closing the backend takes every icon away.

Every method is called on the UI thread, and every listener and every menu item's action runs there.

  • Method Details

    • create

      public static Tray create(Backend backend, String id)
      Makes a tray icon. Nothing is shown until it is given an icon.
      Parameters:
      backend - the application's backend
      id - this icon's identifier, the application's own and the same on every run: one to 64 ASCII letters, digits, dots, hyphens and underscores. A system remembers what the user chose for the icon by it, so two icons of one application have different ones
      Returns:
      the tray
      Throws:
      IllegalArgumentException - when id is not of that form
      IllegalStateException - when a tray of this backend that is not disposed has id, or off the UI thread
    • id

      public String id()
      Returns:
      the identifier this tray was made with
    • setTitle

      public Tray setTitle(String title)
      Sets the icon's name, which a panel shows beside it where it shows names and a screen reader says. It is the identifier until set.
      Parameters:
      title - the name; not empty
      Returns:
      this tray
    • setTitle

      public Tray setTitle(I18nString title)
      Sets the icon's name to a text that follows the language.
      Parameters:
      title - the name; not empty in any language
      Returns:
      this tray
    • title

      public String title()
      Returns:
      the icon's name now
    • setIcon

      public Tray setIcon(@Nullable Icon icon)
      Sets the icon, shown as it is. A tray shows nothing until it has this or setMonochromeIcon(limn.graphics.Icon), and is taken out of the system's tray when it has neither again.
      Parameters:
      icon - the icon, or null for none
      Returns:
      this tray
    • setMonochromeIcon

      public Tray setMonochromeIcon(@Nullable Icon shape)
      Sets an icon that takes the panel's colour: a shape, whose own colour is not used. macOS colours it as it does its own status items and Windows shows it light or dark as its task bar is. A Linux panel does not say its colour, so there the icon of setIcon(limn.graphics.Icon) is shown, and this one in a grey that reads on a light and a dark panel when there is no other.
      Parameters:
      shape - an icon that is tintable, or null for none
      Returns:
      this tray
      Throws:
      IllegalArgumentException - when shape is not tintable
    • setTooltip

      public Tray setTooltip(String tooltip)
      Sets the tooltip.
      Parameters:
      tooltip - the text, empty for none. A system may cut a long one, and some panels show none
      Returns:
      this tray
    • setTooltip

      public Tray setTooltip(I18nString tooltip)
      Sets the tooltip to a text that follows the language.
      Parameters:
      tooltip - the text
      Returns:
      this tray
    • setMenu

      public Tray setMenu(@Nullable Menu menu)
      Sets the menu. The tray reads it each time the system is about to open it, so later changes to the same menu need no call here.
      Parameters:
      menu - the menu, or null for none
      Returns:
      this tray
      Throws:
      IllegalArgumentException - when a submenu of menu contains a menu it is in
    • onActivate

      public Tray onActivate(@Nullable Runnable listener)
      Sets what the click that means "this application" does; see the class description for which click that is. Setting or clearing it on an icon already shown may make the system show the icon anew.
      Parameters:
      listener - what to run, or null for every click to open the menu
      Returns:
      this tray
    • setAttention

      public Tray setAttention(boolean attention)
      Sets whether the icon asks for attention. While it does, it is shown with a dot at its top trailing corner, or as the icon of setAttentionIcon(limn.graphics.Icon) when there is one, and a panel that knows the state may bring the icon out from among its hidden ones.
      Parameters:
      attention - whether to ask
      Returns:
      this tray
    • isAttention

      public boolean isAttention()
      Returns:
      whether the icon asks for attention
    • setAttentionIcon

      public Tray setAttentionIcon(@Nullable Icon icon)
      Sets the icon shown while the tray asks for attention, in place of the icon with a dot.
      Parameters:
      icon - the icon, shown as it is, or null for the dot
      Returns:
      this tray
    • setLayoutDirection

      public Tray setLayoutDirection(LayoutDirection direction)
      Sets the direction the menu is laid out in, where the system takes one; left to right until set.
      Parameters:
      direction - the direction
      Returns:
      this tray
    • isAvailable

      public boolean isAvailable()
      Returns:
      whether the system took the icon: false on a desktop with no tray, before the tray has an icon, and once it is disposed. Not whether somebody sees it
    • onAvailabilityChange

      public Subscription onAvailabilityChange(Runnable listener)
      Subscribes to isAvailable() changing, which it does when a desktop's tray appears or goes while the application runs.
      Parameters:
      listener - what to run after a change
      Returns:
      a handle that unsubscribes
    • dispose

      public void dispose()
      Takes the icon away. A disposed tray ignores every call; its identifier is free again.