1e97716636
plugins/window replaces the window_manager fork on every desktop. Changelog: Tray hotkeys, node delays and a delay test
78 lines
3.1 KiB
Markdown
78 lines
3.1 KiB
Markdown
# tray
|
|
|
|
System tray integration for FlClash on Linux, macOS and Windows.
|
|
|
|
## API
|
|
|
|
The plugin owns call ordering, idempotency, call serialization and unchanged-payload suppression.
|
|
Callers declare the desired tray state; they never sequence platform calls themselves.
|
|
|
|
```dart
|
|
await Tray.instance.show(
|
|
TraySpec(
|
|
icon: TrayIcon.asset('assets/images/tray/unix/status_1.png', isTemplate: true),
|
|
toolTip: 'FlClash',
|
|
menu: [
|
|
TrayMenuAction(label: 'Show', onSelected: showWindow),
|
|
const TrayMenuSeparator(),
|
|
TrayMenuCheckbox(label: 'TUN', checked: true, onSelected: toggleTun),
|
|
TrayMenuSubmenu(label: 'Proxy', items: proxyItems),
|
|
],
|
|
),
|
|
);
|
|
|
|
await Tray.instance.setTitle('↑ 1.2 MB/s');
|
|
await Tray.instance.hide();
|
|
```
|
|
|
|
- `show` creates the tray on first call and reconciles it afterwards. Re-sending a structurally
|
|
identical `TraySpec` performs no platform call, so callbacks may be rebuilt freely.
|
|
- `setTitle` is the incremental path for high-frequency text. It is a no-op where
|
|
`capabilities.title` is false, and while no tray is visible.
|
|
- `hide` is idempotent and returns native state to "`show` was never called", so a later `show`
|
|
rebuilds the tray from scratch.
|
|
- `openMenu` is a no-op where `capabilities.menuControl` is false.
|
|
|
|
`TrayIcon.asset` names a bundled PNG and follows Flutter's resolution-aware layout: every
|
|
`2.0x/`, `3.0x/`, `4.0x/` sibling that exists is loaded too. macOS receives them all as
|
|
representations of one `size`-point image; Linux is handed the largest raster on disk and lets the
|
|
indicator scale it; Windows loads the path as-is, so point it at a multi-size `.ico` instead.
|
|
|
|
Menu item ids are assigned by pre-order position, so an unchanged menu serializes identically across
|
|
rebuilds and click dispatch stays stable while a menu is open.
|
|
|
|
Actions, checkboxes and submenus take an optional `detail`, secondary text shown after the label, such as
|
|
a shortcut or a measured latency:
|
|
|
|
| macOS | Windows | Linux |
|
|
| --- | --- | --- |
|
|
| right-aligned column in the color of a native key equivalent | the menu's accelerator column | appended in parentheses |
|
|
|
|
AppIndicator menus travel over dbusmenu, which carries no column for free text, hence the Linux fallback.
|
|
|
|
## Events
|
|
|
|
`Tray.instance.events` is a broadcast stream of `TrayIconActivated`, `TrayMenuRequested` and
|
|
`TrayMenuItemSelected`. Per-item `onSelected` callbacks fire before the corresponding stream event.
|
|
On Windows a left click is `TrayIconActivated` and a right click `TrayMenuRequested`; macOS opens the
|
|
menu from either button, as status items do there, so it only sends `TrayMenuRequested`.
|
|
|
|
## Capabilities
|
|
|
|
`Tray.instance.capabilities` reports what the current platform can do, so callers branch on ability
|
|
rather than on `Platform.isX`.
|
|
|
|
| | macOS | Windows | Linux |
|
|
| --- | --- | --- | --- |
|
|
| `title` | yes | no | yes |
|
|
| `toolTip` | yes | yes | yes |
|
|
| `iconEvents` | yes | yes | no |
|
|
| `menuControl` | yes | yes | no |
|
|
|
|
Linux runs on AppIndicator/StatusNotifierItem, where the desktop shell owns the menu; the application
|
|
cannot receive icon clicks or open the menu itself.
|
|
|
|
## Linux requirements
|
|
|
|
`libayatana-appindicator3-dev`, or `libappindicator3-dev` as a fallback.
|