138 lines
3.7 KiB
Markdown
138 lines
3.7 KiB
Markdown
# racket-tray
|
|
|
|
A small cross-platform system tray API for Racket GUI applications.
|
|
|
|
Version 0.1.1 contains native backends for Windows, Linux and macOS:
|
|
|
|
- Windows uses `Shell_NotifyIconW` and `SetWindowSubclass`.
|
|
- Linux uses Ayatana AppIndicator and GTK3.
|
|
- macOS uses AppKit `NSStatusItem` and `NSMenu` through Racket's Objective-C FFI.
|
|
|
|
The public API and symbolic menu actions are the same on every platform.
|
|
|
|
```racket
|
|
#lang racket/gui
|
|
|
|
(require racket-tray)
|
|
|
|
(define tray-frame%
|
|
(class frame%
|
|
(super-new [label "Tray example"]
|
|
[width 400]
|
|
[height 250])
|
|
|
|
;; Close [X] to the tray instead of destroying the frame.
|
|
(define/override (on-close)
|
|
(send this show #f))))
|
|
|
|
(define frame (new tray-frame%))
|
|
|
|
(define (show-frame)
|
|
(send frame show #t)
|
|
(when (send frame is-iconized?)
|
|
(send frame iconize #f)))
|
|
|
|
(define (tray-action action)
|
|
(case action
|
|
[(open)
|
|
(show-frame)]
|
|
[(exit)
|
|
(tray-close tray)
|
|
(exit)]))
|
|
|
|
(define tray
|
|
(mk-tray frame
|
|
"example.png"
|
|
(list tray-action 'open)
|
|
#:hide-on-minimize? #t))
|
|
|
|
(tray-set-menu!
|
|
tray
|
|
(list
|
|
(list 'open "Open")
|
|
'separator
|
|
(list 'exit "Exit")))
|
|
|
|
(send frame show #t)
|
|
```
|
|
|
|
## Action and menu model
|
|
|
|
The third argument of `mk-tray` is mandatory and has the form:
|
|
|
|
```racket
|
|
(list callback default-action-id)
|
|
```
|
|
|
|
`callback` accepts one symbol. `default-action-id` is a symbol that must also
|
|
occur in the menu installed by `tray-set-menu!`.
|
|
|
|
A menu contains `(list action-id label)` entries and separators:
|
|
|
|
```racket
|
|
(list
|
|
(list 'open "Open")
|
|
'separator
|
|
(list 'exit "Exit"))
|
|
```
|
|
|
|
Choosing a menu item calls the callback with its action identifier. In the
|
|
example above, choosing `Open` calls `(tray-action 'open)` and choosing `Exit`
|
|
calls `(tray-action 'exit)`.
|
|
|
|
Direct tray activation is platform dependent:
|
|
|
|
- **Windows:** a normal activation invokes the configured default action.
|
|
The context-menu gesture opens the tray menu.
|
|
- **Linux with Ayatana AppIndicator 0.6 or newer:** a primary activation can
|
|
invoke the configured default action. The context-menu gesture opens the
|
|
menu.
|
|
- **Linux with Ayatana AppIndicator 0.5.x:** primary activation opens the menu;
|
|
the older library has no primary-activation callback.
|
|
- **macOS:** the native status item opens its menu. Menu selections invoke the
|
|
symbolic callback. The default id remains part of the common API but is not
|
|
invoked directly by an `NSStatusItem` with an attached menu.
|
|
|
|
## Hide on minimize
|
|
|
|
`#:hide-on-minimize?` is implemented in the platform-independent Racket layer.
|
|
It periodically checks `frame%`'s public `is-iconized?` method and hides the
|
|
frame when it becomes iconized. No Win32, GTK or AppKit minimize hook is used.
|
|
|
|
Closing a frame to the tray is separate because Racket already has the public
|
|
`on-close` callback. Override it and call `(send this show #f)` as shown above.
|
|
|
|
## Icons
|
|
|
|
`example.png` is suitable on all three supported platforms. Windows also
|
|
accepts `.ico`; PNG alpha transparency is converted to a native `HICON` by the
|
|
Windows backend. Linux passes an absolute image path to AppIndicator. macOS
|
|
loads the image with `NSImage`.
|
|
|
|
## Linux runtime dependency
|
|
|
|
Linux requires the Ayatana AppIndicator GTK3 runtime library. `racket-tray`
|
|
loads the native shared library dynamically. If it is missing, `mk-tray`
|
|
reports the dependency and the appropriate package commands instead of
|
|
exposing a raw FFI loader error.
|
|
|
|
Debian/Ubuntu:
|
|
|
|
```text
|
|
sudo apt install libayatana-appindicator3-1
|
|
```
|
|
|
|
Fedora:
|
|
|
|
```text
|
|
sudo dnf install libayatana-appindicator-gtk3
|
|
```
|
|
|
|
Arch Linux:
|
|
|
|
```text
|
|
sudo pacman -S libayatana-appindicator
|
|
```
|
|
|
|
No additional native dependency is required by the Windows or macOS backend.
|