Update notifications with libnotify

18th October 2020

The libnotify library allows you to send desktop notifications to a notification daemon commonly used under Linux. In particular, it offers the notify-send command, which displays a notification directly on the desktop:

notify-send "Notification title" "Notification description"

But what if you want to update or delete a notification already displayed? If this command is executed several times, the notifications pile up rather than updating the one that has just been sent.

The manual (man notify-send) shows us that the options are rather short and do not allow us to expect much:

-?, --help
-u, --urgency=LEVEL
-t, --expire-time=TIME
-i, --icon=ICON[,ICON...]
-c, --category=TYPE[,TYPE...]
-h, --hint=TYPE:NAME:VALUE

We will therefore have to move away from it and return to the fundamentals. notify-send simply sends information as defined in the “Desktop Notifications” specification, which we will be able to do ourselves with gdbus.

The following function will allow us to obtain the same result as before:

gdbus call \
    --session \
    --dest org.freedesktop.Notifications \
    --object-path /org/freedesktop/Notifications \
    --method org.freedesktop.Notifications.Notify \
    "identifier" \
    "1" \
    "" \
    "Notification title" \
    "Notification description" \
    "[]" \
    "{}" \
    "2000"

The second identifier (here 1) concerns the id of the notification we wish to replace, we will come back to this shortly. The next identifier allows you to define an icon. "[]" allows you to define actions, "{}" to define hints, and finally the last argument 2000 presents the time during which the notification must remain visible (in milliseconds).

Once this command is executed, the system returns a response that looks like :

(uint32 13,)

This number, here 13, is the id of the notification that we will be able to replace.

This means that the following command will not create a new notification, but will replace the one we just created:

gdbus call \
    --session \
    --dest org.freedesktop.Notifications \
    --object-path /org/freedesktop/Notifications \
    --method org.freedesktop.Notifications.Notify \
    "identifier" \
    "13" \
    "" \
    "My updated title" \
    "My updated description" \
    "[]" \
    "{}" \
    "2000"

All that remains is to automatically retrieve this number, and to reinject it as an argument in our function.

To retrieve it, filter the previous function with :

| sed 's/[^ ]* //; s/,.//'

We could then store the number in a temporary file, for example with > /tmp/.notif. However, to avoid using the hard disk or the SSD, let’s go directly to the RAM :

> ${XDG_RUNTIME_DIR}/.notif

This number can be initiated at startup with :

echo '1' > ${XDG_RUNTIME_DIR}/.notif

It is then easily retrieved with:

notif=`cat ${XDG_RUNTIME_DIR}/.notif`

The following code, executed several times, will then update the notification :

notif=`cat ${XDG_RUNTIME_DIR}/.notif`
gdbus call \
    --session \
    --dest org.freedesktop.Notifications \
    --object-path /org/freedesktop/Notifications \
    --method org.freedesktop.Notifications.Notify \
    "identifier" \
    "`echo $notif`" \
    "" \
    "My updated title" \
    "My updated description" \
    "[]" \
    "{}" \
    "2000" \
| sed 's/[^ ]* //; s/,.//' > ${XDG_RUNTIME_DIR}/.notif