notify
@profile(t1);
import notify from "notify";
import io from "io";
pub fn main() -> i32 {
notify.set_app("com.example.chat", "Example Chat");
let id: notify.NoteId = notify.show(notify.Note {
title: "Aino";
body: "On my way";
tag: "chat-7";
}) or {
io.println("no notification: {err}");
return 1;
};
io.println("shown as {id.v}");
return 0;
}A note appears in the system’s notification area under your program’s name, and stays in the notification centre until the user or your program takes it away.
| Function | Does |
|---|---|
notify.set_app(id, name) | Your program’s id ("com.example.chat") and the name its notes show. Call it once, at the start, before anything else; without it the id is tape.<program> and the name the program’s file name. On macOS the app bundle’s are used. On Windows it also gets your program ready for clicks on its notes, also the click that started it (below) |
notify.show(note) -> NoteId or NotifyError | Shows the note |
notify.withdraw(id) -> void or NotifyError | Takes it off the screen and out of the notification centre (nothing if it is gone) |
notify.withdraw_tag(tag) -> void or NotifyError | The same for every note with the tag |
notify.badge(n) -> void or NotifyError | The unread count on your program: the Dock icon on macOS, the taskbar button of your ui window on Windows; 0 takes it off |
notify.handle() -> i64 | What ui.Watch waits on for the user’s clicks and dismissals (-1 where there are none to wait for) |
notify.next() -> ?NoteEvent | The oldest click or dismissal not yet taken, or null |
Note:
| Field | Is |
|---|---|
title: []const u8 | One line, not empty |
body: []const u8 = "" | The text under it |
icon: *gfx.Surface = null | A picture beside the text; null: your program’s icon |
tag: []const u8 = "" | What the note is about ("chat-7"), up to notify.MAX_TAG (64) bytes: withdraw_tag uses it and the note’s events carry it |
silent: bool = false | No sound |
sender: []const u8 = "" | Who a message is from: a messenger’s note (below) |
avatar: *gfx.Surface = null | The sender’s picture; only with a sender |
An empty title, a tag that is too long or a negative badge trap.
A note stays until the user closes it or your program withdraws it. To
take a conversation’s notes away when its chat is read, or when the user
closes one of them, call notify.withdraw_tag(tag). On macOS, don’t
withdraw a conversation’s notes just before you show its next one: the
new note then plays its sound but shows no banner. Withdraw them when the
chat is read instead.
Who a message is from
A messenger’s note names its sender, with their picture:
notify.show(notify.Note {
title: "Aino";
body: "Lunch at 12?";
tag: "chat-aino";
sender: "Aino";
avatar: &aino_avatar;
}) or { io.println("no notification: {err}"); };The avatar is shown the way the system shows a person:
- Windows: in the place of your app’s logo, cropped round. An
icongiven as well is shown under the text. - macOS: on the left of the note, with your app’s icon as a small badge on it, as a communication notification. That needs the Communication Notifications entitlement in your app’s signature (a Developer ID build with a provisioning profile that has it). Without it the avatar is shown as a picture on the right, and your app’s icon stays on the left.
- Linux: as the note’s image (an
icongiven as well is not shown).
Clicks and dismissals
When the user clicks a note, or closes it, your program gets a
NoteEvent { action, id, tag } (action is NoteAction.Clicked or
NoteAction.Dismissed). They arrive while ui.run runs: put a
ui.Watch on notify.handle() and take them all in its event.
@profile(t1);
import notify from "notify";
import ui from "ui";
import io from "io";
fn on_notes(h: i64) {
while (true) {
let e: ?notify.NoteEvent = notify.next();
if (e == null) { break; }
if (e!.action == notify.NoteAction.Clicked) {
io.println("open {e!.tag}");
notify.withdraw_tag(e!.tag) or { };
}
}
}
component App {
view {
ui.Watch { handle: notify.handle(); on_ready: on_notes; }
}
}A note that times out is not dismissed: it waits in the notification centre, and a click there later still comes, while your program runs.
A click lets your program come to the front: call ui.activate_window()
in its handler to bring your window forward.
A click after your program exited
On Windows, a click on one of your notes in the notification centre
after your program exited starts it again (a program built with tape build; under tape run it doesn’t). It starts as usual, with one more
argument, -Embedding, which your program should ignore. Once it calls
notify.set_app, the click is waiting as a Clicked event: its tag is
the note’s, and its id.v is 0, since the note was the earlier run’s.
So call set_app early, and watch notify.handle() as above.
If your program is still running, the click goes to it and no second copy
starts, as with launch.claim. Elsewhere a click after exit
does nothing yet.
Errors
NotifyError:
| Variant | When |
|---|---|
PermissionDenied | The user turned your program’s notifications off |
Unsupported | The system shows your program none: Linux without a notification server, macOS outside an app bundle (tape run, a bare executable) |
NoWindow | badge on Windows with no ui window open |
Failed | The system refused otherwise |
OutOfMemory | Out of memory |
Platforms
- Windows: toasts.
set_app’s id is your AppUserModelID; it is registered for the current user so a program without a Start-menu shortcut can show toasts, and it groups your taskbar button. A built program is also registered as its notes’ activator, for the current user:HKEY_CURRENT_USER\Software\Classes\CLSID\{...}names the executable’s path (the{...}is the same for every run of the same app id), so move or rebuild the program and its next run registers the new path. The badge is a red disc with the count over the taskbar button. - macOS: the Notification Centre, for a program in an app bundle. The first call asks the user to allow notifications; until they answer, notes are shown as the system decides.
- Linux: the desktop’s notification server (
org.freedesktop.Notifications) on the session bus, throughdbus’s shared connection: a click on the note and a dismissal by the user are events, as elsewhere, andhandle()is ready while they wait (also when one came while a file dialog or a keyring prompt had the program waiting). The badge is the Unity launcher signal, shown by Ubuntu’s dock, Dash to Dock and KDE Plasma on the launcher of the desktop file named after your app id (set_app); where no dock listens it shows nothing.Unsupportedwithout a session bus or a notification server.
The library is shell100 (.dll, .dylib, .so), next to tape;
tape build copies it beside your program.
Last modified: