diff --git a/services/shell/activityregistryservice.py b/services/shell/activityregistryservice.py index 60293d47..44c99694 100644 --- a/services/shell/activityregistryservice.py +++ b/services/shell/activityregistryservice.py @@ -48,6 +48,15 @@ class ActivityRegistry(dbus.service.Object): registry = bundleregistry.get_registry() return registry.add_bundle(bundle_path) + @dbus.service.method(_ACTIVITY_REGISTRY_IFACE, + in_signature='', out_signature='aa{sv}') + def GetActivities(self): + result = [] + registry = bundleregistry.get_registry() + for bundle in registry: + result.append(self._bundle_to_dict(bundle)) + return result + @dbus.service.method(_ACTIVITY_REGISTRY_IFACE, in_signature='s', out_signature='a{sv}') def GetActivity(self, service_name): @@ -89,7 +98,8 @@ class ActivityRegistry(dbus.service.Object): return {'name': bundle.get_name(), 'icon': bundle.get_icon(), 'service_name': bundle.get_service_name(), - 'path': bundle.get_path()} + 'path': bundle.get_path(), + 'show_launcher': bundle.get_show_launcher()} def _bundle_added_cb(self, bundle_registry, bundle): self.ActivityAdded(self._bundle_to_dict(bundle)) diff --git a/shell/model/MeshModel.py b/shell/model/MeshModel.py index 44974e21..82980c34 100644 --- a/shell/model/MeshModel.py +++ b/shell/model/MeshModel.py @@ -18,29 +18,29 @@ import gobject from sugar.graphics.xocolor import XoColor from sugar.presence import presenceservice +from sugar import activity -from model import bundleregistry from model.BuddyModel import BuddyModel from model.accesspointmodel import AccessPointModel from hardware import hardwaremanager from hardware import nmclient class ActivityModel: - def __init__(self, activity, bundle): + def __init__(self, activity, activity_info): self._activity = activity - self._bundle = bundle + self._activity_info = activity_info def get_id(self): return self._activity.props.id def get_icon_name(self): - return self._bundle.get_icon() + return self._activity_info.icon def get_color(self): return XoColor(self._activity.props.color) def get_service_name(self): - return self._bundle.get_service_name() + return self._activity_info.service_name def get_title(self): return self._activity.props.name @@ -75,7 +75,6 @@ class MeshModel(gobject.GObject): self._buddies = {} self._access_points = {} self._mesh = None - self._bundle_registry = bundleregistry.get_registry() self._pservice = presenceservice.get_instance() self._pservice.connect("activity-appeared", @@ -196,13 +195,14 @@ class MeshModel(gobject.GObject): def _activity_appeared_cb(self, pservice, activity): self._check_activity(activity) - def _check_activity(self, activity): - bundle = self._bundle_registry.get_bundle(activity.props.type) - if not bundle: + def _check_activity(self, presence_activity): + registry = activity.get_registry() + activity_info = registry.get_activity(presence_activity.props.type) + if not activity_info: return - if self.has_activity(activity.props.id): + if self.has_activity(presence_activity.props.id): return - self.add_activity(bundle, activity) + self.add_activity(activity_info, presence_activity) def has_activity(self, activity_id): return self._activities.has_key(activity_id) @@ -213,8 +213,8 @@ class MeshModel(gobject.GObject): else: return None - def add_activity(self, bundle, activity): - model = ActivityModel(activity, bundle) + def add_activity(self, activity_info, activity): + model = ActivityModel(activity, activity_info) self._activities[model.get_id()] = model self.emit('activity-added', model) diff --git a/shell/model/homeactivity.py b/shell/model/homeactivity.py index c45e5c75..e95fe9ad 100644 --- a/shell/model/homeactivity.py +++ b/shell/model/homeactivity.py @@ -44,10 +44,10 @@ class HomeActivity(gobject.GObject): gobject.PARAM_READWRITE), } - def __init__(self, bundle, activity_id): + def __init__(self, activity_info, activity_id): """Initialise the HomeActivity - bundle -- sugar.activity.bundle.Bundle instance, + activity_info -- sugar.activity.registry.ActivityInfo instance, provides the information required to actually create the new instance. This is, in effect, the "type" of activity being created. @@ -61,7 +61,7 @@ class HomeActivity(gobject.GObject): self._pid = None self._service = None self._activity_id = activity_id - self._bundle = bundle + self._activity_info = activity_info self._launch_time = time.time() self._launching = False @@ -99,9 +99,9 @@ class HomeActivity(gobject.GObject): return self._window.get_name() def get_icon_name(self): - """Retrieve the bundle's icon (file) name""" - if self._bundle: - return self._bundle.get_icon() + """Retrieve the activity's icon (file) name""" + if self._activity_info: + return self._activity_info.icon else: return 'theme:stock-missing' @@ -156,9 +156,9 @@ class HomeActivity(gobject.GObject): return self._window def get_type(self): - """Retrieve bundle's "service_name" for future reference""" - if self._bundle: - return self._bundle.get_service_name() + """Retrieve activity_info's "service_name" for future reference""" + if self._activity_info: + return self._activity_info.service_name else: return None diff --git a/shell/model/homemodel.py b/shell/model/homemodel.py index c5e761cd..dac434a3 100644 --- a/shell/model/homemodel.py +++ b/shell/model/homemodel.py @@ -21,9 +21,9 @@ import wnck import dbus from sugar import wm +from sugar import activity from model.homeactivity import HomeActivity -from model import bundleregistry class HomeModel(gobject.GObject): """Model of the "Home" view (activity management) @@ -61,7 +61,6 @@ class HomeModel(gobject.GObject): gobject.GObject.__init__(self) self._activities = [] - self._bundle_registry = bundleregistry.get_registry() self._active_activity = None self._pending_activity = None @@ -83,11 +82,11 @@ class HomeModel(gobject.GObject): """ return self._pending_activity - def _set_pending_activity(self, activity): - if self._pending_activity == activity: + def _set_pending_activity(self, home_activity): + if self._pending_activity == home_activity: return - self._pending_activity = activity + self._pending_activity = home_activity self.emit('pending-activity-changed', self._pending_activity) def get_active_activity(self): @@ -101,8 +100,8 @@ class HomeModel(gobject.GObject): """ return self._active_activity - def _set_active_activity(self, activity): - if self._active_activity == activity: + def _set_active_activity(self, home_activity): + if self._active_activity == home_activity: return if self._active_activity: @@ -111,14 +110,14 @@ class HomeModel(gobject.GObject): service.set_active(False, reply_handler=self._set_active_success, error_handler=self._set_active_error) - if activity: - service = activity.get_service() + if home_activity: + service = home_activity.get_service() if service: service.set_active(True, reply_handler=self._set_active_success, error_handler=self._set_active_error) - self._active_activity = activity + self._active_activity = home_activity self.emit('active-activity-changed', self._active_activity) def __iter__(self): @@ -135,45 +134,46 @@ class HomeModel(gobject.GObject): def _window_opened_cb(self, screen, window): if window.get_window_type() == wnck.WINDOW_NORMAL: - activity = None + home_activity = None activity_id = wm.get_activity_id(window) - bundle_id = wm.get_bundle_id(window) - if bundle_id: - bundle = self._bundle_registry.get_bundle(bundle_id) + service_name = wm.get_bundle_id(window) + if service_name: + registry = activity.get_registry() + activity_info = registry.get_activity(service_name) else: - bundle = None + activity_info = None if activity_id: - activity = self._get_activity_by_id(activity_id) + home_activity = self._get_activity_by_id(activity_id) - if not activity: - activity = HomeActivity(bundle, activity_id) - self._add_activity(activity) + if not home_activity: + home_activity = HomeActivity(activity_info, activity_id) + self._add_activity(home_activity) - activity.set_window(window) + home_activity.set_window(window) - activity.props.launching = False - self.emit('activity-started', activity) + home_activity.props.launching = False + self.emit('activity-started', home_activity) if self._pending_activity is None: - self._set_pending_activity(activity) + self._set_pending_activity(home_activity) def _window_closed_cb(self, screen, window): if window.get_window_type() == wnck.WINDOW_NORMAL: self._remove_activity_by_xid(window.get_xid()) def _get_activity_by_xid(self, xid): - for activity in self._activities: - if activity.get_xid() == xid: - return activity + for home_activity in self._activities: + if home_activity.get_xid() == xid: + return home_activity return None def _get_activity_by_id(self, activity_id): - for activity in self._activities: - if activity.get_activity_id() == activity_id: - return activity + for home_activity in self._activities: + if home_activity.get_activity_id() == activity_id: + return home_activity return None def _set_active_success(self): @@ -194,12 +194,12 @@ class HomeModel(gobject.GObject): self._set_pending_activity(act) self._set_active_activity(act) - def _add_activity(self, activity): - self._activities.append(activity) - self.emit('activity-added', activity) + def _add_activity(self, home_activity): + self._activities.append(home_activity) + self.emit('activity-added', home_activity) - def _remove_activity(self, activity): - if activity == self._active_activity: + def _remove_activity(self, home_activity): + if home_activity == self._active_activity: self._set_active_activity(None) # Figure out the new _pending_activity. windows = wnck.screen_get_default().get_windows_stacked() @@ -213,28 +213,29 @@ class HomeModel(gobject.GObject): logging.error('No activities are running') self._set_pending_activity(None) - self.emit('activity-removed', activity) - self._activities.remove(activity) + self.emit('activity-removed', home_activity) + self._activities.remove(home_activity) def _remove_activity_by_xid(self, xid): - activity = self._get_activity_by_xid(xid) - if activity: - self._remove_activity(activity) + home_activity = self._get_activity_by_xid(xid) + if home_activity: + self._remove_activity(home_activity) else: logging.error('Model for window %d does not exist.' % xid) def notify_activity_launch(self, activity_id, service_name): - bundle = self._bundle_registry.get_bundle(service_name) - if not bundle: + registry = activity.get_registry() + activity_info = registry.get_activity(service_name) + if not activity_info: raise ValueError("Activity service name '%s' was not found in the bundle registry." % service_name) - activity = HomeActivity(bundle, activity_id) - activity.props.launching = True - self._add_activity(activity) + home_activity = HomeActivity(activity_info, activity_id) + home_activity.props.launching = True + self._add_activity(home_activity) def notify_activity_launch_failed(self, activity_id): - activity = self._get_activity_by_id(activity_id) - if activity: - logging.debug("Activity %s (%s) launch failed" % (activity_id, activity.get_type())) - self._remove_activity(activity) + home_activity = self._get_activity_by_id(activity_id) + if home_activity: + logging.debug("Activity %s (%s) launch failed" % (activity_id, home_activity.get_type())) + self._remove_activity(home_activity) else: logging.error('Model for activity id %s does not exist.' % activity_id) diff --git a/shell/view/Shell.py b/shell/view/Shell.py index af9036a4..044cbde4 100644 --- a/shell/view/Shell.py +++ b/shell/view/Shell.py @@ -26,6 +26,7 @@ import gtk import wnck from sugar.activity.activityhandle import ActivityHandle +from sugar import activity from sugar.activity import activityfactory from sugar.datastore import datastore from sugar import profile @@ -34,7 +35,6 @@ from view.ActivityHost import ActivityHost from view.frame.frame import Frame from view.keyhandler import KeyHandler from view.home.HomeWindow import HomeWindow -from model import bundleregistry from model.shellmodel import ShellModel from hardware import hardwaremanager @@ -116,16 +116,16 @@ class Shell(gobject.GObject): return self._frame def join_activity(self, bundle_id, activity_id): - activity = self.get_activity(activity_id) - if activity: - activity.present() + activity_host = self.get_activity(activity_id) + if activity_host: + activity_host.present() return # Get the service name for this activity, if # we have a bundle on the system capable of handling # this activity type - breg = bundleregistry.get_registry() - bundle = breg.get_bundle(bundle_id) + registry = activity.get_registry() + bundle = registry.get_activity(bundle_id) if not bundle: logging.error("Couldn't find activity for type %s" % bundle_id) return diff --git a/shell/view/clipboardmenu.py b/shell/view/clipboardmenu.py index 1d9f85c0..28ea0bb6 100644 --- a/shell/view/clipboardmenu.py +++ b/shell/view/clipboardmenu.py @@ -123,32 +123,8 @@ class ClipboardMenu(Palette): def _open_item_activate_cb(self, menu_item): if self._percent < 100: return - jobject = self._copy_to_journal() - # TODO: we cannot simply call resume() right now because we would lock - # the shell as we are sharing the same loop as the shell service. - #jobject.resume() - - # TODO: take this out when we fix the mess that is the shell/shellservice. - from model import bundleregistry - from sugar.activity.bundle import Bundle - from sugar.activity import activityfactory - if jobject.is_bundle(): - bundle = Bundle(jobject.file_path) - if not bundle.is_installed(): - bundle.install() - - activityfactory.create(bundle.get_service_name()) - else: - service_name = None - mime_type = jobject.metadata['mime_type'] - for bundle in bundleregistry.get_registry(): - if bundle.get_mime_types() and mime_type in bundle.get_mime_types(): - service_name = bundle.get_service_name() - break - if service_name: - activityfactory.create_with_object_id(service_name, - jobject.object_id) + jobject.resume() def _remove_item_activate_cb(self, menu_item): cb_service = clipboardservice.get_instance() diff --git a/shell/view/frame/ActivitiesBox.py b/shell/view/frame/ActivitiesBox.py index 5a9e0de7..909a5f2c 100644 --- a/shell/view/frame/ActivitiesBox.py +++ b/shell/view/frame/ActivitiesBox.py @@ -22,31 +22,31 @@ from sugar.graphics.xocolor import XoColor from sugar.graphics.iconbutton import IconButton from sugar.graphics import style from sugar import profile +from sugar import activity -from model import bundleregistry from frameinvoker import FrameCanvasInvoker class ActivityButton(IconButton): - def __init__(self, activity): - IconButton.__init__(self, icon_name=activity.get_icon(), + def __init__(self, activity_info): + IconButton.__init__(self, icon_name=activity_info.icon, stroke_color=style.COLOR_WHITE, fill_color=style.COLOR_TRANSPARENT) - palette = Palette(activity.get_name()) + palette = Palette(activity_info.name) palette.props.invoker = FrameCanvasInvoker(self) palette.set_group_id('frame') self.set_palette(palette) - self._activity = activity + self._activity_info = activity_info def get_bundle_id(self): - return self._activity.get_service_name() + return self._activity_info.service_name class InviteButton(IconButton): - def __init__(self, activity, invite): - IconButton.__init__(self, icon_name=activity.get_icon()) + def __init__(self, activity_model, invite): + IconButton.__init__(self, icon_name=activity_model.get_color()) - self.props.xo_color = activity.get_color() + self.props.xo_color = activity_model.get_color() self._invite = invite def get_activity_id(self): @@ -67,12 +67,12 @@ class ActivitiesBox(hippo.CanvasBox): self._invite_to_item = {} self._invites = self._shell_model.get_invites() - bundle_registry = bundleregistry.get_registry() - for bundle in bundle_registry: - if bundle.get_show_launcher(): - self.add_activity(bundle) + registry = activity.get_registry() + for activity_info in registry.get_activities(): + if activity_info.show_launcher: + self.add_activity(activity_info) - bundle_registry.connect('bundle-added', self._bundle_added_cb) + registry.connect('activity-added', self._activity_added_cb) for invite in self._invites: self.add_invite(invite) @@ -93,19 +93,19 @@ class ActivitiesBox(hippo.CanvasBox): def _invite_removed_cb(self, invites, invite): self.remove_invite(invite) - def _bundle_added_cb(self, bundle_registry, bundle): - self.add_activity(bundle) + def _activity_added_cb(self, activity_registry, activity_info): + self.add_activity(activity_info) - def add_activity(self, activity): - item = ActivityButton(activity) + def add_activity(self, activity_info): + item = ActivityButton(activity_info) item.connect('activated', self._activity_clicked_cb) self.append(item, 0) def add_invite(self, invite): mesh = self._shell_model.get_mesh() - activity = mesh.get_activity(invite.get_activity_id()) + activity_model = mesh.get_activity(invite.get_activity_id()) if activity: - item = InviteButton(activity, invite) + item = InviteButton(activity_model, invite) item.connect('activated', self._invite_clicked_cb) self.append(item, 0) diff --git a/shell/view/home/FriendView.py b/shell/view/home/FriendView.py index c585312c..ed058927 100644 --- a/shell/view/home/FriendView.py +++ b/shell/view/home/FriendView.py @@ -20,8 +20,8 @@ import gobject from sugar.graphics.canvasicon import CanvasIcon from sugar.graphics import style from sugar.presence import presenceservice +from sugar import activity -from model import bundleregistry from view.BuddyIcon import BuddyIcon class FriendView(hippo.CanvasBox): @@ -46,9 +46,9 @@ class FriendView(hippo.CanvasBox): self._buddy.connect('disappeared', self._buddy_disappeared_cb) self._buddy.connect('color-changed', self._buddy_color_changed_cb) - def _get_new_icon_name(self, activity): - registry = bundleregistry.get_registry() - bundle = registry.get_bundle(activity.get_type()) + def _get_new_icon_name(self, home_activity): + registry = activity.get_registry() + bundle = registry.get_bundle(home_activity.get_type()) if bundle: return bundle.get_icon() return None @@ -58,14 +58,14 @@ class FriendView(hippo.CanvasBox): self.remove(self._activity_icon) self._activity_icon_visible = False - def _buddy_activity_changed_cb(self, buddy, activity=None): - if not activity: + def _buddy_activity_changed_cb(self, buddy, home_activity=None): + if not home_activity: self._remove_activity_icon() return # FIXME: use some sort of "unknown activity" icon rather # than hiding the icon? - name = self._get_new_icon_name(activity) + name = self._get_new_icon_name(home_activity) if name: self._activity_icon.props.icon_name = name self._activity_icon.props.xo_color = buddy.get_color() @@ -76,8 +76,8 @@ class FriendView(hippo.CanvasBox): self._remove_activity_icon() def _buddy_appeared_cb(self, buddy): - activity = self._buddy.get_current_activity() - self._buddy_activity_changed_cb(buddy, activity) + home_activity = self._buddy.get_current_activity() + self._buddy_activity_changed_cb(buddy, home_activity) def _buddy_disappeared_cb(self, buddy): self._buddy_activity_changed_cb(buddy, None) diff --git a/sugar/activity/bundle.py b/sugar/activity/bundle.py index bc24092a..d361c621 100644 --- a/sugar/activity/bundle.py +++ b/sugar/activity/bundle.py @@ -296,11 +296,8 @@ class Bundle: raise ZipExtractException self._init_with_path(bundle_path) - - bus = dbus.SessionBus() - proxy_obj = bus.get_object(_DBUS_SHELL_SERVICE, _DBUS_SHELL_PATH) - dbus_service = dbus.Interface(proxy_obj, _DBUS_ACTIVITY_REGISTRY_IFACE) - if not dbus_service.AddBundle(bundle_path): + + if not activity.get_registry().add_bundle(bundle_path): raise RegistrationException def deinstall(self): diff --git a/sugar/activity/registry.py b/sugar/activity/registry.py index 430a2df2..1483a786 100644 --- a/sugar/activity/registry.py +++ b/sugar/activity/registry.py @@ -19,6 +19,7 @@ import logging import dbus +import gobject _ACTIVITY_REGISTRY_SERVICE_NAME = 'org.laptop.ActivityRegistry' _ACTIVITY_REGISTRY_IFACE = 'org.laptop.ActivityRegistry' @@ -28,17 +29,25 @@ def _activity_info_from_dict(info_dict): if not info_dict: return None return ActivityInfo(info_dict['name'], info_dict['icon'], - info_dict['service_name'], info_dict['path']) + info_dict['service_name'], info_dict['path'], + info_dict['show_launcher']) class ActivityInfo(object): - def __init__(self, name, icon, service_name, path): + def __init__(self, name, icon, service_name, path, show_launcher): self.name = name self.icon = icon self.service_name = service_name self.path = path + self.show_launcher = show_launcher -class ActivityRegistry(object): +class ActivityRegistry(gobject.GObject): + __gsignals__ = { + 'activity-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + ([gobject.TYPE_PYOBJECT])) + } def __init__(self): + gobject.GObject.__init__(self) + bus = dbus.SessionBus() bus_object = bus.get_object(_ACTIVITY_REGISTRY_SERVICE_NAME, _ACTIVITY_REGISTRY_PATH) @@ -57,6 +66,10 @@ class ActivityRegistry(object): return result + def get_activities(self): + info_list = self._registry.GetActivities() + return self._convert_info_list(info_list) + def get_activity(self, service_name): if self._service_name_to_activity_info.has_key(service_name): return self._service_name_to_activity_info[service_name] @@ -81,10 +94,14 @@ class ActivityRegistry(object): self._mime_type_to_activities[mime_type] = activities return activities - def _activity_added_cb(self, bundle): + def add_bundle(self, bundle_path): + return self._registry.AddBundle(bundle_path) + + def _activity_added_cb(self, info_dict): logging.debug('ActivityRegistry._activity_added_cb: flushing caches') self._service_name_to_activity_info.clear() self._mime_type_to_activities.clear() + self.emit('activity-added', _activity_info_from_dict(info_dict)) _registry = None