--- dbus-0.23.4.old/python/dbus.py 2005-05-08 17:30:21.000000000 +0100 +++ dbus-0.23.4/python/dbus.py 2005-05-09 00:54:28.761878056 +0100 @@ -49,7 +49,73 @@ if not _threads_initialized: dbus_bindings.init_gthreads () _threads_initialized = 1 + +class DBusMatchRule: + """This class represents a dbus rule used to filter signals. + When a rule matches a filter, the signal is propagated to the handler_funtions + """ + def __init__(self,bus,signal_name,interface,service,path): + self.handler_functions = [] + + self.bus = bus + self.signal_name = signal_name + self.interface = interface + self.service = service + self.path = path + + def matches_rule(self,rule): + """Returns True if this rule's parameters has the same values as the arguments + passed in. + The only exception is the optional service which will only be verified if the + rule's service isn't None + """ + matches = (self.signal_name == rule.signal_name and + self.interface == rule.interface and + self.path == rule.path) + + if (self.service): + matches = matches and (self.service == rule.service) + + return matches + + def __cmp__(self,rule): + """Custom comparator for DBusMatchRule because some class arguments + need to be compared + """ + if not isinstance(rule,DBusMatchRule): + return -1 + + if(self.signal_name == rule.signal_name and + self.interface == rule.interface and + self.path == self.path and + self.service == rule.service): + return 0 + else: + return 1 + + def __repr__(self): + """Returns a custom representation of this DBusMatchRule that can + be used with dbus_bindings + """ + repr = "type='signal'" + if (self.interface): + repr = repr + ",interface='%s'" % (self.interface) + + if (self.service): + if (self.service[0] != ':' and self.service != "org.freedesktop.DBus"): + bus_service = bus.get_service("org.freedesktop.DBus") + bus_object = bus_service.get_object('/org/freedesktop/DBus', + 'org.freedesktop.DBus') + service = bus_object.GetServiceOwner(service) + + repr = repr + ",sender='%s'" % (self.service) + if (self.path): + repr = repr + ",path='%s'" % (self.path) + if (self.signal_name): + repr = repr + ",member='%s'" % (self.signal_name) + return repr + class Bus: """A connection to a DBus daemon. @@ -70,7 +136,7 @@ self._connection = dbus_bindings.bus_get(bus_type) self._connection.add_filter(self._signal_func) - self._match_rule_to_receivers = { } + self._dbus_rules = [ ] if (glib_mainloop): self._connection.setup_with_g_main() @@ -84,21 +150,30 @@ return RemoteService(self, service_name) 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(handler_function) - - dbus_bindings.bus_add_match(self._connection, match_rule) + match_rule = DBusMatchRule(self,signal_name,interface,service,path) + + current_rules = [rule for rule in self._dbus_rules if rule == match_rule] + #if there are any filters that match this receiver's arguments + if (len(current_rules) > 0): + #simply append a new handler + for rule in current_rules: + rule.handler_functions.append(rule) + else: + #otherwise add this rule to the _dbus_rules + match_rule.handler_functions.append(handler_function) + self._dbus_rules.append(match_rule) + dbus_bindings.bus_add_match(self._connection, repr(match_rule)) 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) + match_rule = DBusMatchRule(self,signal_name,interface,service,path) - if self._match_rule_to_receivers.has_key(match_rule): - 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) + current_rules = [rule for rule in self._dbus_rules if rule == match_rule] + for rule in current_rules: + if rule.handler_functions.__contains__(handler_function): + rule.handler_functions.remove(handler_function) + #if there aren't any more handlers left, remove the match from dbus + if (len(rule.handler_functions) > 0): + dbus_bindings.bus_remove_match(self._connection, repr(rule)) def get_connection(self): """Get the dbus_bindings.Connection object associated with this Bus""" @@ -108,24 +183,6 @@ """Get the unix user for the given service_name on this Bus""" return dbus_bindings.bus_get_unix_user(self._connection, service_name) - 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): return dbus_bindings.HANDLER_RESULT_NOT_YET_HANDLED @@ -135,13 +192,13 @@ path = message.get_path() member = message.get_member() - match_rule = self._get_match_rule(member, interface, service, path) + match_rule = DBusMatchRule(self,member,interface,service,path) + args = [interface,member,service,path,message] - if (self._match_rule_to_receivers.has_key(match_rule)): - receivers = self._match_rule_to_receivers[match_rule] - args = [interface, member, service, path, message] - for receiver in receivers: - receiver(*args) + for rule in self._dbus_rules: + if (rule.matches_rule(match_rule)): + for handler in rule.handler_functions: + handler(*args) def activate_service(self, service): return dbus_bindings.bus_activate_service(self._connection, service)