summaryrefslogtreecommitdiff
path: root/doc/tutorial.txt
diff options
context:
space:
mode:
authorvivian, zhang <vivian.zhang@intel.com>2012-06-03 11:21:25 +0800
committervivian, zhang <vivian.zhang@intel.com>2012-06-03 11:21:25 +0800
commit018fcb4a1852ab3368903d57bc0b5e54fa03e6c8 (patch)
tree108a0f4727db6ea287725f85bbca3eee9801983a /doc/tutorial.txt
parentc0384c46d79b70ce46d887fdaa2f4c59fb89fd33 (diff)
downloaddbus-python-018fcb4a1852ab3368903d57bc0b5e54fa03e6c8.tar.gz
dbus-python-018fcb4a1852ab3368903d57bc0b5e54fa03e6c8.tar.bz2
dbus-python-018fcb4a1852ab3368903d57bc0b5e54fa03e6c8.zip
Initial import package dbus-python: D-Bus Python BindingsHEAD2.0_alphamaster2.0alpha1.0_post
Diffstat (limited to 'doc/tutorial.txt')
-rw-r--r--doc/tutorial.txt681
1 files changed, 681 insertions, 0 deletions
diff --git a/doc/tutorial.txt b/doc/tutorial.txt
new file mode 100644
index 0000000..73251cf
--- /dev/null
+++ b/doc/tutorial.txt
@@ -0,0 +1,681 @@
+====================
+dbus-python tutorial
+====================
+
+:Author: Simon McVittie, `Collabora Ltd.`_
+:Date: 2006-06-14
+
+.. _`Collabora Ltd.`: http://www.collabora.co.uk/
+
+This tutorial requires Python 2.4 or up, and ``dbus-python`` 0.80rc4 or up.
+
+.. contents::
+
+.. --------------------------------------------------------------------
+
+.. _Bus object:
+.. _Bus objects:
+
+Connecting to the Bus
+=====================
+
+Applications that use D-Bus typically connect to a *bus daemon*, which
+forwards messages between the applications. To use D-Bus, you need to create a
+``Bus`` object representing the connection to the bus daemon.
+
+There are generally two bus daemons you may be interested in. Each user
+login session should have a *session bus*, which is local to that
+session. It's used to communicate between desktop applications. Connect
+to the session bus by creating a ``SessionBus`` object::
+
+ import dbus
+
+ session_bus = dbus.SessionBus()
+
+The *system bus* is global and usually started during boot; it's used to
+communicate with system services like udev_, NetworkManager_, and the
+`Hardware Abstraction Layer daemon (hald)`_. To connect to the system
+bus, create a ``SystemBus`` object::
+
+ import dbus
+
+ system_bus = dbus.SystemBus()
+
+Of course, you can connect to both in the same application.
+
+For special purposes, you might use a non-default Bus, or a connection
+which isn't a Bus at all, using some new API added in dbus-python 0.81.0.
+This is not described here, and will at some stage be the subject of a separate
+tutorial.
+
+.. _udev:
+ http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html
+.. _NetworkManager:
+ http://www.gnome.org/projects/NetworkManager/
+.. _Hardware Abstraction Layer daemon (hald):
+ http://www.freedesktop.org/wiki/Software/hal
+
+.. --------------------------------------------------------------------
+
+Making method calls
+===================
+
+D-Bus applications can export objects for other applications' use. To
+start working with an object in another application, you need to know:
+
+* The *bus name*. This identifies which application you want to
+ communicate with. You'll usually identify applications by a
+ *well-known name*, which is a dot-separated string starting with a
+ reversed domain name, such as ``org.freedesktop.NetworkManager``
+ or ``com.example.WordProcessor``.
+
+* The *object path*. Applications can export many objects - for
+ instance, example.com's word processor might provide an object
+ representing the word processor application itself and an object for
+ each document window opened, or it might also provide an object for
+ each paragraph within a document.
+
+ To identify which one you want to interact with, you use an object path,
+ a slash-separated string resembling a filename. For instance, example.com's
+ word processor might provide an object at ``/`` representing the word
+ processor itself, and objects at ``/documents/123`` and
+ ``/documents/345`` representing opened document windows.
+
+As you'd expect, one of the main things you can do with remote objects
+is to call their methods. As in Python, methods may have parameters,
+and they may return one or more values.
+
+.. _proxy object:
+
+Proxy objects
+-------------
+
+To interact with a remote object, you use a *proxy object*. This is a
+Python object which acts as a proxy or "stand-in" for the remote object -
+when you call a method on a proxy object, this causes dbus-python to make
+a method call on the remote object, passing back any return values from
+the remote object's method as the return values of the proxy method call.
+
+To obtain a proxy object, call the ``get_object`` method on the ``Bus``.
+For example, NetworkManager_ has the well-known name
+``org.freedesktop.NetworkManager`` and exports an object whose object
+path is ``/org/freedesktop/NetworkManager``, plus an object per network
+interface at object paths like
+``/org/freedesktop/NetworkManager/Devices/eth0``. You can get a proxy
+for the object representing eth0 like this::
+
+ import dbus
+ bus = dbus.SystemBus()
+ proxy = bus.get_object('org.freedesktop.NetworkManager',
+ '/org/freedesktop/NetworkManager/Devices/eth0')
+ # proxy is a dbus.proxies.ProxyObject
+
+Interfaces and methods
+----------------------
+
+D-Bus uses *interfaces* to provide a namespacing mechanism for methods.
+An interface is a group of related methods and signals (more on signals
+later), identified by a name which is a series of dot-separated components
+starting with a reversed domain name. For instance, each NetworkManager_
+object representing a network interface implements the interface
+``org.freedesktop.NetworkManager.Devices``, which has methods like
+``getProperties``.
+
+To call a method, call the method of the same name on the proxy object,
+passing in the interface name via the ``dbus_interface`` keyword argument::
+
+ import dbus
+ bus = dbus.SystemBus()
+ eth0 = bus.get_object('org.freedesktop.NetworkManager',
+ '/org/freedesktop/NetworkManager/Devices/eth0')
+ props = eth0.getProperties(dbus_interface='org.freedesktop.NetworkManager.Devices')
+ # props is a tuple of properties, the first of which is the object path
+
+.. _dbus.Interface:
+
+As a short cut, if you're going to be calling many methods with the same
+interface, you can construct a ``dbus.Interface`` object and call
+methods on that, without needing to specify the interface again::
+
+ import dbus
+ bus = dbus.SystemBus()
+ eth0 = bus.get_object('org.freedesktop.NetworkManager',
+ '/org/freedesktop/NetworkManager/Devices/eth0')
+ eth0_dev_iface = dbus.Interface(eth0,
+ dbus_interface='org.freedesktop.NetworkManager.Devices')
+ props = eth0_dev_iface.getProperties()
+ # props is the same as before
+
+See also
+~~~~~~~~
+
+See the example in ``examples/example-client.py``. Before running it,
+you'll need to run ``examples/example-service.py`` in the background or
+in another shell.
+
+Data types
+----------
+
+Unlike Python, D-Bus is statically typed - each method has a certain
+*signature* representing the types of its arguments, and will not accept
+arguments of other types.
+
+D-Bus has an introspection mechanism, which ``dbus-python`` tries to use
+to discover the correct argument types. If this succeeds, Python types
+are converted into the right D-Bus data types automatically, if possible;
+``TypeError`` is raised if the type is inappropriate.
+
+If the introspection mechanism fails (or the argument's type is
+variant - see below), you have to provide arguments of
+the correct type. ``dbus-python`` provides Python types corresponding to
+the D-Bus data types, and a few native Python types are also converted to
+D-Bus data types automatically. If you use a type which isn't among these,
+a ``TypeError`` will be raised telling you that ``dbus-python`` was
+unable to guess the D-Bus signature.
+
+Basic types
+~~~~~~~~~~~
+
+The following basic data types are supported.
+
+========================== ============================= =====
+Python type converted to D-Bus type notes
+========================== ============================= =====
+D-Bus `proxy object`_ ObjectPath (signature 'o') `(+)`_
+`dbus.Interface`_ ObjectPath (signature 'o') `(+)`_
+`dbus.service.Object`_ ObjectPath (signature 'o') `(+)`_
+``dbus.Boolean`` Boolean (signature 'b') a subclass of ``int``
+``dbus.Byte`` byte (signature 'y') a subclass of ``int``
+``dbus.Int16`` 16-bit signed integer ('n') a subclass of ``int``
+``dbus.Int32`` 32-bit signed integer ('i') a subclass of ``int``
+``dbus.Int64`` 64-bit signed integer ('x') `(*)`_
+``dbus.UInt16`` 16-bit unsigned integer ('q') a subclass of ``int``
+``dbus.UInt32`` 32-bit unsigned integer ('u') `(*)_`
+``dbus.UInt64`` 64-bit unsigned integer ('t') `(*)_`
+``dbus.Double`` double-precision float ('d') a subclass of ``float``
+``dbus.ObjectPath`` object path ('o') a subclass of ``str``
+``dbus.Signature`` signature ('g') a subclass of ``str``
+``dbus.String`` string ('s') a subclass of
+ ``unicode``
+``dbus.UTF8String`` string ('s') a subclass of ``str``
+``bool`` Boolean ('b')
+``int`` or subclass 32-bit signed integer ('i')
+``long`` or subclass 64-bit signed integer ('x')
+``float`` or subclass double-precision float ('d')
+``str`` or subclass string ('s') must be valid UTF-8
+``unicode`` or subclass string ('s')
+========================== ============================= =====
+
+.. _(*):
+
+Types marked (*) may be a subclass of either ``int`` or ``long``, depending
+on platform.
+
+.. _(+):
+
+(+): D-Bus proxy objects, exported D-Bus service objects and anything
+else with the special attribute ``__dbus_object_path__``, which
+must be a string, are converted to their object-path. This might be
+useful if you're writing an object-oriented API using dbus-python.
+
+Basic type conversions
+~~~~~~~~~~~~~~~~~~~~~~
+
+If introspection succeeded, ``dbus-python`` will also accept:
+
+* for Boolean parameters, any object (converted as if via ``int(bool(...))``)
+* for byte parameters, a single-character string (converted as if via ``ord()``)
+* for byte and integer parameters, any integer (must be in the correct range)
+* for object-path and signature parameters, any ``str`` or ``unicode``
+ subclass (the value must follow the appropriate syntax)
+
+Container types
+~~~~~~~~~~~~~~~
+
+D-Bus supports four container types: array (a variable-length sequence of the
+same type), struct (a fixed-length sequence whose members may have
+different types), dictionary (a mapping from values of the same basic type to
+values of the same type), and variant (a container which may hold any
+D-Bus type, including another variant).
+
+Arrays are represented by Python lists, or by ``dbus.Array``, a subclass
+of ``list``. When sending an array, if an introspected signature is
+available, that will be used; otherwise, if the ``signature`` keyword
+parameter was passed to the ``Array`` constructor, that will be used to
+determine the contents' signature; otherwise, ``dbus-python`` will guess
+from the array's first item.
+
+The signature of an array is 'ax' where 'x' represents the signature of
+one item. For instance, you could also have 'as' (array of strings) or
+'a(ii)' (array of structs each containing two 32-bit integers).
+
+There's also a type ``dbus.ByteArray`` which is a subclass of ``str``,
+used as a more efficient representation of a D-Bus array of bytes
+(signature 'ay').
+
+Structs are represented by Python tuples, or by ``dbus.Struct``, a
+subclass of ``tuple``. When sending a struct, if an introspected signature is
+available, that will be used; otherwise, if the ``signature`` keyword
+parameter was passed to the ``Array`` constructor, that will be used to
+determine the contents' signature; otherwise, ``dbus-python`` will guess
+from the array's first item.
+
+The signature of a struct consists of the signatures of the contents,
+in parentheses - for instance '(is)' is the signature of a struct
+containing a 32-bit integer and a string.
+
+Dictionaries are represented by Python dictionaries, or by
+``dbus.Dictionary``, a subclass of ``dict``. When sending a dictionary,
+if an introspected signature is available, that will be used; otherwise,
+if the ``signature`` keyword parameter was passed to the ``Dictionary``
+constructor, that will be used to determine the contents' key and value
+signatures; otherwise, ``dbus-python`` will guess from an arbitrary item
+of the ``dict``.
+
+The signature of a dictionary is 'a{xy}' where 'x' represents the
+signature of the keys (which may not be a container type) and 'y'
+represents the signature of the values. For instance,
+'a{s(ii)}' is a dictionary where the keys are strings and the values are
+structs containing two 32-bit integers.
+
+Variants are represented by setting the ``variant_level`` keyword
+argument in the constructor of any D-Bus data type to a value greater
+than 0 (``variant_level`` 1 means a variant containing some other data type,
+``variant_level`` 2 means a variant containing a variant containing some
+other data type, and so on). If a non-variant is passed as an argument
+but introspection indicates that a variant is expected, it'll
+automatically be wrapped in a variant.
+
+The signature of a variant is 'v'.
+
+.. _byte_arrays and utf8_strings:
+
+Return values, and the ``byte_arrays`` and ``utf8_strings`` options
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If a D-Bus method returns no value, the Python proxy method will return
+``None``.
+
+If a D-Bus method returns one value, the Python proxy method will return
+that value as one of the ``dbus.`` types - by default, strings are
+returned as ``dbus.String`` (a subclass of Unicode) and byte arrays are
+returned as a ``dbus.Array`` of ``dbus.Byte``.
+
+If a D-Bus method returns multiple values, the Python proxy method
+will return a tuple containing those values.
+
+If you want strings returned as ``dbus.UTF8String`` (a subclass of
+``str``) pass the keyword parameter ``utf8_strings=True`` to the proxy
+method.
+
+If you want byte arrays returned as ``dbus.ByteArray`` (also a
+subclass of ``str`` - in practice, this is often what you want) pass
+the keyword parameter ``byte_arrays=True`` to the proxy method.
+
+.. --------------------------------------------------------------------
+
+Making asynchronous method calls
+================================
+
+Asynchronous (non-blocking) method calls allow multiple method calls to
+be in progress simultaneously, and allow your application to do other
+work while it's waiting for the results. To make asynchronous calls,
+you first need an event loop or "main loop".
+
+Setting up an event loop
+------------------------
+
+Currently, the only main loop supported by ``dbus-python`` is GLib.
+
+``dbus-python`` has a global default main loop, which is the easiest way
+to use this functionality. To arrange for the GLib main loop to be the
+default, use::
+
+ from dbus.mainloop.glib import DBusGMainLoop
+
+ DBusGMainLoop(set_as_default=True)
+
+You must do this before `connecting to the bus`_.
+
+Actually starting the main loop is as usual for ``pygobject``::
+
+ import gobject
+
+ loop = gobject.MainLoop()
+ loop.run()
+
+While ``loop.run()`` is executing, GLib will run your callbacks when
+appropriate. To stop, call ``loop.quit()``.
+
+You can also set a main loop on a per-connection basis, by passing a
+main loop to the Bus constructor::
+
+ import dbus
+ from dbus.mainloop.glib import DBusGMainLoop
+
+ dbus_loop = DBusGMainLoop()
+
+ bus = dbus.SessionBus(mainloop=dbus_loop)
+
+This isn't very useful until we support more than one main loop, though.
+
+Backwards compatibility: ``dbus.glib``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In versions of ``dbus-python`` prior to 0.80, the way to set GLib as the
+default main loop was::
+
+ import dbus.glib
+
+Executing that import statement would automatically load the GLib main
+loop and make this the default. This is now deprecated, since it's
+highly non-obvious, but may be useful if you want to write or understand
+backwards-compatible code.
+
+The Qt main loop
+~~~~~~~~~~~~~~~~
+
+PyQt v4.2 and later includes support for integrating dbus-python with
+the Qt event loop. To connect D-Bus to this main loop, call
+``dbus.mainloop.qt.DBusQtMainLoop`` instead of
+``dbus.mainloop.glib.DBusGMainLoop``. Otherwise the Qt loop is used in
+exactly the same way as the GLib loop.
+
+Making asynchronous calls
+-------------------------
+
+To make a call asynchronous, pass two callables as keyword arguments
+``reply_handler`` and ``error_handler`` to the proxy method. The proxy
+method will immediately return `None`. At some later time, when the event
+loop is running, one of these will happen: either
+
+* the ``reply_handler`` will be called with the method's return values
+ as arguments; or
+
+* the ``error_handler`` will be called with one argument, an instance of
+ ``DBusException`` representing a remote exception.
+
+See also
+~~~~~~~~
+
+``examples/example-async-client.py`` makes asynchronous method calls to
+the service provided by ``examples/example-service.py`` which return
+either a value or an exception. As for ``examples/example-client.py``,
+you need to run ``examples/example-service.py`` in the background or
+in another shell first.
+
+.. --------------------------------------------------------------------
+
+Receiving signals
+=================
+
+To receive signals, the Bus needs to be connected to an event loop - see
+section `Setting up an event loop`_. Signals will only be received while
+the event loop is running.
+
+Signal matching
+---------------
+
+To respond to signals, you can use the ``add_signal_receiver`` method on
+`Bus objects`_. This arranges for a callback to be called when a
+matching signal is received, and has the following arguments:
+
+* a callable (the ``handler_function``) which will be called by the event loop
+ when the signal is received - its parameters will be the arguments of
+ the signal
+
+* the signal name, ``signal_name``: here None (the default) matches all names
+
+* the D-Bus interface, ``dbus_interface``: again None is the default,
+ and matches all interfaces
+
+* a sender bus name (well-known or unique), ``bus_name``: None is again
+ the default, and matches all senders. Well-known names match signals
+ from whatever application is currently the primary owner of that
+ well-known name.
+
+* a sender object path, ``path``: once again None is the default and
+ matches all object paths
+
+``add_signal_receiver`` also has keyword arguments ``utf8_strings`` and
+``byte_arrays`` which influence the types used when calling the
+handler function, in the same way as the `byte_arrays and utf8_strings`_
+options on proxy methods.
+
+``add_signal_receiver`` returns a ``SignalMatch`` object. Its only
+useful public API at the moment is a ``remove`` method with no
+arguments, which removes the signal match from the connection.
+
+Getting more information from a signal
+--------------------------------------
+
+You can also arrange for more information to be passed to the handler
+function. If you pass the keyword arguments ``sender_keyword``,
+``destination_keyword``, ``interface_keyword``, ``member_keyword`` or
+``path_keyword`` to the ``connect_to_signal`` method, the appropriate
+part of the signal message will be passed to the handler function as a
+keyword argument: for instance if you use ::
+
+ def handler(sender=None):
+ print "got signal from %r" % sender
+
+ iface.connect_to_signal("Hello", handler, sender_keyword='sender')
+
+and a signal ``Hello`` with no arguments is received from
+``com.example.Foo``, the ``handler`` function will be called with
+``sender='com.example.Foo'``.
+
+String argument matching
+------------------------
+
+If there are keyword parameters for the form ``arg``\ *n* where n is a
+small non-negative number, their values must be ``unicode`` objects
+or UTF-8 strings. The handler will only be called if that argument
+of the signal (numbered from zero) is a D-Bus string (in particular,
+not an object-path or a signature) with that value.
+
+.. *this comment is to stop the above breaking vim syntax highlighting*
+
+Receiving signals from a proxy object
+-------------------------------------
+
+`Proxy objects`_ have a special method ``connect_to_signal`` which
+arranges for a callback to be called when a signal is received
+from the corresponding remote object. The parameters are:
+
+* the name of the signal
+
+* a callable (the handler function) which will be called by the event loop
+ when the signal is received - its parameters will be the arguments of
+ the signal
+
+* the handler function, a callable: the same as for ``add_signal_receiver``
+
+* the keyword argument ``dbus_interface`` qualifies the name with its
+ interface
+
+`dbus.Interface` objects have a similar ``connect_to_signal`` method,
+but in this case you don't need the ``dbus_interface`` keyword argument
+since the interface to use is already known.
+
+The same extra keyword arguments as for ``add_signal_receiver`` are also
+available, and just like ``add_signal_receiver``, it returns a
+SignalMatch.
+
+You shouldn't use proxy objects just to listen to signals, since they
+might activate the relevant service when created, but if you already have a
+proxy object in order to call methods, it's often convenient to use it to add
+signal matches too.
+
+See also
+--------
+
+``examples/signal-recipient.py`` receives signals - it demonstrates
+general signal matching as well as ``connect_to_signal``. Before running it,
+you'll need to run ``examples/signal-emitter.py`` in the background or
+in another shell.
+
+.. _BusName:
+
+.. --------------------------------------------------------------------
+
+Claiming a bus name
+===================
+
+FIXME describe `BusName`_ - perhaps fix its API first?
+
+The unique-instance idiom
+-------------------------
+
+FIXME provide exemplary code, put it in examples
+
+.. _exported object:
+.. _exported objects:
+
+.. --------------------------------------------------------------------
+
+Exporting objects
+=================
+
+Objects made available to other applications over D-Bus are said to be
+*exported*. All subclasses of ``dbus.service.Object`` are automatically
+exported.
+
+To export objects, the Bus needs to be connected to an event loop - see
+section `Setting up an event loop`_. Exported methods will only be called,
+and queued signals will only be sent, while the event loop is running.
+
+.. _dbus.service.Object:
+
+Inheriting from ``dbus.service.Object``
+---------------------------------------
+
+To export an object onto the Bus, just subclass
+``dbus.service.Object``. Object expects either a `BusName`_ or a `Bus
+object`_, and an object-path, to be passed to its constructor: arrange
+for this information to be available. For example::
+
+ class Example(dbus.service.Object):
+ def __init__(self, object_path):
+ dbus.service.Object.__init__(self, dbus.SessionBus(), path)
+
+This object will automatically support introspection, but won't do
+anything particularly interesting. To fix that, you'll need to export some
+methods and signals too.
+
+FIXME also mention dbus.gobject.ExportedGObject once I've written it
+
+Exporting methods with ``dbus.service.method``
+----------------------------------------------
+
+To export a method, use the decorator ``dbus.service.method``. For
+example::
+
+ class Example(dbus.service.Object):
+ def __init__(self, object_path):
+ dbus.service.Object.__init__(self, dbus.SessionBus(), path)
+
+ @dbus.service.method(dbus_interface='com.example.Sample',
+ in_signature='v', out_signature='s')
+ def StringifyVariant(self, variant):
+ return str(variant)
+
+The ``in_signature`` and ``out_signature`` are D-Bus signature strings
+as described in `Data Types`_.
+
+As well as the keywords shown, you can pass ``utf8_strings`` and
+``byte_arrays`` keyword arguments, which influence the types which will
+be passed to the decorated method when it's called via D-Bus, in the
+same way that the `byte_arrays and utf8_strings`_ options affect the
+return value of a proxy method.
+
+You can find a simple example in ``examples/example-service.py``, which
+we used earlier to demonstrate ``examples/example-client.py``.
+
+Finding out the caller's bus name
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``method`` decorator accepts a ``sender_keyword`` keyword argument.
+If you set that to a string, the unique bus name of the sender will be
+passed to the decorated method as a keyword argument of that name::
+
+ class Example(dbus.service.Object):
+ def __init__(self, object_path):
+ dbus.service.Object.__init__(self, dbus.SessionBus(), path)
+
+ @dbus.service.method(dbus_interface='com.example.Sample',
+ in_signature='', out_signature='s',
+ sender_keyword='sender')
+ def SayHello(self, sender=None):
+ return 'Hello, %s!' % sender
+ # -> something like 'Hello, :1.1!'
+
+Asynchronous method implementations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+FIXME and also add an example, perhaps examples/example-async-service.py
+
+Emitting signals with ``dbus.service.signal``
+---------------------------------------------
+
+To export a signal, use the decorator ``dbus.service.signal``; to emit
+that signal, call the decorated method. The decorated method can also
+contain code which will be run when called, as usual. For example::
+
+ class Example(dbus.service.Object):
+ def __init__(self, object_path):
+ dbus.service.Object.__init__(self, dbus.SessionBus(), path)
+
+ @dbus.service.signal(dbus_interface='com.example.Sample',
+ signature='us')
+ def NumberOfBottlesChanged(self, number, contents):
+ print "%d bottles of %s on the wall" % (number, contents)
+
+ e = Example('/bottle-counter')
+ e.NumberOfBottlesChanged(100, 'beer')
+ # -> emits com.example.Sample.NumberOfBottlesChanged(100, 'beer')
+ # and prints "100 bottles of beer on the wall"
+
+The signal will be queued for sending when the decorated method returns -
+you can prevent the signal from being sent by raising an exception
+from the decorated method (for instance, if the parameters are
+inappropriate). The signal will only actually be sent when the event loop
+next runs.
+
+Example
+~~~~~~~
+
+``examples/example-signal-emitter.py`` emits some signals on demand when
+one of its methods is called. (In reality, you'd emit a signal when some
+sort of internal state changed, which may or may not be triggered by a
+D-Bus method call.)
+
+.. --------------------------------------------------------------------
+
+License for this document
+=========================
+
+Copyright 2006-2007 `Collabora Ltd.`_
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+..
+ vim:set ft=rst sw=4 sts=4 et tw=72: