Deprecation notice

Deprecation Notice: This blog is no longer updated. Please visit my current blog at subfocal.net.

Friday, June 3, 2011

Create notification bubbles in Python

Preface

Note: You can skip the background discussion here if you already understand what freedesktop.org and D-Bus are.

freedesktop.org

You could live your whole life as a user of Linux-based desktops and never know that freedesktop.org exists. And yet its existence makes your life better in a lot of ways.

freedesktop.org essentially specifies a bunch of standard behaviors that an X-window-system-based desktop should implement. It was created to address the problem of various desktop environments (Gnome, KDE, XFCE, etc.) each having different ways of solving the same problems.

Ever wonder how Pidgin is able to put an icon in the notification area (often called the "tray") whether you're running Gnome or KDE? It would have been a nuisance to have to write the notification applet logic twice, once for Gnome and once for KDE. Even worse, less commonly used desktops like XFCE might be neglected entirely, meaning those users wouldn't see any Pidgin notification applet.

freedesktop solves problems like this by defining a common way for programs to interact with desktop environments. This way, application authors only have to implement the applet behavior once, and it will work on every desktop environment that adheres to the freedesktop standard.

D-Bus

Another key system needs to be mentioned briefly here: D-Bus. It's another one of those things the average user may never hear about in a lifetime of Linux use. In fact, you typically don't hear about it unless something has gone wrong. Yet once again, it's sitting there quietly making life in Linux very cool.

D-Bus is a message-passing system that allows different applications to communicate in well-defined ways. The "well-defined" part is key here: an application can provide a service (and document exactly how it works and where to find it), and other applications can take advantage of the service without caring about the specifics of the system (desktop environment, programming language, etc.) Used this way, D-Bus is very similar to CORBA or RPC.

freedesktop takes advantage of D-Bus to provide a lot of the cross-desktop standards for behavior, and the result is that Linux applications can behave consistently no matter what desktop you use.

Fun with Python

I'm sure you find the above discussion enthralling and would love nothing more than to spend more time reading about open specifications and standards committees. But let's digress and do something fun with Python instead.

While working on a large C++ project, I realized that I often kick off a make command and then pop over to a web browser or an IRC session to distract myself while the test suite runs (knowing it will take a few minutes). The problem with this is that I sometimes find myself reading something fascinating and don't realize that the test suite finished five or ten minutes ago. What I needed was some kind of notification...

It turns out freedesktop.org has an app for that. There's a notification service available via D-Bus, and it's pretty straightforward to call from a Python program:

    import dbus
    import sys

    def notify(summary, body='', app_name='', app_icon='',
            timeout=5000, actions=[], hints=[], replaces_id=0):
        _bus_name = 'org.freedesktop.Notifications'
        _object_path = '/org/freedesktop/Notifications'
        _interface_name = _bus_name

        session_bus = dbus.SessionBus()
        obj = session_bus.get_object(_bus_name, _object_path)
        interface = dbus.Interface(obj, _interface_name)
        interface.Notify(app_name, replaces_id, app_icon,
                summary, body, actions, hints, timeout)

    # If run as a script, just display the argv as summary
    if __name__ == '__main__':
        notify(summary=' '.join(sys.argv[1:]))

I created this little script1 and dropped it in my ~/bin directory so I can pop up notifications whenever I feel like it. (The script wraps the D-Bus logic in a native Python function, then calls it.) Next, I added a new function in my .bash_profile to wrap the make command:

    # Run make and show freedesktop notifications on success/fail
    function make
    {   
        if /usr/bin/make "$@"; then
            notify.py "Make succeeded."
        else
            notify.py "Make failed."
            return 1
        fi
    }

Now whenever a make command finishes, I get a little notification bubble in Gnome to tell me to stop wasting time and get back to work!

Screenshot of notification
Figure 1: Screenshot of notification.

Achieving and maintaining a focused mental state is critical for writing software (among other things). When I'm trying to be productive, it's nice to get a little nudge in the right direction before I start to drift out of the zone.

1. Note that the timeout parameter will probably be ignored on Ubuntu. See this long-standing, contentious bug report.

1 comment: