NotificationDevelopmentGuidelines
Contents
How to use libnotify (and be a good citizen)
To use libnotify correctly - first and foremost - means to stick to the f.d.o specification and query for notification-daemon capabilities before using them. Don't just assume they are there. Also checking a notifications-daemon's name is a good way to branch off to dedicated code-paths catering for one or the other. Complete self-contained sourcecode for C, Python and C# you find further down the page.
- C code-fragments for querying capabilities
gboolean g_capabilities[CAP_MAX] = {FALSE, /* actions */ FALSE, /* body */ FALSE, /* body-hyperlinks */ FALSE, /* body-imges */ FALSE, /* body-markup */ FALSE, /* icon-multi */ FALSE, /* icon-static */ FALSE, /* sound */ FALSE, /* image/svg+xml */ FALSE /* append-hint */}; ... void set_cap (gpointer data, gpointer user_data) { /* test for "actions" */ if (!g_strcmp0 ("actions", (gchar*) data)) g_capabilities[CAP_ACTIONS] = TRUE; /* test for "body" */ if (!g_strcmp0 ("body", (gchar*) data)) g_capabilities[CAP_BODY] = TRUE; ... /* test for "append" */ if (!g_strcmp0 ("append", (gchar*) data)) g_capabilities[CAP_APPEND] = TRUE; } ... void walk_caps_list () { GList* caps_list; caps_list = notify_get_server_caps (); if (caps_list) { g_list_foreach (caps_list, set_cap, NULL); g_list_foreach (caps_list, (GFunc) g_free, NULL); g_list_free (caps_list); } } ... int main (int argc, char** argv) { ... walk_caps_list (); ... if (g_capabilities[CAP_APPEND]) { /* you're save to make use of the append hint */ ... } else { /* do _not_ use the append hint */ ... } ... }
- C code-fragments for checking name of daemon
gchar* name; gchar* vendor; gchar* version; gchar* spec_version; notify_get_server_info (&name, &vendor, &version, &spec_version); ... if (!g_strcmp0 ("notify-osd", name)) g_print ("You're very likely running Ubuntu 9.04.\n"); if (!g_strcmp0 ("notification-daemon", name)) g_print ("Perhaps you're running Fedora or an earlier version of Ubuntu."); ... g_free ((gpointer) name); g_free ((gpointer) vendor); g_free ((gpointer) version); g_free ((gpointer) spec_version);
- Python code-fragments for querying capabilities
- Python code-fragments for checking name of daemon
- C# code-fragments for querying capabilities
- C# code-fragments for checking name of daemon
Target developer-audience
- C
Example code from VLC (broken):
notify_notification_add_action(notification, "previous", _("Previous"), Prev, (gpointer*) p_intf, NULL); notify_notification_add_action(notification, "next", _("Next"), Next, (gpointer*) p_intf, NULL );
Example code (fixed):
caps = notify_get_server_caps(); if(caps != NULL) { for(c = caps; c != NULL; c = c->next) { if(strcmp((char*)c->data, "actions") == 0 ) { supports_actions = TRUE; break; } } g_list_foreach(caps, (GFunc)g_free, NULL); g_list_free(caps); } /* Adds previous and next buttons in the notification if actions are supported. */ if(supports_actions) { notify_notification_add_action(notification, "previous", _("Previous"), Prev, (gpointer*) p_intf, NULL); notify_notification_add_action(notification, "next", _("Next"), Next, (gpointer*) p_intf, NULL); }
- Python
- C#:
In C# you should check the existence of "actions" in Notifications.Global.Capabilities. This is easy with Array.IndexOf such as:
bool actions_supported = Notifications.Global.Capabilities != null && Array.IndexOf(Notifications.Global.Capabilities, "actions") > -1
Example code from Banshee:
Notification nf = new Notification (Catalog.GetString("Now Playing"), message, image, notif_area.Widget); if (interface_action_service.PlaybackActions["NextAction"].Sensitive) { nf.AddAction("skip-song", Catalog.GetString("Skip this item"), OnSongSkipped); } nf.Show();
After notification fixes:
Notification nf = new Notification (Catalog.GetString ("Now Playing"), message, image, notif_area.Widget); bool actions_supported = Notifications.Global.Capabilities != null && Array.IndexOf (Notifications.Global.Capabilities, "actions") > -1; if (interface_action_service.PlaybackActions["NextAction"].Sensitive && actions_supported) { nf.AddAction ("skip-song", Catalog.GetString("Skip this item"), OnSongSkipped); } nf.Show ();
Layout cases (with examples in C, Python and C#)
Everything not listed as a valid layout will lead to a "no-layout"-case (results in an empty notification-bubble). Also using non-existing (stock-)icon-names results in empty notification-bubbles. Common caues for the latter could be that the user has not set "Human" as the icon-theme and a notification is trying to use one of the new icon-name (see icons). The comment header of each sourcecode example contains compilation and run instructions. NOTE: The C#-examples don't format and display in thie MoinMoin wiki. You can only download them directly to your harddisk. Sorry for the inconvenience!
Icon-Summary-Body
example: IM-message
Icon-Summary
example: Wifi connection lost
Summary-Body
example: a very simple notification-bubble
Summary-only
This layout-case works, but is strongly discouraged. Avoid it if you can.
How to use the append-hint
Current configuration does not allow embedding of the file append-hint-example.ogg because of its mimetype audio/ogg.: append-hint-example.ogg
(Gee, I cannot get this ogg/theora-screencast correctly embedded. So much for supporting open standards.)
For IM-clients (like pidgin) you can use the append-hint ("append").
How to update an existing notification-bubble
code
How do I get these slick icons
The user has to be using the Human icon-theme. Have a look at the icon-matrix. Or if a different icon-theme is selected, default icons satisfying the new icon-names are used. These will look different of course. The available icon-names are...
- notification-audio-next
- notification-audio-play
- notification-audio-previous
- notification-audio-volume-high
- notification-audio-volume-low
- notification-audio-volume-medium
- notification-audio-volume-muted
- notification-audio-volume-off
- notification-battery-low
- notification-device-eject
- notification-device-firewire
- notification-display-brightness-full
- notification-display-brightness-high
- notification-display-brightness-low
- notification-display-brightness-medium
- notification-display-brightness-off
- notification-GSM-3G-full
- notification-GSM-3G-high
- notification-GSM-3G-low
- notification-GSM-3G-medium
- notification-GSM-3G-none
- notification-GSM-disconnected
- notification-GSM-EDGE-full
- notification-GSM-EDGE-high
- notification-GSM-EDGE-low
- notification-GSM-EDGE-medium
- notification-GSM-EDGE-none
- notification-GSM-full
- notification-GSM-H-full
- notification-GSM-H-high
- notification-GSM-high
- notification-GSM-H-low
- notification-GSM-H-medium
- notification-GSM-H-none
- notification-GSM-low
- notification-GSM-medium
- notification-GSM-none
- notification-keyboard-brightness-full
- notification-keyboard-brightness-high
- notification-keyboard-brightness-low
- notification-keyboard-brightness-medium
- notification-keyboard-brightness-off
- notification-message-email
- notification-message-IM
- notification-network-ethernet-connected
- notification-network-ethernet-disconnected
- notification-network-wireless-disconnected
- notification-network-wireless-full
- notification-network-wireless-high
- notification-network-wireless-low
- notification-network-wireless-medium
- notification-network-wireless-none
- notification-power-disconnected
... and are located under /usr/share/icons/Human/scalable/status. Until symlinks or updated icons for other icon-themes are installed (provided by updated packages) using these without the icon-theme being set to Human will fail to display the intended icon. The result is an empty notification-bubble. You can still of course use full file paths to .svg/.png/.jpg icons.
What will get you burnt
Do not use any of these...
- expire-timeout
- actions
- html-markup (read: URL) in you summary- or body-text
If you do you'll either get a fallback GTK+-dialog or notification-bubble with no contents at all.