dbus-tcl

What: dbus
Where: https://chiselapp.com/user/schelte/repository/dbus 
Description: The DBus project provides a Tcl interface to the dbus message
        bus system. It allows Tcl programs to send and receive dbus signals,
        as well as invoke and respond to dbus method calls.
Updated: 01/2018
Contact: Schelte Bron

The dbus package is primarily intended for using the dbus interfaces published by other programs. To publish a dbus interface for your own program, use dbif.


Because it may not be immediately obvious how to use the package to communicate with other programs, here's an example based on a real-life question brought up by saedelaere in the Tcl chatroom:

There is a standard for a desktop notifications service, through which applications can generate passive popups (sometimes known as "poptarts") to notify the user in an asynchronous manner of events. This service is available for multiple desktop environments, like GNOME and KDE.

The specification can be found at: http://people.gnome.org/~mccann/docs/notification-spec/notification-spec-latest.html

This specification indicates that the notification service registers under the name "org.freedesktop.Notifications" on the dbus session bus and implements the org.freedesktop.Notifications interface on an object with the path "/org/freedesktop/Notifications". The method to use to popup a notification is called "org.freedesktop.Notifications.Notify". This method takes a whole bunch of arguments, but from the specification it is not completely clear for all arguments what their type should be exactly.

To obtain the required information you can introspect the dbus interface of the application using the following commands:

package require dbus
dbus connect
dbus call -dest org.freedesktop.Notifications /org/freedesktop/Notifications \
        org.freedesktop.DBus.Introspectable Introspect

This returns an XML document that describes the available methods and signals. Look for the Notify method that we are currently interested in:

    <method name="Notify">
      <annotation value="QVariantMap" name="com.trolltech.QtDBus.QtTypeName.In6"/>
      <arg direction="out" type="u"/>
      <arg direction="in" type="s" name="app_name"/>
      <arg direction="in" type="u" name="replaces_id"/>
      <arg direction="in" type="s" name="app_icon"/>
      <arg direction="in" type="s" name="summary"/>
      <arg direction="in" type="s" name="body"/>
      <arg direction="in" type="as" name="actions"/>
      <arg direction="in" type="a{sv}" name="hints"/>
      <arg direction="in" type="i" name="timeout"/>
    </method>

The args where direction="in" provide the signature specification we need to pass to the dbus call. Simply concatenate all the type values together.

So now we can call the method as follows:

dbus call -dest org.freedesktop.Notifications -signature susssasa{sv}i \
        /org/freedesktop/Notifications org.freedesktop.Notifications Notify \
        "My App" 0 "" "Message" "Hello, World!" {} {} -1

Not specifically Tcl related, but can be difficult to find: This is how you make the application start automatically when another application calls a method on the dbus name belonging to our application. Create a file with a .service extension under /usr/share/dbus-1/services, with the following contents (assuming we use tk.tcl.wiki.foo as dbus name for the application):

[D-BUS Service]
Name=tk.tcl.wiki.foo
Exec=/usr/local/bin/foo.tcl

For applications connecting to the system dbus, you would put the .service file under /usr/share/dbus-1/system-services. You may also want to add a User option to indicate under which uid the program should run.

To be allowed to use a symbolic dbus name on the system dbus you also need a file under /etc/dbus-1/system.d that may look something like this:

<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
 "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
  <!-- User userid can own this service -->
  <policy user="userid">
    <allow own="tk.tcl.wiki.foo"/>
  </policy>

  <policy context="default">
    <allow send_interface="tk.tcl.wiki.foo"/>
    <allow receive_interface="tk.tcl.wiki.foo"/>
    <!-- Allow introspection -->
    <allow send_destination="tk.tcl.wiki.foo"
           send_interface="org.freedesktop.DBus.Introspectable"/>
  </policy>
</busconfig>

bll 2017-1-31 Great stuff sbron, thanks. Some more examples:

Get a list of registered names (I use this to get a list of registered media players)

set serial [dbus call session -details \
    -handler result \
    -dest org.freedesktop.DBus \
    /org/freedesktop/DBus \
    org.freedesktop.DBus ListNames \
    ]

Set the volume for a media player

set serial [dbus call session -details \
    -dest org.mpris.MediaPlayer2.vlc \
    -signature ssv \
    -handler result \
    /org/mpris/MediaPlayer2 \
    org.freedesktop.DBus.Properties Set \
    org.mpris.MediaPlayer2.Player Volume \
    [list d $vol] \
    ]