Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/tutorius/TProbe.py
diff options
context:
space:
mode:
Diffstat (limited to 'tutorius/TProbe.py')
-rw-r--r--tutorius/TProbe.py165
1 files changed, 88 insertions, 77 deletions
diff --git a/tutorius/TProbe.py b/tutorius/TProbe.py
index ec0f9a3..6c0883a 100644
--- a/tutorius/TProbe.py
+++ b/tutorius/TProbe.py
@@ -10,7 +10,9 @@ import cPickle as pickle
import sugar.tutorius.addon as addon
from sugar.tutorius.services import ObjectStore
+from sugar.tutorius.properties import TPropContainer
+from sugar.tutorius.dbustools import remote_call, save_args
import copy
"""
@@ -157,38 +159,21 @@ class TProbe(dbus.service.Object):
in_signature='s', out_signature='s')
def subscribe(self, pickled_event):
"""
- Subscribe to a Gtk Widget Event
- @param pickled_event string pickled Event
+ Subscribe to an Event
+ @param pickled_event string pickled EventFilter
@return string unique name of registered event
"""
- event = pickle.loads(str(pickled_event))
-
- # TODO elavoie 2009-07-25 Move to a reference counting implementation
- # to avoid duplicating eventfilters when the event signature is the
- # same
-
- # For now we will assume every probe is inserted in a GTK activity,
- # however, in the future this should be moved in a subclass
- eventfilter = addon.create("GtkWidgetEventFilter")
-
- # There might be a validation of the Address in source in the future
- # and a partial resolution to extract the object_id from the address
- eventfilter.object_id = event.source
-
- # TODO elavoie 2009-07-19
- # There should be a type translation from a tutorius type
- # to a GTK type here
- eventfilter.event_name = event.type
+ eventfilter = pickle.loads(str(pickled_event))
# The callback uses the event defined previously and each
# successive call to subscribe will register a different
# callback that references a different event
def callback(*args):
- self.notify(event)
+ self.notify(eventfilter)
eventfilter.install_handlers(callback, activity=self._activity)
- name = self._generate_event_reference(event)
+ name = self._generate_event_reference(eventfilter)
self._subscribedEvents[name] = eventfilter
return name
@@ -215,7 +200,14 @@ class TProbe(dbus.service.Object):
# The actual method we will call on the probe to send events
def notify(self, event):
- self.eventOccured(pickle.dumps(event))
+ logging.debug("TProbe :: notify event %s", str(event))
+ #HACK: reinstanciate the event with it's properties, to clear
+ # any internal state from getting pickled
+ if isinstance(event, TPropContainer):
+ newevent = type(event)(**event._props)
+ else:
+ newevent = event
+ self.eventOccured(pickle.dumps(newevent))
# Return a unique name for this action
def _generate_action_reference(self, action):
@@ -232,7 +224,7 @@ class TProbe(dbus.service.Object):
# Return a unique name for this event
def _generate_event_reference(self, event):
# TODO elavoie 2009-07-25 Should return a universal address
- name = event.type
+ name = event.__class__.__name__
suffix = 1
while self._subscribedEvents.has_key(name+str(suffix)):
@@ -270,36 +262,51 @@ class ProbeProxy:
self._probe = dbus.Interface(self._object, "org.tutorius.ProbeInterface")
self._actions = {}
- self._events = {}
# We keep those two data structures to be able to have multiple callbacks
# for the same event and be able to remove them independently
+ # _subscribedEvents holds a list of callback addresses's for each event
+ # _registeredCallbacks holds the functions to call for each address
self._subscribedEvents = {}
self._registeredCallbacks = {}
- def _handle_signal(pickled_event):
- event = pickle.loads(str(pickled_event))
- if self._registeredCallbacks.has_key(event):
- for callback in self._registeredCallbacks[event].itervalues():
- callback(event)
-
- self._object.connect_to_signal("eventOccured", _handle_signal, dbus_interface="org.tutorius.ProbeInterface")
-
+ self._object.connect_to_signal("eventOccured", self._handle_signal, dbus_interface="org.tutorius.ProbeInterface")
+
+ def _handle_signal(self, pickled_event):
+ event = pickle.loads(str(pickled_event))
+ logging.debug("ProbeProxy :: Received Event : %s %s", str(event), str(event._props.items()))
+
+ logging.debug("ProbeProxy :: Currently %d events registered", len(self._registeredCallbacks))
+ if self._registeredCallbacks.has_key(event):
+ for callback in self._registeredCallbacks[event].itervalues():
+ callback(event)
+ else:
+ for event in self._registeredCallbacks.keys():
+ logging.debug("==== %s", str(event._props.items()))
+ logging.debug("ProbeProxy :: Event does not appear to be registered")
+
def isAlive(self):
try:
return self._probe.ping() == "alive"
except:
return False
- def install(self, action):
+ def __update_action(self, action, address):
+ self._actions[action] = str(address)
+
+ def __clear_action(self, action):
+ self._actions.pop(action, None)
+
+ def install(self, action, block=False):
"""
Install an action on the TProbe's activity
@param action Action to install
@return None
"""
- address = str(self._probe.install(pickle.dumps(action)))
- self._actions[action] = address
+ remote_call(self._probe.install, (pickle.dumps(action),),
+ save_args(self.__update_action, action),
+ block=block)
- def update(self, action):
+ def update(self, action, block=False):
"""
Update an already installed action's properties and run it again
@param action Action to update
@@ -308,46 +315,32 @@ class ProbeProxy:
if not action in self._actions:
raise RuntimeWarning("Action not installed")
return
- self._probe.update(self._actions[action], pickle.dumps(action._props))
+ remote_call(self._probe.update, (self._actions[action], pickle.dumps(action._props)), block=block)
- def uninstall(self, action):
+ def uninstall(self, action, block=False):
"""
Uninstall an installed action
@param action Action to uninstall
"""
if action in self._actions:
- self._probe.uninstall(self._actions.pop(action))
+ remote_call(self._probe.uninstall,(self._actions.pop(action),), block=block)
- def uninstall_all(self):
+ def uninstall_all(self, block=False):
"""
Uninstall all installed actions
@return None
"""
for action in self._actions.keys():
- self.uninstall(action)
-
- def subscribe(self, event, callback):
- """
- Register an event listener
- @param event Event to listen for
- @param callback callable that will be called when the event occurs
- @return address identifier used for unsubscribing
- """
- # TODO elavoie 2009-07-25 When we will allow for patterns both
- # for event types and sources, we will need to revise the lookup
- # mecanism for which callback function to call
- if (event, callback) in self._events:
- raise RuntimeError("event already registered for callback")
- return
+ self.uninstall(action, block)
+ def __update_event(self, event, callback, address):
+ logging.debug("ProbeProxy :: Registered event %s with address %s", str(event), str(address))
# Since multiple callbacks could be associated to the same
# event signature, we will store multiple callbacks
# in a dictionary indexed by the unique address
# given for this subscribtion and access this
# dictionary from another one indexed by event
- address = str(self._probe.subscribe(pickle.dumps(event)))
-
- self._events[(event, callback)] = address
+ address = str(address)
# We use the event object as a key
if not self._registeredCallbacks.has_key(event):
@@ -371,19 +364,7 @@ class ProbeProxy:
return address
- def unsubscribe(self, event, callback):
- """
- Unregister an event listener
- @param address identifier given by subscribe()
- @return None
- """
- if not (event, callback) in self._events:
- raise RuntimeWarning("callback/event not subscribed")
- return
-
- address = self._events.pop((event, callback))
- self._probe.unsubscribe()
-
+ def __clear_event(self, address):
# Cleanup everything
if self._subscribedEvents.has_key(address):
event = self._subscribedEvents[address]
@@ -397,13 +378,43 @@ class ProbeProxy:
self._subscribedEvents.pop(address)
- def unsubscribe_all(self):
+ def subscribe(self, event, callback, block=True):
+ """
+ Register an event listener
+ @param event Event to listen for
+ @param callback callable that will be called when the event occurs
+ @return address identifier used for unsubscribing
+ """
+ if not block:
+ raise RuntimeError("This function does not allow non-blocking mode yet")
+
+ # TODO elavoie 2009-07-25 When we will allow for patterns both
+ # for event types and sources, we will need to revise the lookup
+ # mecanism for which callback function to call
+ return remote_call(self._probe.subscribe, (pickle.dumps(event),),
+ save_args(self.__update_event, event, callback),
+ block=block)
+
+ def unsubscribe(self, address, block=False):
+ """
+ Unregister an event listener
+ @param address identifier given by subscribe()
+ @return None
+ """
+ if address in self._subscribedEvents.keys():
+ remote_call(self._probe.unsubscribe, (address,),
+ return_cb=save_args(self.__clear_event, address),
+ block=block)
+ else:
+ logging.debug("ProbeProxy :: unsubsribe address %s failed : not registered", address)
+
+ def unsubscribe_all(self, block=False):
"""
Unregister all event listeners
@return None
"""
- for event, callback in self._events.keys():
- self.unsubscribe(event, callback)
+ for address in self._subscribedEvents.keys():
+ self.unsubscribe(address, block)
class ProbeManager(object):
"""
@@ -471,9 +482,9 @@ class ProbeManager(object):
else:
raise RuntimeWarning("No activity attached")
- def unsubscribe(self, event, callback):
+ def unsubscribe(self, address):
if self.currentActivity:
- return self._probes[self.currentActivity].unsubscribe(event, callback)
+ return self._probes[self.currentActivity].unsubscribe(address)
else:
raise RuntimeWarning("No activity attached")