NotificationDevelopmentGuidelines

Differences between revisions 1 and 21 (spanning 20 versions)
Revision 1 as of 2009-02-20 17:15:20
Size: 1360
Editor: dslb-084-063-099-000
Comment:
Revision 21 as of 2009-02-26 01:04:22
Size: 10329
Editor: dslb-084-063-099-000
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
This is a place holder, please don't mess around with this

== How to use libnotify ==
And comply to the new jaunty notifications spec at the same time

== How to be a good citizen ==
Use all of libnotify's API ... '''query''' a notification-server's name and capabilities and don't just assume anything. If you don't -> no ponies for you
<<TableOfContents>>

== 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 [[#examples|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
{{{

}}}
Line 11: Line 132:

'''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);
}
}}}

Line 12: Line 173:
 * C#

== Layout cases ==
 * Icon-Summary-Body - e.g. IM-message

 * Icon-Summary - e.g. Wifi connection lost

 * Icon-only - e.g. eject CD

 * Summary-Body - e.g. bla

 * Summary-only - works but is discouraged

 * Icon-Value - e.g. keyboard-brightness

Everything else will give you an empty bubble (no-layout-case) or cause an ugly fallback-dialog done in GTK+ if non-supported capabilities are used

== Synchronous vs. Asynchronous notifications ==
bla
 * 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 ();
}}}

<<Anchor(examples)>>

== 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|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 ===
{{attachment:icon-summary-body.png}}<<BR>>
example: IM-message
 * [[attachment:icon-summary-body.c|example in C]]
 * [[attachment:icon-summary-body.py|example in Python]]
 * [[attachment:icon-summary-body.cs|example in C#]]

=== Icon-Summary ===
{{attachment:icon-summary.png}}<<BR>>
example: Wifi connection lost
 * [[attachment:icon-summary.c|example in C]]
 * [[attachment:icon-summary.py|example in Python]]
 * [[attachment:icon-summary.cs|example in C#]]

=== Summary-Body ===
{{attachment:summary-body.png}}<<BR>>
example: a very simple notification-bubble
 * [[attachment:summary-body.c|example in C]]
 * [[attachment:summary-body.py|example in Python]]
 * [[attachment:summary-body.cs|example in C#]]

=== Summary-only ===
{{attachment:summary-only.png}}<<BR>>
This layout-case works, but is strongly discouraged. Avoid it if you can.
 * [[attachment:summary-only.c|example in C]]
 * [[attachment:summary-only.py|example in Python]]
 * [[attachment:summary-only.cs|example in C#]]
Line 33: Line 243:
You can use a special hint to...

== How to use the value-hint ==
For notifications like the volume-display...
Under/Overshoot
<<EmbedObject(append-hint-example.ogg)>><<BR>>
(Gee, I cannot get this ogg/theora-screencast correctly embedded. So much for supporting open standards.)<<BR>>
[[{{attachment:append-hint-example.ogg}}|{{attachment:small_append-hint-example_ogg.png}}]]<<BR>>
For IM-clients (like pidgin) you can use the append-hint ("append").
 * [[attachment:append-hint-example.c|example in C]]
 * [[attachment:append-hint-example.py|example in Python]]
 * [[attachment:append-hint-example.cs|example in C#]]

== How to update an existing notification-bubble ==
code

<<Anchor(icons)>>
Line 40: Line 257:
The use has to be using the Human icon-theme. The available icon-names are ... (might add the icon-matrix of the design team here). Otherwise GNOME's fallback icons are used The user has to be using the Human icon-theme. Have a look at the [[https://wiki.ubuntu.com/NotifyOSD#Icon|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 [[file:///usr/share/icons/Human/scalable/status|/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.
Line 43: Line 314:
 * timeout Do not use any of these...
 * expire-timeout
Line 45: Line 317:
 * html-markup in you summary- or body-text  * 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.

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

icon-summary-body.png
example: IM-message

Icon-Summary

icon-summary.png
example: Wifi connection lost

Summary-Body

summary-body.png
example: a very simple notification-bubble

Summary-only

summary-only.png
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.)
{{attachment:append-hint-example.ogg}}
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.

NotificationDevelopmentGuidelines (last edited 2010-08-25 15:53:12 by 121)