Track activities while they launch

HomeModel now uses the activity ID to track activities, and creates
the HomeActivity object when the activity is launched, not when
its window appears.
This commit is contained in:
Dan Williams 2007-01-06 19:31:19 -05:00
parent b27257fadb
commit 8cea4c5fc6
3 changed files with 146 additions and 18 deletions

View File

@ -14,23 +14,73 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import time
import gobject
import logging
from sugar.presence import PresenceService from sugar.presence import PresenceService
from sugar.activity import Activity from sugar.activity import Activity
from sugar import profile from sugar import profile
class HomeActivity: class HomeActivity(gobject.GObject):
def __init__(self, registry, window): __gsignals__ = {
'launch-timeout': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE,
([])),
}
def __init__(self, bundle, activity_id):
gobject.GObject.__init__(self)
self._window = None
self._xid = None
self._service = None
self._id = activity_id
self._type = bundle.get_service_name()
self._icon_name = bundle.get_icon()
self._launch_time = time.time()
self._launched = False
self._launch_timeout_id = gobject.timeout_add(10000, self._launch_timeout_cb)
logging.debug("Activity %s (%s) launching..." % (self._id, self._type))
def __del__(self):
gobject.source_remove(self._launch_timeout_id)
self._launch_timeout_id = 0
def _launch_timeout_cb(self, user_data=None):
logging.debug("Activity %s (%s) launch timed out" % (self._id, self._type))
self._launch_timeout_id = 0
self.emit('launch-timeout')
return False
def set_window(self, window):
"""An activity is 'launched' once we get its window."""
logging.debug("Activity %s (%s) finished launching" % (self._id, self._type))
self._launched = True
gobject.source_remove(self._launch_timeout_id)
self._launch_timeout_id = 0
if self._window or self._xid:
raise RuntimeError("Activity is already launched!")
if not window:
raise ValueError("window must be valid")
self._window = window self._window = window
self._xid = window.get_xid() self._xid = window.get_xid()
self._service = Activity.get_service(window.get_xid()) self._service = Activity.get_service(window.get_xid())
self._id = self._service.get_id()
self._type = self._service.get_type()
info = registry.get_bundle(self._type) # verify id and type details
self._icon_name = info.get_icon() act_id = self._service.get_id()
if act_id != self._id:
raise RuntimeError("Activity's real ID (%s) didn't match expected (%s)." % (act_id, self._id))
act_type = self._service.get_type()
if act_type != self._type:
raise RuntimeError("Activity's real type (%s) didn't match expected (%s)." % (act_type, self._type))
def get_title(self): def get_title(self):
if not self._launched:
raise RuntimeError("Activity is still launching.")
return self._window.get_name() return self._window.get_name()
def get_icon_name(self): def get_icon_name(self):
@ -47,13 +97,25 @@ class HomeActivity:
return self._id return self._id
def get_xid(self): def get_xid(self):
if not self._launched:
raise RuntimeError("Activity is still launching.")
return self._xid return self._xid
def get_window(self): def get_window(self):
if not self._launched:
raise RuntimeError("Activity is still launching.")
return self._window return self._window
def get_type(self): def get_type(self):
return self._type return self._type
def get_shared(self): def get_shared(self):
if not self._launched:
raise RuntimeError("Activity is still launching.")
return self._service.get_shared() return self._service.get_shared()
def get_launch_time(self):
return self._launch_time
def get_launched(self):
return self._launched

View File

@ -20,10 +20,14 @@ import gobject
import wnck import wnck
from model.homeactivity import HomeActivity from model.homeactivity import HomeActivity
from sugar.activity import Activity
class HomeModel(gobject.GObject): class HomeModel(gobject.GObject):
__gsignals__ = { __gsignals__ = {
'activity-launched': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])),
'activity-added': (gobject.SIGNAL_RUN_FIRST, 'activity-added': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])), ([gobject.TYPE_PYOBJECT])),
@ -68,6 +72,12 @@ class HomeModel(gobject.GObject):
if window.get_window_type() == wnck.WINDOW_NORMAL: if window.get_window_type() == wnck.WINDOW_NORMAL:
self._remove_activity(window.get_xid()) self._remove_activity(window.get_xid())
def _get_activity_by_xid(self, xid):
for act in self._activities.values():
if act.get_xid() == xid:
return act
return None
def _active_window_changed_cb(self, screen): def _active_window_changed_cb(self, screen):
window = screen.get_active_window() window = screen.get_active_window()
if window == None: if window == None:
@ -77,8 +87,13 @@ class HomeModel(gobject.GObject):
return return
xid = window.get_xid() xid = window.get_xid()
if self._activities.has_key(xid): act = self._get_activity_by_xid(window.get_xid())
self._current_activity = self._activities[xid] if act:
if act.get_launched() == True:
self._current_activity = act
else:
self._current_activity = None
logging.error('Actiivty for window %d was not yet launched.' % xid)
else: else:
self._current_activity = None self._current_activity = None
logging.error('Model for window %d does not exist.' % xid) logging.error('Model for window %d does not exist.' % xid)
@ -86,13 +101,57 @@ class HomeModel(gobject.GObject):
self.emit('active-activity-changed', self._current_activity) self.emit('active-activity-changed', self._current_activity)
def _add_activity(self, window): def _add_activity(self, window):
activity = HomeActivity(self._bundle_registry, window) act_service = Activity.get_service(window.get_xid())
self._activities[window.get_xid()] = activity act_id = act_service.get_id()
activity = None
if self._activities.has_key(act_id):
activity = self._activities[act_id]
else:
# activity got lost, took longer to launch than we allow,
# or it was launched by something other than the shell
act_type = act_service.get_type()
bundle = self._bundle_registry.get_bundle(act_type)
if not bundle:
raise RuntimeError("No bundle for activity type '%s'." % act_type)
return
activity = HomeActivity(bundle, act_id)
self._activities[act_id] = activity
activity.set_window(window)
self.emit('activity-added', activity) self.emit('activity-added', activity)
def _internal_remove_activity(self, activity):
self.emit('activity-removed', activity)
act_id = activity.get_id()
del self._activities[act_id]
def _remove_activity(self, xid): def _remove_activity(self, xid):
if self._activities.has_key(xid): activity = self._get_activity_by_xid(window.get_xid())
self.emit('activity-removed', self._activities[xid]) if activity:
del self._activities[xid] self._internal_remove_activity(activity)
else: else:
logging.error('Model for window %d does not exist.' % xid) logging.error('Model for window %d does not exist.' % xid)
def _activity_launch_timeout_cb(self, activity):
act_id = activity.get_id()
if not act_id in self._activities.keys():
return
self._internal_remove_activity(activity)
def notify_activity_launch(self, activity_id, service_name):
bundle = self._bundle_registry.get_bundle(service_name)
if not bundle:
raise ValueError("Activity service name '%s' was not found in the bundle registry." % service_name)
activity = HomeActivity(bundle, activity_id)
activity.connect('launch-timeout', self._activity_launch_timeout_cb)
self._activities[activity_id] = activity
self.emit('activity-launched', activity)
def notify_activity_launch_failed(self, activity_id):
if self._activities.has_key(activity_id):
activity = self._activities[activity_id]
logging.debug("Activity %s (%s) launch failed" % (activity_id, activity.get_type()))
self._internal_remove_activity(activity)
else:
logging.error('Model for activity id %s does not exist.' % activity_id)

View File

@ -205,13 +205,16 @@ class Shell(gobject.GObject):
breg = self._model.get_bundle_registry() breg = self._model.get_bundle_registry()
bundle = breg.find_by_default_type(bundle_id) bundle = breg.find_by_default_type(bundle_id)
if bundle: if bundle:
serv_name = bundle.get_service_name() act_type = bundle.get_service_name()
home_model = self._model.get_home()
home_model.notify_activity_launch(activity_id, act_type)
try: try:
activity = ActivityFactory.create(serv_name) activity = ActivityFactory.create(act_type)
except DBusException, e: except DBusException, e:
logging.error("Couldn't launch activity %s:\n%s" % (serv_name, e)) logging.error("Couldn't launch activity %s:\n%s" % (act_type, e))
home_mode.notify_activity_launch_failed(activity_id)
else: else:
logging.debug("Joining activity type %s id %s" % (serv_name, activity_id)) logging.debug("Joining activity type %s id %s" % (act_type, activity_id))
activity.join(activity_ps.object_path()) activity.join(activity_ps.object_path())
else: else:
logging.error("Couldn't find activity for type %s" % bundle_id) logging.error("Couldn't find activity for type %s" % bundle_id)
@ -255,11 +258,15 @@ class Shell(gobject.GObject):
logging.error("Couldn't find available activity ID.") logging.error("Couldn't find available activity ID.")
return None return None
home_model = self._model.get_home()
home_model.notify_activity_launch(act_id, activity_type)
try: try:
logging.debug("Shell.start_activity will start %s:%s" % (activity_type, act_id)) logging.debug("Shell.start_activity will start %s:%s" % (activity_type, act_id))
activity = ActivityFactory.create(activity_type) activity = ActivityFactory.create(activity_type)
except dbus.DBusException, e: except dbus.DBusException, e:
logging.debug("Couldn't start activity '%s':\n %s" % (activity_type, e)) logging.debug("Couldn't start activity '%s':\n %s" % (activity_type, e))
home_mode.notify_activity_launch_failed(act_id)
return None return None
activity.start(act_id) activity.start(act_id)