Racket Tray
1 Creating a Tray Icon
mk-tray
2 Tray Actions and Menus
tray-set-menu!
3 Changing and Closing a Tray Icon
tray-set-icon!
tray-close
4 Closing a Window to the Tray
5 Platform Behaviour
6 Linux Runtime Dependency
7 Example
9.3

Racket Tray🔗ℹ

Hans Dijkema <hans@dijkewijk.nl>

 (require racket-tray) package: racket-tray

Racket Tray provides a small cross-platform system tray API for Racket GUI applications. Version 0.1.1 contains native backends for Windows, Linux and macOS. The public API uses symbolic actions so application code does not depend on a platform-specific tray menu implementation.

1 Creating a Tray Icon🔗ℹ

procedure

(mk-tray frame    
  icon-file    
  action-spec    
  [#:hide-on-minimize? hide-on-minimize?])  any/c
  frame : (is-a?/c top-level-window<%>)
  icon-file : path-string?
  action-spec : list?
  hide-on-minimize? : boolean? = #f
Creates a tray icon associated with frame. A frame% or dialog% is suitable.

action-spec is mandatory and must contain exactly two values: (list callback default-action-id). callback must accept one argument and default-action-id must be a symbol. Every action generated by the tray is passed to callback as a symbol.

The default action must occur in the menu later installed with tray-set-menu!. Windows maps normal tray activation to this action. Ayatana AppIndicator 0.6 or newer can do the same on Linux. Older AppIndicator 0.5.x implementations open the menu on primary activation instead. A native macOS status item with an attached menu also opens its menu instead of invoking the default action directly.

When hide-on-minimize? is true, Racket Tray periodically checks is-iconized?. When the frame changes to the iconized state it is hidden with (send frame show #f). This implementation is entirely platform independent and does not use a Win32, GTK or AppKit minimize hook.

The returned value represents the tray icon and is accepted by the other procedures in this library.

2 Tray Actions and Menus🔗ℹ

procedure

(tray-set-menu! tray menu-spec)  void?

  tray : any/c
  menu-spec : list?
Sets the menu for tray. An actionable entry has the form (list action-id label), where action-id is a symbol and label is a string. 'separator or #f creates a separator. Action identifiers must be unique and the menu must contain the default action supplied to mk-tray.

For example:

(tray-set-menu!
 tray
 (list
  (list 'open "Open")
  'separator
  (list 'exit "Exit")))

Choosing "Open" invokes the callback as (callback 'open). The same callback receives every other menu action.

3 Changing and Closing a Tray Icon🔗ℹ

procedure

(tray-set-icon! tray icon-file)  void?

  tray : any/c
  icon-file : path-string?
Replaces the image of tray. PNG files can be used on all supported platforms. The Windows backend also accepts ICO files.

procedure

(tray-close tray)  void?

  tray : any/c
Removes tray, stops its optional portable minimize watcher and releases the native resources owned by the active platform backend. Calling this procedure does not close the associated Racket window.

4 Closing a Window to the Tray🔗ℹ

Racket already provides on-close for handling the close button of a frame. A tray application normally overrides it and hides the frame:

(define tray-frame%
  (class frame%
    (super-new)
 
    (define/override (on-close)
      (send this show #f))))

This is intentionally separate from #:hide-on-minimize?. Closing a window already has a portable public Racket callback; minimizing does not.

5 Platform Behaviour🔗ℹ

On Windows, the backend uses the native HWND returned by Racket GUI, Shell_NotifyIconW and SetWindowSubclass. A normal tray activation invokes the configured default action. No additional native library is needed.

On Linux, the backend uses Ayatana AppIndicator and GTK3. AppIndicator 0.6 or newer provides primary activation, which Racket Tray maps to the default action. With AppIndicator 0.5.x, primary activation opens the menu instead. Menu choices have the same symbolic callback behaviour on both library versions.

On macOS, the backend uses AppKit NSStatusItem, NSStatusBarButton and NSMenu through Racket’s Objective-C FFI. A status item with an attached menu opens that menu when activated. Menu choices invoke the common symbolic callback. No additional native library is needed.

6 Linux Runtime Dependency🔗ℹ

The Linux backend requires the Ayatana AppIndicator GTK3 runtime library. If it cannot be loaded, mk-tray reports the missing dependency and suggests the native package to install.

Debian and Ubuntu use libayatana-appindicator3-1. Fedora uses libayatana-appindicator-gtk3. Arch Linux uses libayatana-appindicator.

7 Example🔗ℹ

The package contains "examples/simple.rkt". It demonstrates symbolic tray actions, hiding a frame on minimize and close, restoring it from the tray, and terminating the application only through the 'exit action.