Showing posts with label Tomboy. Show all posts
Showing posts with label Tomboy. Show all posts

Ruby D-Bus and Fedora 11

Earlier this year I wrote a number of posts about monitoring and interacting with D-Bus using shell scripts. In this post I use Ruby to monitor and interact with D-Bus enabled applications. If you are unfamiliar with D-Bus, a good starting point is this Freedesktop.org tutorial by the authors of the D-Bus specification.

I used the standard out-of-the-box version of Ruby which comes with Fedora 11, i.e.

$ ruby --version
ruby 1.8.6 (2009-06-08 patchlevel 369) [x86_64-linux]

Those readers who are familiar with Ruby will recognize that this version of Ruby is quite old by Ruby standards and is in maintenance mode with Kirk Haines of Engine Yard being the lead maintainer. Hopefully a 1.9 version of Ruby will be included in the official repositories for Fedora 12.

I also installed the latest version (0.2.9 "I'm not dead") of ruby-dbus which comes as a compressed tarball rather than as a gem. This project was recently taken over by Martin Vidner, who works for Novell in their Prague development group, after a long period of no activity by the original developers. An introduction to and a tutorial on ruby-dbus is available here. It needs to be updated and expanded to include all the interfaces and methods but it is a good introduction to the general concepts.

Introspection is core to D-Bus scripting. Here is one way to introspect the D-Bus system bus and output the resulting introspection data in XML format. The introspection data format is specified by the D-Bus Specification. The introspect_data method does all the heavy lifting.

#!/usr/bin/ruby

require 'dbus'

bus = DBus::SystemBus.instance
xml = bus.introspect_data("org.freedesktop.DBus", "/org/freedesktop/DBus/Introspectable")
puts xml

Here is the output from my computer which is running Fedora 11:

<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg name="data" direction="out" type="s"/>
</method>
</interface>
<interface name="org.freedesktop.DBus">
<method name="Hello">
<arg direction="out" type="s"/>
</method>
<method name="RequestName">
<arg direction="in" type="s"/>
<arg direction="in" type="u"/>
<arg direction="out" type="u"/>
</method>
<method name="ReleaseName">
<arg direction="in" type="s"/>
<arg direction="out" type="u"/>
</method>
<method name="StartServiceByName">
<arg direction="in" type="s"/>
<arg direction="in" type="u"/>
<arg direction="out" type="u"/>
</method>
<method name="UpdateActivationEnvironment">
<arg direction="in" type="a{ss}"/>
</method>
<method name="NameHasOwner">
<arg direction="in" type="s"/>
<arg direction="out" type="b"/>
</method>
<method name="ListNames">
<arg direction="out" type="as"/>
</method>
<method name="ListActivatableNames">
<arg direction="out" type="as"/>
</method>
<method name="AddMatch">
<arg direction="in" type="s"/>
</method>
<method name="RemoveMatch">
<arg direction="in" type="s"/>
</method>
<method name="GetNameOwner">
<arg direction="in" type="s"/>
<arg direction="out" type="s"/>
</method>
<method name="ListQueuedOwners">
<arg direction="in" type="s"/>
<arg direction="out" type="as"/>
</method>
<method name="GetConnectionUnixUser">
<arg direction="in" type="s"/>
<arg direction="out" type="u"/>
</method>
<method name="GetConnectionUnixProcessID">
<arg direction="in" type="s"/>
<arg direction="out" type="u"/>
</method>
<method name="GetAdtAuditSessionData">
<arg direction="in" type="s"/>
<arg direction="out" type="ay"/>
</method>
<method name="GetConnectionSELinuxSecurityContext">
<arg direction="in" type="s"/>
<arg direction="out" type="ay"/>
</method>
<method name="ReloadConfig">
</method>
<method name="GetId">
<arg direction="out" type="s"/>
</method>
<signal name="NameOwnerChanged">
<arg type="s"/>
<arg type="s"/>
<arg type="s"/>
</signal>
<signal name="NameLost">
<arg type="s"/>
</signal>
<signal name="NameAcquired">
<arg type="s"/>
</signal>
</interface>
</node>

The following example uses the introspect method instead of the introspect_data method to enumerate a list of the available services using the ListActivatableNames method. I am going to assume that you are familiar with the Ruby language.so concepts such as looping and arrays do not need explanation.

require 'dbus'

bus = DBus::SystemBus.instance
proxy = bus.introspect("org.freedesktop.DBus", "/org/freedesktop/DBus/ListActivatableNames")

bus.proxy.ListActivatableNames[0].each do |service|
puts "#{service}"
end

This is the output:

org.freedesktop.DBus
org.freedesktop.DeviceKit.Disks
org.fedoraproject.Setroubleshootd
com.hp.hplip
org.fedoraproject.Config.Services
org.freedesktop.ConsoleKit
org.gnome.CPUFreqSelector
net.reactivated.Fprint
org.freedesktop.PackageKit
org.freedesktop.DeviceKit
org.freedesktop.NetworkManagerSystemSettings
org.gnome.ClockApplet.Mechanism
org.kerneloops.submit
org.freedesktop.PolicyKit
org.freedesktop.Gypsy
org.gnome.GConf.Defaults
fi.epitest.hostap.WPASupplicant
org.gnome.SystemMonitor.Mechanism
org.freedesktop.DeviceKit.Power
org.freedesktop.nm_dispatcher
org.opensuse.CupsPkHelper.Mechanism

You can query devices via the D-Bus interface to HAL as the following examples demonstrate.

#!/usr/bin/ruby

require 'dbus'

bus = DBus::SystemBus.instance
xml = bus.introspect_data("org.freedesktop.Hal", "/org/freedesktop/Hal/devices/computer")
puts xml

Here is what is outputted when this script is executed:

<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.freedesktop.Hal.Device">
<method name="GetAllProperties">
<arg name="properties" direction="out" type="a{sv}"/>
</method>
<method name="SetMultipleProperties">
<arg name="properties" direction="in" type="a{sv}"/>
</method>
<method name="GetProperty">
<arg name="key" direction="in" type="s"/>
<arg name="value" direction="out" type="v"/>
</method>
......
<signal name="InterfaceLockAcquired">
<arg name="interface_name" type="s"/>
<arg name="lock_holder" type="s"/>
<arg name="num_locks" type="i"/>
</signal>
<signal name="InterfaceLockReleased">
<arg name="interface_name" type="s"/>
<arg name="lock_holder" type="s"/>
<arg name="num_locks" type="i"/>
</signal>
</interface>
.......
<interface name="org.freedesktop.Hal.Device.CPUFreq">
<method name="SetCPUFreqGovernor">
<arg name="governor_string" direction="in" type="s"/>
</method>
<method name="SetCPUFreqPerformance">
<arg name="value" direction="in" type="i"/>
</method>
<method name="SetCPUFreqConsiderNice">
<arg name="value" direction="in" type="b"/>
</method>
<method name="GetCPUFreqGovernor">
<arg name="return_code" direction="out" type="s"/>
</method>
<method name="GetCPUFreqPerformance">
<arg name="return_code" direction="out" type="i"/>
</method>
<method name="GetCPUFreqConsiderNice">
<arg name="return_code" direction="out" type="b"/>
</method>
<method name="GetCPUFreqAvailableGovernors">
<arg name="return_code" direction="out" type="as"/>
</method>
</interface>
</node>

Here is an example of how to output the previous data in a more readable form using the interfaces method..

#!/usr/bin/ruby

require 'dbus'

bus = DBus::SystemBus.instance
proxy = bus.introspect("org.freedesktop.Hal", "/org/freedesktop/Hal/devices/computer")

proxy.interfaces.each do |interface|
puts "Interface: #{interface}"
proxy[interface].methods.each do |key,value|
puts " Method: #{key}"
end
proxy[interface].signals.each do |key,value|
puts " Signal: #{key}"
end

Here is an portion of the output: from executing this script.

Interface: org.freedesktop.Hal.Device.CPUFreq
Method: GetCPUFreqConsiderNice
Method: GetCPUFreqGovernor
Method: SetCPUFreqPerformance
Method: GetCPUFreqAvailableGovernors
Method: SetCPUFreqGovernor
Method: GetCPUFreqPerformance
Method: SetCPUFreqConsiderNice
Interface: org.freedesktop.Hal.Device.SystemPowerManagement
Method: Shutdown
Method: SuspendHybrid
Method: SetPowerSave
Method: Hibernate
Method: Reboot
Method: Suspend
Interface: org.freedesktop.Hal.Device
Method: ReleaseInterfaceLock
Method: ClaimInterface
Method: Reprobe
........
Method: SetPropertyBoolean
Signal: InterfaceLockAcquired
Signal: InterfaceLockReleased
Signal: PropertyModified
Signal: Condition
Interface: org.freedesktop.DBus.Introspectable
Method: Introspect

You can easily drill down to individual interfaces and methods. For example, here is one way to list the set of available CPU frequency governors.

#!/usr/bin/ruby
#
# <interface name="org.freedesktop.Hal.Device.CPUFreq">
# <method name="SetCPUFreqGovernor">
# <arg name="governor_string" direction="in" type="s"/>
# </method>
# <method name="SetCPUFreqPerformance">
# <arg name="value" direction="in" type="i"/>
# </method>
# <method name="SetCPUFreqConsiderNice">
# <arg name="value" direction="in" type="b"/>
# </method>
# <method name="GetCPUFreqGovernor">
# <arg name="return_code" direction="out" type="s"/>
# </method>
# <method name="GetCPUFreqPerformance">
# <arg name="return_code" direction="out" type="i"/>
# </method>
# <method name="GetCPUFreqConsiderNice">
# <arg name="return_code" direction="out" type="b"/>
# </method>
# <method name="GetCPUFreqAvailableGovernors">
# <arg name="return_code" direction="out" type="as"/>
# </method>
# </interface>
#

require 'dbus'

bus = DBus::SystemBus.instance
proxy = bus.introspect("org.freedesktop.Hal", "/org/freedesktop/Hal/devices/computer")

interface = proxy["org.freedesktop.Hal.Device.CPUFreq"]
governors = interface.GetCPUFreqAvailableGovernors
puts "Available CPU Freq Governors:"
governors[0].each do |gov|
puts " #{gov}"
end

which produces the following output:

Available CPU Freq Governors:
ondemand
userspace
performance

Lots of useful information can be be obtained from the HAL manager interface. The following script lists all the methods supported by the HAL manager interface and then uses the GetAllDevices method to enumerate the devices on my computer.

require 'dbus'

bus = DBus::SystemBus.instance
proxy = bus.introspect("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager")

puts "HAL manager reports following methods:"
proxy.interfaces[0].each do |interface|
proxy[interface].methods.each do |key, value|
puts " #{key}"
end
end

interface = proxy["org.freedesktop.Hal.Manager"]
devices = interface.GetAllDevices
puts "\nHAL manager reports following devices:"
devices[0].each do |device|
puts " #{device}"
end

Here is a portion of the output when this script is executed

HAL manager reports following methods:
AcquireGlobalInterfaceLock
DeviceExists
CommitToGdl
GetAllDevicesWithProperties
FindDeviceByCapability
NewDevice
SingletonAddonIsReady
FindDeviceStringMatch
GetAllDevices
ReleaseGlobalInterfaceLock
Remove

HAL manager reports following devices:
/org/freedesktop/Hal/devices/net_ba_cf_03_4e_14_ca
/org/freedesktop/Hal/devices/volume_part7_size_115326976
/org/freedesktop/Hal/devices/computer
/org/freedesktop/Hal/devices/storage_model_DVD_Writer_1070d
...............
/org/freedesktop/Hal/devices/acpi_CPU0
/org/freedesktop/Hal/devices/acpi_CPU1
/org/freedesktop/Hal/devices/acpi_CPU2
/org/freedesktop/Hal/devices/acpi_CPU3
/org/freedesktop/Hal/devices/pci_8086_2940
/org/freedesktop/Hal/devices/pci_8086_293e
/org/freedesktop/Hal/devices/usb_device_1d6b_2_0000_00_1a_7_if0
/org/freedesktop/Hal/devices/usb_device_1d6b_2_0000_00_1a_7
/org/freedesktop/Hal/devices/pci_8086_293c
/org/freedesktop/Hal/devices/usb_device_1d6b_1_0000_00_1a_2_if0
/org/freedesktop/Hal/devices/usb_device_1d6b_1_0000_00_1a_2
/org/freedesktop/Hal/devices/pci_8086_2939
/org/freedesktop/Hal/devices/usb_device_1d6b_1_0000_00_1a_1_if0
/org/freedesktop/Hal/devices/usb_device_1d6b_1_0000_00_1a_1
/org/freedesktop/Hal/devices/pci_8086_2938
/org/freedesktop/Hal/devices/usb_device_1d6b_1_0000_00_1a_0_if0
/org/freedesktop/Hal/devices/usb_device_1d6b_1_0000_00_1a_0
/org/freedesktop/Hal/devices/pci_8086_2937
/org/freedesktop/Hal/devices/pci_8086_294c
/org/freedesktop/Hal/devices/pci_10de_640
/org/freedesktop/Hal/devices/pci_8086_29e1
/org/freedesktop/Hal/devices/pci_8086_29e0

The next example uses the D-Bus interface to Tomboy, a desktop note-taking application, to create a simple note, display it for 5 seconds and then delete the note.

#!/usr/bin/ruby

require 'dbus'

bus = DBus::SessionBus.instance
service = bus.service("org.gnome.Tomboy")

tomboy = service.object("/org/gnome/Tomboy/RemoteControl")
tomboy.introspect
tomboy.default_iface = "org.gnome.Tomboy.RemoteControl"
note = tomboy.CreateNamedNote("My Note")[0]
tomboy.SetNoteContents(note, "Hello World")
tomboy.DisplayNote(note)
sleep 5
tomboy.DeleteNote(note)

Note the need to introspect the tomboy object and set the default interface using the default_iface method.

You can also add one or more tags to a Tomboy note and extract comprehensive metadata in XML format as shown in the following example.

#!/usr/bin/ruby

require 'dbus'

bus = DBus::SessionBus.instance
service = bus.service("org.gnome.Tomboy")

tomboy = service.object("/org/gnome/Tomboy/RemoteControl")
tomboy.introspect
tomboy.default_iface = "org.gnome.Tomboy.RemoteControl"
note = tomboy.CreateNamedNote("My Note")[0]
tomboy.SetNoteContents(note, "Hello World")
tomboy.AddTagToNote(note, "blog example")
tomboy.DisplayNote(note)
sleep 5
xml = tomboy.GetNoteCompleteXml(note)
tomboy.DeleteNote(note)

puts xml

Here is the XML that is outputted when this script is executed:

<?xml version="1.0" encoding="utf-16"?>
<note version="0.3" xmlns:link="http://beatniksoftware.com/tomboy/link" xmlns:size="http://beatniksoftware.com/tomboy/size" xmlns="http://beatniksoftware.com/tomboy">
<title>My Note</title>
<text xml:space="preserve"><note-content version="0.1">Hello World</note-content></text>
<last-change-date>2009-09-07T15:44:10.2178650-04:00</last-change-date>
<last-metadata-change-date>2009-09-07T15:44:10.2212100-04:00</last-metadata-change-date>
<create-date>2009-09-07T15:44:10.2142940-04:00</create-date>
<cursor-position>37</cursor-position>
<width>450</width>
<height>360</height>
<x>1440</x>
<y>0</y>
<tags>
<tag>blog example</tag>
</tags>
<open-on-startup>False</open-on-startup>
</note>

The next example show you how to monitor D-Bus messages and act upon certain messages. You can do this using D-Bus signals. Suppose, for example, you want to monitor activity relating to Tomboy notes such as when Tomboy notes are created. First of all you need to find out what D-Bus signals Tomboy supports. This is easy to do using introspection as shown in the following script.

#!/usr/bin/ruby

require 'dbus'

bus = DBus::SessionBus.instance
service = bus.service("org.gnome.Tomboy")

tomboy = service.object("/org/gnome/Tomboy/RemoteControl")
tomboy.introspect
tomboy.default_iface = "org.gnome.Tomboy.RemoteControl"
puts "List of supported signals:"
tomboy.signals.each do |key,value|
puts " #{key}"
end

Here is the output:

List of supported signals:
NoteSaved
NoteAdded
NoteDeleted

As you can see the version of Tomboy on my computer emits three D-Bus signals - NoteAdded when a note is added, NoteSaved when a note is saved, and NoteDeleted when a note is deleted.

The following script outputs a message each time a Tomboy note is created, saved or deleted.

#!/usr/bin/ruby

require 'dbus'

bus = DBus::SessionBus.instance

match = DBus::MatchRule.new
match.type = "signal"
match.interface = "org.gnome.Tomboy.RemoteControl"
match.path = "/org/gnome/Tomboy/RemoteControl"

bus.add_match(match) do |msg, misc|
puts "#{msg.member} #{msg.params[0]}"
end

main = DBus::Main.new
main << bus
main.run

Here is what is outputted when a single Tomboy note is created, saved and then deleted.

NoteAdded note://tomboy/56587548-7535-4e21-a4b3-3ee85ffa7756
NoteSaved note://tomboy/56587548-7535-4e21-a4b3-3ee85ffa7756
NoteDeleted note://tomboy/56587548-7535-4e21-a4b3-3ee85ffa7756

Well that's all for now. There is a lot more that you can do using ruby-dbus but I will leave it up to you to go explore the possibilities. The best place to discover what is possible is to study the ruby-dbussource code. It is fairly compact and terse but logically laid out.
 

Monitoring D-Bus

Because D-Bus operates for the most part under the hood invisible to the user, means of monitoring D-Bus messages is important for both activation and debugging purposes.  In this post I examine how to monitor and act on such messages.  I assume that you are relatively familiar with D-Bus.  If not, you should look at my previous posts on D-Bus to gain an understanding of the basic concepts.

Probably the most commonly used tool is the command line utility dbus-monitor which was written by Philip Blundell as part of the reference D-Bus implementation and which is standard on most D-Bus enabled platforms.  It is a very powerful utility but unfortunately it's man page is terse and fails to explain the most powerful feature of dbus-monitor i.e. watch expressions.

Suppose, for example, I want to monitor the creation, saving and deletion of Tomboy notes using D-Bus signals.  To get the list of the supported signals I could introspect Tomboy using qdbus i.e.
$ qdbus org.gnome.Tomboy /org/gnome/Tomboy/RemoteControl | grep signal
signal void org.gnome.Tomboy.RemoteControl.NoteAdded(QString uri)
signal void org.gnome.Tomboy.RemoteControl.NoteDeleted(QString uri, QString title)
signal void org.gnome.Tomboy.RemoteControl.NoteSaved(QString uri)
$
or I could use dbus-monitor to look at the signals generated when Tomboy creates, saves and deletes a note.
$ dbus-monitor type=signal interface="org.gnome.Tomboy.RemoteControl"
signal sender=org.freedesktop.DBus -> dest=:1.102 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameAcquired
string ":1.102"
signal sender=:1.63 -> dest=(null destination) path=/org/gnome/Tomboy/RemoteControl; interface=org.gnome.Tomboy.RemoteControl; member=NoteAdded
string "note://tomboy/0ae6b0b3-9394-44e9-ad4a-46726e68cebc"
signal sender=:1.63 -> dest=(null destination) path=/org/gnome/Tomboy/RemoteControl; interface=org.gnome.Tomboy.RemoteControl; member=NoteSaved
string "note://tomboy/0ae6b0b3-9394-44e9-ad4a-46726e68cebc"
signal sender=:1.63 -> dest=(null destination) path=/org/gnome/Tomboy/RemoteControl; interface=org.gnome.Tomboy.RemoteControl; member=NoteDeleted
string "note://tomboy/0ae6b0b3-9394-44e9-ad4a-46726e68cebc"
string "New Note 1"
$
As you can see Tomboy issues three signals - NoteAdded when a note is added, NoteSaved when a note is saved, and NoteDeleted when a note is deleted.  Interestingly, for some reason NoteDeleted provides both the uri and the title of the note whereas the other two signals only provide the uri.

Suppose I just want to to monitor when a Tomboy note is saved by a user.  I can use a dbus-monitor watch expression for this purpose as shown in the following example.
dbus-monitor "type='signal',sender='org.gnome.Tomboy',interface='org.gnome.Tomboy.RemoteControl',path='/org/gnome/Tomboy/RemoteControl',member='NoteSaved'"
A watch expression is essentially a message filter.  Note the syntax!  Everything between the two double quotes is part of the watch expression.

Unfortunately the syntax of a watch expression is not documented in the dbus-monitor man page.  However from looking at the source code for dbus-monitor, it appears that a watch expression consists of one or more name-value pairs, e.g. sender='org.gnome.Tomboy' separated by commas.  The following are valid names: type, sender, destination, path, interface, member and error_name.  The value of type must be one of the following: signal, method_call, method_return or error

Probably the most powerful feature of dbus-monitor is the fact that you are not limited to using just one watch expression at a time.  The following example simultaneously monitors all 3 Tomboy signals and uses awk to parse the output from dbus-monitor and display a meaningful message.
#!/bin/bash

OJECT="'org.gnome.Tomboy'"
IFACE="'org.gnome.Tomboy.RemoteControl'"
DPATH="'/org/gnome/Tomboy/RemoteControl'"

WATCH1="type='signal', sender=${OJECT}, interface=${IFACE}, path=${DPATH}, member='NoteAdded'"
WATCH2="type='signal', sender=${OJECT}, interface=${IFACE}, path=${DPATH}, member='NoteSaved'"
WATCH3="type='signal', sender=${OJECT}, interface=${IFACE}, path=${DPATH}, member='NoteDeleted'"

dbus-monitor "${WATCH1}" "${WATCH2}" "${WATCH3}" | \
awk '
/member=NoteAdded/ { getline; print "Created note " substr($2,7) }
/member=NoteSaved/ { getline; print "Added note " substr($2,7) }
/member=NoteDeleted/ { getline; print "Deleted note " substr($2,7) }
'
Here is the output generated when I clicked on the Tomboy icon to create a new note, waited for the automatic save and then selected the delete option to delete the note.
$ ./test
Created note //tomboy/3da026dc-f6ee-4637-8a94-bec6e2844824"
Added note //tomboy/3da026dc-f6ee-4637-8a94-bec6e2844824"
Deleted note //tomboy/3da026dc-f6ee-4637-8a94-bec6e2844824"
Well that is all for this post.  Enjoy!

P.S. I tested these examples using Fedora 10. I have no idea whether they will work on previous versions of Fedora or other Linux distributions.
 

Scripting Tomboy

Tomboy is an open source GNOME desktop note-taking application which is written in C# and utilizing the Mono runtime, Gtk# and the GtkSpell spell-checker.

The actual release of Tomboy which comes with Fedora 10 is version 0.12.0.  This includes a comprehensive D-Bus interface which makes it possible to create, modify and display Tomcat notes from your shell scripts.  This post provides an overview of the available D-Bus methods and includes a number of examples for you to experiment with.  See my previous post on D-Bus scripting if you are unfamilar with the basic concepts of D-Bus scripting.

First we will list the available objects using qdbus.
$ qdbus org.gnome.Tomboy
/
/org
/org/gnome
/org/gnome/Tomboy
/org/gnome/Tomboy/RemoteControl
Next, we list all the available signals and methods for RemoteControl.
$ qdbus org.gnome.Tomboy /org/gnome/Tomboy/RemoteControl
method QString org.freedesktop.DBus.Introspectable.Introspect()
method bool org.gnome.Tomboy.RemoteControl.AddTagToNote(QString uri, QString tag_name)
method QString org.gnome.Tomboy.RemoteControl.CreateNamedNote(QString linked_title)
method QString org.gnome.Tomboy.RemoteControl.CreateNote()
method bool org.gnome.Tomboy.RemoteControl.DeleteNote(QString uri)
method bool org.gnome.Tomboy.RemoteControl.DisplayNote(QString uri)
method bool org.gnome.Tomboy.RemoteControl.DisplayNoteWithSearch(QString uri, QString search)
method void org.gnome.Tomboy.RemoteControl.DisplaySearch()
method void org.gnome.Tomboy.RemoteControl.DisplaySearchWithText(QString search_text)
method QString org.gnome.Tomboy.RemoteControl.FindNote(QString linked_title)
method QString org.gnome.Tomboy.RemoteControl.FindStartHereNote()
method QStringList org.gnome.Tomboy.RemoteControl.GetAllNotesWithTag(QString tag_name)
method qlonglong org.gnome.Tomboy.RemoteControl.GetNoteChangeDate(QString uri)
method QString org.gnome.Tomboy.RemoteControl.GetNoteCompleteXml(QString uri)
method QString org.gnome.Tomboy.RemoteControl.GetNoteContents(QString uri)
method QString org.gnome.Tomboy.RemoteControl.GetNoteContentsXml(QString uri)
method qlonglong org.gnome.Tomboy.RemoteControl.GetNoteCreateDate(QString uri)
method QString org.gnome.Tomboy.RemoteControl.GetNoteTitle(QString uri)
method QStringList org.gnome.Tomboy.RemoteControl.GetTagsForNote(QString uri)
method bool org.gnome.Tomboy.RemoteControl.HideNote(QString uri)
method QStringList org.gnome.Tomboy.RemoteControl.ListAllNotes()
signal void org.gnome.Tomboy.RemoteControl.NoteAdded(QString uri)
signal void org.gnome.Tomboy.RemoteControl.NoteDeleted(QString uri, QString title)
method bool org.gnome.Tomboy.RemoteControl.NoteExists(QString uri)
signal void org.gnome.Tomboy.RemoteControl.NoteSaved(QString uri)
method bool org.gnome.Tomboy.RemoteControl.RemoveTagFromNote(QString uri, QString tag_name)
method QStringList org.gnome.Tomboy.RemoteControl.SearchNotes(QString query, bool case_sensitive)
method bool org.gnome.Tomboy.RemoteControl.SetNoteCompleteXml(QString uri, QString xml_contents)
method bool org.gnome.Tomboy.RemoteControl.SetNoteContents(QString uri, QString text_contents)
method bool org.gnome.Tomboy.RemoteControl.SetNoteContentsXml(QString uri, QString xml_contents)
method QString org.gnome.Tomboy.RemoteControl.Version()
As a simple example of how to use a published method, we invoke the Version method to return the version of Tomboy that we are using.
$ qdbus org.gnome.Tomboy /org/gnome/Tomboy/RemoteControl org.gnome.Tomboy.RemoteControl.Version
0.12.0
We can use dbus-send instead of qdbus as shown below but, as you can, see qdbus syntax is more compact.  Also note that we have to use the session bus.
$ dbus-send --type=method_call --session --print-reply \
--dest='org.gnome.Tomboy' /org/gnome/Tomboy/RemoteControl \
org.gnome.Tomboy.RemoteControl.Version
0.12.0
In the following example, we create the equivalant of "Hello World" using a note, display it for 5 seconds and then delete the note.
#!/bin/bash
DPATH="/org/gnome/Tomboy/RemoteControl"
INTERFACE="org.gnome.Tomboy.RemoteControl"

TMP=`qdbus org.gnome.Tomboy ${DPATH} ${INTERFACE}.CreateNamedNote "My Note" 2>/dev/null`
RESULT=$?
if [[ $RESULT != 0 ]]
then
exit 1
fi

# figure out note uri string which is of the form
# note://0xaf3356abcdefg
OID=${TMP#note:}

# set the contents of the note using the uid
qdbus org.gnome.Tomboy ${DPATH} ${INTERFACE}.SetNoteContents note:$OID "Hello World"
qdbus org.gnome.Tomboy ${DPATH} ${INTERFACE}.DisplayNote note:$OID
sleep 5
qdbus org.gnome.Tomboy ${DPATH} ${INTERFACE}.DeleteNote note:$OID
Here is a screenshot of the note created by this shell script.



Incidentally, if you create one or more notes by accident while experimenting and need to delete them, the following script will delete all notes.
#!/bin/bash
OJECT="org.gnome.Tomboy"
DPATH="/org/gnome/Tomboy/RemoteControl"
IFACE="org.gnome.Tomboy.RemoteControl"

qdbus ${OJECT} ${DPATH} ${IFACE}.ListAllNotes |
while read TMP
do
echo "$TMP"
OID=${TMP#note:}
qdbus ${OJECT} ${DPATH} ${IFACE}.DeleteNote note:$OID
done
You can also add one or more tags to a note and extract comprehensive metadata in XML format as shown in the following example.
#!/bin/bash
OJECT="org.gnome.Tomboy"
DPATH="/org/gnome/Tomboy/RemoteControl"
IFACE="org.gnome.Tomboy.RemoteControl"

TMP=`qdbus ${OJECT} ${DPATH} ${IFACE}.CreateNamedNote "My Note" 2>/dev/null`
RESULT=$?
OID=${TMP#note:}

qdbus ${OJECT} ${DPATH} ${IFACE}.SetNoteContents note:$OID "Hello World"
qdbus ${OJECT} ${DPATH} ${IFACE}.AddTagToNote note:$OID "blog example"
qdbus ${OJECT} ${DPATH} ${IFACE}.DisplayNote note:$OID
sleep 4
qdbus ${OJECT} ${DPATH} ${IFACE}.GetNoteCompleteXml note:$OID
qdbus ${OJECT} ${DPATH} ${IFACE}.DeleteNote note:$OID

# this is the output from the GetNoteCompleteXml
<?xml version="1.0" encoding="utf-16"?>
<note version="0.3" xmlns:link="http://beatniksoftware.com/tomboy/link" xmlns:size="http://beatniksoftware.com/tomboy/size" xmlns="http://beatniksoftware.com/tomboy">
<title>My Note</title>
<text xml:space="preserve"><note-content version="0.1">Hello World</note-content></text>
<last-change-date>2009-02-08T10:44:46.3741020-05:00</last-change-date>
<last-metadata-change-date>2009-02-08T10:44:46.3940970-05:00</last-metadata-change-date>
<create-date>2009-02-08T10:44:46.3441770-05:00</create-date>
<cursor-position>37</cursor-position>
<width>450</width>
<height>360</height>
<x>3</x>
<y>48</y>
<tags>
<tag>blog example</tag>
</tags>
<open-on-startup>False</open-on-startup>
</note>
You can also create a note in a single call to dbus-send or qdbus by passing the appropriate XML formatted details to the SetNoteCompleteXml method.
#!/bin/bash
OJECT="org.gnome.Tomboy"
DPATH="/org/gnome/Tomboy/RemoteControl"
IFACE="org.gnome.Tomboy.RemoteControl"

TMP=`qdbus ${OJECT} ${DPATH} ${IFACE}.CreateNamedNote "My Note" 2>/dev/null`
RESULT=$?
OID=${TMP#note:}

qdbus ${OJECT} ${DPATH} ${IFACE}.SetNoteCompleteXml note:$OID \
"<?xml version='1.0' encoding='utf-16'?>
<note version='0.3' xmlns:link='http://beatniksoftware.com/tomboy/link'
xmlns:size='http://beatniksoftware.com/tomboy/size'
xmlns='http://beatniksoftware.com/tomboy'>
<title>My Note</title>
<text xml:space='preserve'>
<note-content version='0.1'>Hello World</note-content>
</text>
<tags>
<tag>first tag</tag>
<tag>second tag</tag>#!/bin/bash
</tags>
<open-on-startup>False</open-on-startup>
</note>"

qdbus ${OJECT} ${DPATH} ${IFACE}.DisplayNote note:$OID
sleep 4
qdbus ${OJECT} ${DPATH} ${IFACE}.DeleteNote note:$OID
Interestingly, for some reason or other you cannot set the position or size of the resulting note.  If anybody knows how to overcome this limitation, please let me know.

Well that is all for this particular post as I have to head off to the airport for another boring long flight to Europe.  In my next post I will show you how to handle D-Bus signals in your shell scripts.