From 233f8d0e33c3417c4c9abe2790fc949df19b879d Mon Sep 17 00:00:00 2001 From: Seth Nickell Date: Sun, 11 Jul 2004 03:02:14 +0000 Subject: [PATCH] 2004-07-10 Seth Nickell * python/dbus.py: Add "message" argument to service-side dbus.Object methods. This will break existing services written using the python bindings, but will allow extraction of all the message information (e.g. who its from). Add improved "object oriented" signal handling/emission. * python/examples/example-service.py: Nix this example. * python/examples/example-signal-emitter.py: * python/examples/example-signal-recipient.py: Two new examples that show how to emit and receive signals using the new APIs. * python/examples/example-signals.py: * python/examples/gconf-proxy-service.py: * python/examples/gconf-proxy-service2.py: Add "message" argument to service methods. --- ChangeLog | 27 +++++++++ python/dbus.py | 91 +++++++++++++++++++---------- python/examples/example-service.py | 2 +- python/examples/example-signal-emitter.py | 18 ++++++ python/examples/example-signal-recipient.py | 19 ++++++ python/examples/example-signals.py | 27 --------- python/examples/gconf-proxy-service.py | 8 +-- python/examples/gconf-proxy-service2.py | 2 +- 8 files changed, 131 insertions(+), 63 deletions(-) create mode 100644 python/examples/example-signal-emitter.py create mode 100644 python/examples/example-signal-recipient.py delete mode 100644 python/examples/example-signals.py diff --git a/ChangeLog b/ChangeLog index 3e073cd..1e66410 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,30 @@ +2004-07-10 Seth Nickell + + * python/dbus.py: + + Add "message" argument to service-side dbus.Object + methods. This will break existing services written + using the python bindings, but will allow extraction + of all the message information (e.g. who its from). + + Add improved "object oriented" signal handling/emission. + + * python/examples/example-service.py: + + Nix this example. + + * python/examples/example-signal-emitter.py: + * python/examples/example-signal-recipient.py: + + Two new examples that show how to emit and receive + signals using the new APIs. + + * python/examples/example-signals.py: + * python/examples/gconf-proxy-service.py: + * python/examples/gconf-proxy-service2.py: + + Add "message" argument to service methods. + 2004-06-28 Kay Sievers * bus/driver.c (bus_driver_handle_get_connection_unix_user) diff --git a/python/dbus.py b/python/dbus.py index 13ea1ad..e53bf23 100644 --- a/python/dbus.py +++ b/python/dbus.py @@ -63,42 +63,53 @@ class Bus: if (glib_mainloop): self._connection.setup_with_g_main() + def get_connection(self): + return self._connection + def get_service(self, service_name="org.freedesktop.Broadcast"): """Get one of the RemoteServices connected to this Bus. service_name is just a string of the form 'com.widgetcorp.MyService' """ - return RemoteService(self._connection, service_name) + return RemoteService(self, service_name) - def add_signal_receiver(self, receiver, interface=None, service=None, path=None): - match_rule = self._get_match_rule(interface, service, path) + def add_signal_receiver(self, handler_function, signal_name=None, interface=None, service=None, path=None): + match_rule = self._get_match_rule(signal_name, interface, service, path) if (not self._match_rule_to_receivers.has_key(match_rule)): self._match_rule_to_receivers[match_rule] = [ ] - self._match_rule_to_receivers[match_rule].append(receiver) + self._match_rule_to_receivers[match_rule].append(handler_function) dbus_bindings.bus_add_match(self._connection, match_rule) - def remove_signal_receiver(self, receiver, interface=None, service=None, path=None): - match_rule = self._get_match_rule(interface, service, path) + def remove_signal_receiver(self, handler_function, signal_name=None, interface=None, service=None, path=None): + match_rule = self._get_match_rule(signal_name, interface, service, path) if self._match_rule_to_receivers.has_key(match_rule): - if self._match_rule_to_receivers[match_rule].__contains__(receiver): - self._match_rule_to_receivers[match_rule].remove(receiver) + if self._match_rule_to_receivers[match_rule].__contains__(handler_function): + self._match_rule_to_receivers[match_rule].remove(handler_function) dbus_bindings.bus_remove_match(self._connection, match_rule) def get_connection(self): """Get the dbus_bindings.Connection object associated with this Bus""" return self._connection - def _get_match_rule(self, interface, service, path): -## if (interface): -## match_rule = match_rule + ",interface='%s'" % (interface) -## if (service): -## match_rule = match_rule + ",service='%s'" % (service) -## if (path): -## match_rule = match_rule + ",path='%s'" % (path) - # FIXME: use the service here too!!! - return "type='signal',interface='%s',path='%s'" % (interface, path) + def _get_match_rule(self, signal_name, interface, service, path): + match_rule = "type='signal'" + if (interface): + match_rule = match_rule + ",interface='%s'" % (interface) + if (service): + if (service[0] != ':' and service != "org.freedesktop.DBus"): + bus_service = self.get_service("org.freedesktop.DBus") + bus_object = bus_service.get_object('/org/freedesktop/DBus', + 'org.freedesktop.DBus') + service = bus_object.GetServiceOwner(service) + + match_rule = match_rule + ",sender='%s'" % (service) + if (path): + match_rule = match_rule + ",path='%s'" % (path) + if (signal_name): + match_rule = match_rule + ",member='%s'" % (signal_name) + return match_rule def _signal_func(self, connection, message): if (message.get_type() != dbus_bindings.MESSAGE_TYPE_SIGNAL): @@ -109,7 +120,7 @@ class Bus: path = message.get_path() member = message.get_member() - match_rule = self._get_match_rule(interface, service, path) + match_rule = self._get_match_rule(member, interface, service, path) if (self._match_rule_to_receivers.has_key(match_rule)): receivers = self._match_rule_to_receivers[match_rule] @@ -143,17 +154,24 @@ class RemoteObject: A RemoteObject is provided by a RemoteService on a particular Bus. RemoteObjects have member functions, and can be called like normal Python objects. """ - def __init__(self, connection, service_name, object_path, interface): - self._connection = connection - self._service_name = service_name + def __init__(self, service, object_path, interface): + self._service = service self._object_path = object_path self._interface = interface + def connect_to_signal(self, signal_name, handler_function): + self._service.get_bus().add_signal_receiver(handler_function, + signal_name=signal_name, + interface=self._interface, + service=self._service.get_service_name(), + path=self._object_path) + def __getattr__(self, member): if member == '__call__': return object.__call__ else: - return RemoteMethod(self._connection, self._service_name, + return RemoteMethod(self._service.get_bus().get_connection(), + self._service.get_service_name(), self._object_path, self._interface, member) @@ -220,7 +238,7 @@ def _dispatch_dbus_method_call(target_method, argument_list, message): exceptions, etc, and generates a reply to the DBus Message message """ try: - retval = target_method(*argument_list) + retval = target_method(message, *argument_list) except Exception, e: if e.__module__ == '__main__': # FIXME: is it right to use .__name__ here? @@ -267,10 +285,8 @@ class Object: self._connection.register_object_path(object_path, self._unregister_cb, self._message_cb) - def broadcast_signal(self, interface, signal_name): + def emit_signal(self, interface, signal_name): message = dbus_bindings.Signal(self._object_path, interface, signal_name) - #FIXME: need to set_sender, but it always disconnects when we do this - #message.set_sender(self._service.get_service_name()) self._connection.send(message) def _unregister_cb(self, connection): @@ -312,8 +328,16 @@ class ObjectTree: self._method_name_to_method = _build_method_dictionary(dbus_methods) self._connection.register_fallback(base_path, self._unregister_cb, self._message_cb) + + def relative_path_to_object_path(self, relative_path): + return self._base_path + relative_path - def object_method_called(self, object_path, method_name, argument_list): + def broadcast_signal(self, interface, signal_name, relative_path): + object_path = self.relative_path_to_object_path(relative_path) + message = dbus_bindings.Signal(object_path, interface, signal_name) + self._connection.send(message) + + def object_method_called(self, relative_path, method_name, argument_list): """Override this method. Called with, object_path, the relative path of the object under the base_path, the name of the method invoked, and a list of arguments """ @@ -348,10 +372,16 @@ class RemoteService: receives signals from all applications on the Bus. """ - def __init__(self, connection, service_name): - self._connection = connection + def __init__(self, bus, service_name): + self._bus = bus self._service_name = service_name + def get_bus(self): + return self._bus + + def get_service_name(self): + return self._service_name + def get_object(self, object_path, interface): """Get an object provided by this Service that implements a particular interface. object_path is a string of the form @@ -360,5 +390,6 @@ class RemoteService: 'com.widgetcorp.MyInterface', and mostly just defines the set of member functions that will be present in the object. """ - return RemoteObject(self._connection, self._service_name, object_path, interface) + return RemoteObject(self, object_path, interface) +ObjectPath = dbus_bindings.ObjectPath diff --git a/python/examples/example-service.py b/python/examples/example-service.py index 974f8b1..4f753cd 100644 --- a/python/examples/example-service.py +++ b/python/examples/example-service.py @@ -7,7 +7,7 @@ class SomeObject(dbus.Object): def __init__(self, service): dbus.Object.__init__(self, "/SomeObject", service, [self.HelloWorld]) - def HelloWorld(self, hello_message): + def HelloWorld(self, message, hello_message): print (hello_message) return ["Hello", "from example-service.py"] diff --git a/python/examples/example-signal-emitter.py b/python/examples/example-signal-emitter.py new file mode 100644 index 0000000..edabfd7 --- /dev/null +++ b/python/examples/example-signal-emitter.py @@ -0,0 +1,18 @@ +import dbus +import gtk + +class TestObject(dbus.Object): + def __init__(self, service): + dbus.Object.__init__(self, "/object", service, [self.HelloWorld]) + + def emitHelloSignal(self, message): + # Emit the signal + self.emit_signal(interface="org.designfu.TestService", + signal_name="hello") + +session_bus = dbus.SessionBus() +service = dbus.Service("org.designfu.TestService", bus=session_bus) +object = TestObject(service) + +gtk.main() +A diff --git a/python/examples/example-signal-recipient.py b/python/examples/example-signal-recipient.py new file mode 100644 index 0000000..65e5933 --- /dev/null +++ b/python/examples/example-signal-recipient.py @@ -0,0 +1,19 @@ +import gtk +import dbus + +bus = dbus.SessionBus() +service = bus.get_service("org.designfu.TestService") +object = service.get_object("/org/designfu/TestService/object", "org.designfu.TestService") + +def hello_signal_handler(interface, signal_name, service, path, message): + print ("Received signal '%s.%s' from object '%s%s'" + % (interface, signal_name, service, path)) + + +object.connect_to_signal("hello", hello_signal_handler) + +# Tell the remote object to emit the signal +object.emitHelloSignal() + +gtk.main() + diff --git a/python/examples/example-signals.py b/python/examples/example-signals.py deleted file mode 100644 index 8e31956..0000000 --- a/python/examples/example-signals.py +++ /dev/null @@ -1,27 +0,0 @@ -import pygtk -import gtk - -import dbus - -class SignalFrom(dbus.Object): - def __init__(self, service): - dbus.Object.__init__(self, "/", [], service) - -def signal_to(interface, signal_name, service, path): - print ("Received signal '%s.%s' from '%s%s'" % (interface, signal_name, service, path)) - -bus = dbus.Bus() -bus.add_signal_receiver(signal_to, - "org.designfu.SignalInterface", - "org.designfu.SignalService", - "/") - - -service = dbus.Service("org.designfu.SignalService", bus) -signal_from = SignalFrom(service) - -signal_from.broadcast_signal("org.designfu.SignalInterface", "HelloWorld") - -gtk.main() - - diff --git a/python/examples/gconf-proxy-service.py b/python/examples/gconf-proxy-service.py index 76e43ce..25ecbe9 100644 --- a/python/examples/gconf-proxy-service.py +++ b/python/examples/gconf-proxy-service.py @@ -16,19 +16,19 @@ class GConfService(dbus.Service): self.client = gconf.client_get_default() - def getString(self, object_path): + def getString(self, message, object_path): print ("getString called on GConf key %s" % (object_path)) return self.client.get_string(object_path) - def setString(self, object_path, new_value): + def setString(self, message, object_path, new_value): print ("setString called on GConf key %s" % (object_path)) self.client.set_string(object_path, new_value) - def getInt(self, object_path): + def getInt(self, message, object_path): print ("getInt called on GConf key %s" % (object_path)) return self.client.get_int(object_path) - def setInt(self, object_path, new_value): + def setInt(self, message, object_path, new_value): print ("setInt called on GConf key %s" % (object_path)) self.client.set_int(object_path, new_value) diff --git a/python/examples/gconf-proxy-service2.py b/python/examples/gconf-proxy-service2.py index 4cec860..5ba77db 100644 --- a/python/examples/gconf-proxy-service2.py +++ b/python/examples/gconf-proxy-service2.py @@ -16,7 +16,7 @@ class GConfService(dbus.Service): self.client = gconf.client_get_default() - def object_method_called(self, object_path, method_name, argument_list): + def object_method_called(self, message, object_path, method_name, argument_list): print ("Method %s called on GConf key %s" % (method_name, object_path)) if "getString" == method_name: -- 2.7.4