Showing posts with label python-dbus. Show all posts
Showing posts with label python-dbus. Show all posts

Saturday, May 4, 2013

Six ways to make a notification pop-up

UPDATED MAY 2013 to add Go and GObject methods to the existing Command Line and Python methods.
Originally published Feb 27, 2009.

There are several ways to create notifications in Ubuntu. The notify-OSD daemon draws the boxes and creates the notifications, so all these ways simply contact it and tell it what to do.

  1. On the command line, use the notify-send command. This command is part of the libnotify-bin package. It's easy:
    $ notify-send -i /usr/share/icons/Tango/32x32/status/sunny.png \
                       "Notification Title" \
                       "This is the body"

  2. More command line: dbus-send command does NOT work for notification. It does not support nested message variables. If it did, it should be something really close to this:
    dbus-send --session --dest=org.freedesktop.Notifications \
                             --type=method_call --reply-timeout=10000 \
                             /org/freedesktop/Notifications org.freedesktop.Notifications \
                             string:'Test Application' uint32:0 \
                             string: string:'Notification Title' \
                             string:'This is the body' \
                             array:string: dict:string: int32:10000

  3. Using the Python2 or Python3 pynotify module:
    #!/usr/bin/env python
    """Python 2.5 script. Creates a Notification pop-up bubble"""
    import pynotify
    title = "Notification Title"
    text  = "This is the body"
    icon  = "/usr/share/icons/Tango/32x32/status/sunny.png"
    pynotify.init("Test Application")
    notification = pynotify.Notification(title, text, icon) 
    notification.set_urgency(pynotify.URGENCY_NORMAL)
    notification.show() 

  4. Using the Python2 or Python3 dbus module:
    #!/usr/bin/env python
    """Python 2.5 script. Creates a Notification pop-up bubble"""
    import dbus
    item              = "org.freedesktop.Notifications"
    path              = "/org/freedesktop/Notifications"
    interface         = "org.freedesktop.Notifications"
    app_name          = "Test Application"
    id_num_to_replace = 0
    icon              = "/usr/share/icons/Tango/32x32/status/sunny.png"
    title             = "Notification Title"
    text              = "This is the body"
    actions_list      = ''
    hint              = ''
    time              = 5000   # Use seconds x 1000
    
    bus = dbus.SessionBus()
    notif = bus.get_object(item, path)
    notify = dbus.Interface(notif, interface)
    notify.Notify(app_name, id_num_to_replace, icon, title, text, actions_list, hint, time)

  5. Using the Python3 GObject Introspection (gi) module:
    #!/usr/bin/env python3
    import gi.repository
    from gi.repository import Gio, GLib
    
    session_bus                = Gio.BusType.SESSION
    cancellable                = None
    proxy_property             = 0
    interface_properties_array = None
    destination                = "org.freedesktop.Notifications"
    path                       = "/org/freedesktop/Notifications"
    interface                  = destination
    method                     = "Notify"
    application_name           = "Test Application"
    title                      = "Notification Title"
    text                       = "This is the body"
    id_num_to_replace          = 0
    icon                       = "/usr/share/icons/Tango/32x32/status/sunny.png"
    actions_list               = []
    hints_dict                 = {}
    display_milliseconds       = 5000
    timeout                    = -1
    
    connection = Gio.bus_get_sync(session_bus, cancellable)
    notify = Gio.DBusProxy.new_sync( connection, proxy_property, interface_properties_array,
                                     destination, path, interface, cancellable)
    args = GLib.Variant('(susssasa{sv}i)', ( application_name, id_num_to_replace, icon, 
                        title, text, actions_list, hints_dict, display_milliseconds))
    result = notify.call_sync(method, args, proxy_property, timeout, cancellable)
    id = result.unpack()[0]
    print(id)

  6. Using the go programming language (golang):
    package main
    
    import "launchpad.net/~jamesh/go-dbus/trunk"
    import "fmt"
    
    func main() {
        // Set the variables
        var (
            err              error
            conn             *dbus.Connection
            destination      string = "org.freedesktop.Notifications"
            path             string = "/org/freedesktop/Notifications"
            dbus_interface   string = "org.freedesktop.Notifications"
            dbus_method      string = "Notify"
            application_name string = "dbus-test"
            id_num_to_repl   uint32
            icon_path        string = "/usr/share/icons/Tango/32x32/status/sunny.png"
            title            string = "Notification Title"
            text             string = "This is the body"
            actions_list     []string
            hint             map[string]dbus.Variant
            timeout          int32  = -1
        )
    
        // Connect to Session or System buses.
        if conn, err = dbus.Connect(dbus.SessionBus); err != nil {
            fmt.Println("Connection error:", err)
        }
    
        // Create an object proxy
        obj := conn.Object(destination, dbus.ObjectPath(path))
    
        // Call object methods.
        reply, err := obj.Call(
            dbus_interface,             dbus_method,
            application_name,           id_num_to_repl,
            icon_path,                  notif_box_title,
            notif_box_body,             actions_list,
            hint,                       timeout)
        if err != nil {
            fmt.Println("Notification error:", err)
        }
    
        // Parse the reply message
        var notification_id uint32
        if err := reply.Args(&notification_id); err != nil {
            fmt.Println(err)
        }
        fmt.Println("Notification id:", notification_id)
    


Zenity is an application, not a daemon. It creates a regular window that can be abused for notifications.
zenity --info --title "Big Title" --text "This is the\\nbody text"

Saturday, November 24, 2012

Dbus Tutorial - GObject Introspection instead of python-dbus

Introduction
Introspection
Network Manager
Create a Service
GObject Introspection


In previous posts, I have looked at using the python-dbus to communicate with other processes, essentially using it the same way we use the dbus-send command.

There is another way to create DBus messages. It's a bit more complicated than python-dbus, and it depends upon Gnome, but it's also more robust and perhaps better maintained.

Using Gobject Introspection replacement for python-dbus is described several places, but the best example is here. Python-dbus as a separate bindings project has also suffered with complaints of "lightly maintained," and an awkward method of exposing properties that has been unfixed for years.


These examples only work for clients.  Gnome Bug #656330 shows that services cannot yet use PyGI.




Here's an example notification using Pygi instead of Python-DBus. It's based on this blog post by Martin Pitt, but expanded a bit to show all the variables I can figure out....


1) Header and load gi

#!/usr/bin/env python3

import gi.repository
from gi.repository import Gio, GLib


2) Connect to the DBus Session Bus
Documentation: http://developer.gnome.org/gio/2.29/GDBusConnection.html

session_bus = Gio.BusType.SESSION
cancellable = None
connection = Gio.bus_get_sync(session_bus, cancellable)


3) Create (but don't send) the DBus message header
Documentation: http://developer.gnome.org/gio/2.29/GDBusProxy.html

proxy_property = 0
interface_properties_array = None
destination = 'org.freedesktop.Notifications'
path = '/org/freedesktop/Notifications'
interface = destination
notify = Gio.DBusProxy.new_sync(
     connection,
     proxy_property,
     interface_properties_array,
     destination,
     path,
     interface,
     cancellable)


4) Create (but don't send) the DBus message data
The order is determined by arg order of the Notification system
Documentation: http://developer.gnome.org/notification-spec/#protocol

application_name = 'test'
title = 'Hello World!'
body_text = 'Subtext'
id_num_to_replace = 0
actions_list = []
hints_dict = {}
display_milliseconds = 5000
icon = 'gtk-ok'  # Can use full path, too '/usr/share/icons/Humanity/actions/'
args = GLib.Variant('(susssasa{sv}i)', (
                    application_name, 
                    id_num_to_replace,
                    icon, 
                    title,
                    body_text,
                    actions_list,
                    hints_dict,
                    display_milliseconds))


5) Send the DBus message header and data to the notification service
Documentation: http://developer.gnome.org/gio/2.29/GDBusProxy.html

method = 'Notify'
timeout = -1
result = notify.call_sync(method, args, proxy_property, timeout, cancellable)


6) (Optional) Convert the result value from a Uint32 to a python integer

id = result.unpack()[0]
print(id)

Play with it a bit, and you will quickly see how the pieces work together.



Here is a different, original example DBus client using introspection and this askubuntu question. You can see this is a modified and simplified version of the above example:

#!/usr/bin/env python3
import gi.repository
from gi.repository import Gio, GLib

# Create the DBus message
destination = 'org.freedesktop.NetworkManager'
path        = '/org/freedesktop/NetworkManager'
interface   = 'org.freedesktop.DBus.Introspectable'
method      = 'Introspect'
args        = None
answer_fmt  = GLib.VariantType.new ('(v)')
proxy_prpty = Gio.DBusCallFlags.NONE
timeout     = -1
cancellable = None

# Connect to DBus, send the DBus message, and receive the reply
bus   = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)
reply = bus.call_sync(destination, path, interface,
                      method, args, answer_fmt,
                      proxy_prpty, timeout, cancellable)

# Convert the result value to a formatted python element
print(reply.unpack()[0])




Here is a final DBus client example, getting the properties of the current Network Manager connection

#!/usr/bin/env python3
import gi.repository
from gi.repository import Gio, GLib

# Create the DBus message
destination = 'org.freedesktop.NetworkManager'
path        = '/org/freedesktop/NetworkManager/ActiveConnection/19'
interface   = 'org.freedesktop.DBus.Properties'
method      = 'GetAll'
args        = GLib.Variant('(ss)', 
              ('org.freedesktop.NetworkManager.Connection.Active', 'None'))
answer_fmt  = GLib.VariantType.new ('(v)')
proxy_prpty = Gio.DBusCallFlags.NONE
timeout     = -1
cancellable = None

# Connect to DBus, send the DBus message, and receive the reply
bus   = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)
reply = bus.call_sync(destination, path, interface,
                      method, args, answer_fmt,
                      proxy_prpty, timeout, cancellable)

# Convert the result value to a useful python object and print
[print(item[0], item[1]) for item in result.unpack()[0].items()]

As you can see from this example, dbus communication is actually pretty easy using GLib: Assign the nine variables, turn the crank, and unpack the result.