136 lines
5.1 KiB
Racket
136 lines
5.1 KiB
Racket
#lang scribble/manual
|
|
|
|
@(require (for-label racket/base
|
|
racket/class
|
|
racket/gui/base
|
|
racket-tray))
|
|
|
|
@title{Racket Tray}
|
|
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
|
|
|
|
@defmodule[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.
|
|
|
|
@section{Creating a Tray Icon}
|
|
|
|
@defproc[(mk-tray [frame (is-a?/c top-level-window<%>)]
|
|
[icon-file path-string?]
|
|
[action-spec list?]
|
|
[#:hide-on-minimize? hide-on-minimize? boolean? #f])
|
|
any/c]{
|
|
Creates a tray icon associated with @racket[frame]. A @racket[frame%] or
|
|
@racket[dialog%] is suitable.
|
|
|
|
@racket[action-spec] is mandatory and must contain exactly two values:
|
|
@racket[(list callback default-action-id)]. @racket[callback] must accept one
|
|
argument and @racket[default-action-id] must be a symbol. Every action generated
|
|
by the tray is passed to @racket[callback] as a symbol.
|
|
|
|
The default action must occur in the menu later installed with
|
|
@racket[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 @racket[hide-on-minimize?] is true, Racket Tray periodically checks
|
|
@method[frame% is-iconized?]. When the frame changes to the iconized state it
|
|
is hidden with @racket[(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.
|
|
}
|
|
|
|
@section{Tray Actions and Menus}
|
|
|
|
@defproc[(tray-set-menu! [tray any/c]
|
|
[menu-spec list?]) void?]{
|
|
Sets the menu for @racket[tray]. An actionable entry has the form
|
|
@racket[(list action-id label)], where @racket[action-id] is a symbol and
|
|
@racket[label] is a string. @racket['separator] or @racket[#f] creates a
|
|
separator. Action identifiers must be unique and the menu must contain the
|
|
default action supplied to @racket[mk-tray].
|
|
|
|
For example:
|
|
|
|
@racketblock[
|
|
(tray-set-menu!
|
|
tray
|
|
(list
|
|
(list 'open "Open")
|
|
'separator
|
|
(list 'exit "Exit")))
|
|
]
|
|
|
|
Choosing @racket["Open"] invokes the callback as @racket[(callback 'open)]. The
|
|
same callback receives every other menu action.
|
|
}
|
|
|
|
@section{Changing and Closing a Tray Icon}
|
|
|
|
@defproc[(tray-set-icon! [tray any/c]
|
|
[icon-file path-string?]) void?]{
|
|
Replaces the image of @racket[tray]. PNG files can be used on all supported
|
|
platforms. The Windows backend also accepts ICO files.
|
|
}
|
|
|
|
@defproc[(tray-close [tray any/c]) void?]{
|
|
Removes @racket[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.
|
|
}
|
|
|
|
@section{Closing a Window to the Tray}
|
|
|
|
Racket already provides @method[frame% on-close] for handling the close button
|
|
of a frame. A tray application normally overrides it and hides the frame:
|
|
|
|
@racketblock[
|
|
(define tray-frame%
|
|
(class frame%
|
|
(super-new)
|
|
|
|
(define/override (on-close)
|
|
(send this show #f))))
|
|
]
|
|
|
|
This is intentionally separate from @racket[#:hide-on-minimize?]. Closing a
|
|
window already has a portable public Racket callback; minimizing does not.
|
|
|
|
@section{Platform Behaviour}
|
|
|
|
On Windows, the backend uses the native HWND returned by Racket GUI,
|
|
@tt{Shell_NotifyIconW} and @tt{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 @tt{NSStatusItem}, @tt{NSStatusBarButton} and
|
|
@tt{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.
|
|
|
|
@section{Linux Runtime Dependency}
|
|
|
|
The Linux backend requires the Ayatana AppIndicator GTK3 runtime library. If it
|
|
cannot be loaded, @racket[mk-tray] reports the missing dependency and suggests
|
|
the native package to install.
|
|
|
|
Debian and Ubuntu use @tt{libayatana-appindicator3-1}. Fedora uses
|
|
@tt{libayatana-appindicator-gtk3}. Arch Linux uses
|
|
@tt{libayatana-appindicator}.
|
|
|
|
@section{Example}
|
|
|
|
The package contains @filepath{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 @racket['exit] action.
|