diff --git a/NEWS b/NEWS index 9ac60ae1..07859a3b 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,5 @@ +* #2240 Ensure activity uniquness in the shell. (marco) + Snapshot f6f3f2b520 * #2103 Use selection grey for progress in the browser entry. (marco) diff --git a/shell/model/homeactivity.py b/shell/model/homeactivity.py index 4487c09e..8b6a8dc5 100644 --- a/shell/model/homeactivity.py +++ b/shell/model/homeactivity.py @@ -64,6 +64,14 @@ class HomeActivity(gobject.GObject): self._launch_time = time.time() self._launching = False + self._retrieve_service() + + if not self._service: + bus = dbus.SessionBus() + bus.add_signal_receiver(self._name_owner_changed_cb, + signal_name="NameOwnerChanged", + dbus_interface="org.freedesktop.DBus") + def set_window(self, window): """An activity is 'launched' once we get its window.""" if self._window or self._xid: @@ -75,22 +83,14 @@ class HomeActivity(gobject.GObject): self._xid = window.get_xid() def get_service(self): - """Retrieve the application's sugar introspection service + """Get the activity service Note that non-native Sugar applications will not have such a service, so the return value will be None in those cases. """ - bus = dbus.SessionBus() - try: - service = dbus.Interface( - bus.get_object(_SERVICE_NAME + self._activity_id, - _SERVICE_PATH + "/" + self._activity_id), - _SERVICE_INTERFACE) - except dbus.DBusException: - service = None - return service + return self._service def get_title(self): """Retrieve the application's root window's suggested title""" @@ -182,3 +182,19 @@ class HomeActivity(gobject.GObject): def do_get_property(self, pspec): if pspec.name == 'launching': return self._launching + + def _get_service_name(self): + return _SERVICE_NAME + self._activity_id + + def _retrieve_service(self): + try: + bus = dbus.SessionBus() + proxy = bus.get_object(self._get_service_name(), + _SERVICE_PATH + "/" + self._activity_id) + self._service = dbus.Interface(proxy, _SERVICE_INTERFACE) + except dbus.DBusException: + self._service = None + + def _name_owner_changed_cb(self, name, old, new): + if name == self._get_service_name(): + self._retrieve_service() diff --git a/shell/shellservice.py b/shell/shellservice.py index c612d6e2..5728e449 100644 --- a/shell/shellservice.py +++ b/shell/shellservice.py @@ -63,6 +63,15 @@ class ShellService(dbus.service.Object): bus_name = dbus.service.BusName(_DBUS_SERVICE, bus=bus) dbus.service.Object.__init__(self, bus_name, _DBUS_PATH) + @dbus.service.method(_DBUS_SHELL_IFACE, + in_signature="s", out_signature="b") + def ActivateActivity(self, activity_id): + host = self._shell.get_activity(activity_id) + if host: + host.present() + return True + + return False @dbus.service.method(_DBUS_SHELL_IFACE, in_signature="ss", out_signature="") diff --git a/sugar/activity/activity.py b/sugar/activity/activity.py index 22a84a76..ffa46d90 100644 --- a/sugar/activity/activity.py +++ b/sugar/activity/activity.py @@ -248,6 +248,7 @@ class Activity(Window, gtk.Container): self._jobject.metadata['title'] = _('%s Activity') % get_bundle_name() self._jobject.metadata['title_set_by_user'] = '0' self._jobject.metadata['activity'] = self.get_service_name() + self._jobject.metadata['activity_id'] = self.get_id() self._jobject.metadata['keep'] = '0' #self._jobject.metadata['buddies'] = '' self._jobject.metadata['preview'] = '' diff --git a/sugar/activity/activityfactory.py b/sugar/activity/activityfactory.py index d1480b2d..fe2a8bd7 100644 --- a/sugar/activity/activityfactory.py +++ b/sugar/activity/activityfactory.py @@ -90,24 +90,32 @@ class ActivityCreationHandler(gobject.GObject): self._activity_handle = activity_handle bus = dbus.SessionBus() - object_path = '/' + service_name.replace('.', '/') - proxy_obj = bus.get_object(service_name, object_path, - follow_name_owner_changes=True) - factory = dbus.Interface(proxy_obj, _ACTIVITY_FACTORY_INTERFACE) - factory.create(self._activity_handle.get_dict(), - reply_handler=self._no_reply_handler, - error_handler=self._create_error_handler) - - bus = dbus.SessionBus() bus_object = bus.get_object(_SHELL_SERVICE, _SHELL_PATH) self._shell = dbus.Interface(bus_object, _SHELL_IFACE) + object_path = '/' + service_name.replace('.', '/') + proxy_obj = bus.get_object(service_name, object_path, + follow_name_owner_changes=True) + self._factory = dbus.Interface(proxy_obj, _ACTIVITY_FACTORY_INTERFACE) + + if self.get_activity_id() != None: + self._shell.ActivateActivity(self.get_activity_id(), + reply_handler=self._activate_reply_handler, + error_handler=self._activate_error_handler) + else: + self._launch_activity() + + def _launch_activity(self): self._shell.NotifyLaunch( - service_name, self.get_activity_id(), + self._service_name, self.get_activity_id(), reply_handler=self._no_reply_handler, error_handler=self._notify_launch_error_handler) + self._factory.create(self._activity_handle.get_dict(), + reply_handler=self._no_reply_handler, + error_handler=self._create_error_handler) + def get_activity_id(self): """Retrieve the unique identity for this activity""" return self._activity_handle.activity_id @@ -121,6 +129,13 @@ class ActivityCreationHandler(gobject.GObject): def _notify_launch_error_handler(self, err): logging.debug('Notify launch failed %s' % err) + def _activate_reply_handler(self, activated): + if not activated: + self._launch_activity() + + def _activate_error_handler(self, err): + logging.debug("Activity activation request failed %s" % err) + def _create_reply_handler(self, xid): logging.debug("Activity created %s (%s)." % (self._activity_handle.activity_id, self._service_name)) diff --git a/sugar/activity/activityhandle.py b/sugar/activity/activityhandle.py index 26d0d47c..8e90e705 100644 --- a/sugar/activity/activityhandle.py +++ b/sugar/activity/activityhandle.py @@ -20,8 +20,8 @@ from sugar.presence import presenceservice class ActivityHandle(object): """Data structure storing simple activity metadata""" def __init__( - self, activity_id, pservice_id=None, - object_id=None,uri=None + self, activity_id=None, pservice_id=None, + object_id=None, uri=None ): """Initialise the handle from activity_id diff --git a/sugar/datastore/datastore.py b/sugar/datastore/datastore.py index 2561733b..4249239c 100644 --- a/sugar/datastore/datastore.py +++ b/sugar/datastore/datastore.py @@ -24,6 +24,7 @@ from sugar.datastore import dbus_helpers from sugar import activity from sugar.activity.bundle import Bundle from sugar.activity import activityfactory +from sugar.activity.activityhandle import ActivityHandle class DSMetadata(gobject.GObject): __gsignals__ = { @@ -38,7 +39,8 @@ class DSMetadata(gobject.GObject): else: self._props = props - default_keys = ['activity', 'mime_type', 'title_set_by_user'] + default_keys = ['activity', 'activity_id', + 'mime_type', 'title_set_by_user'] for key in default_keys: if not self._props.has_key(key): self._props[key] = '' @@ -116,9 +118,13 @@ class DSObject: activityfactory.create(bundle.get_service_name()) else: - activity_info = self.get_activities()[0] - activityfactory.create_with_object_id(activity_info.service_name, - self.object_id) + service_name = self.get_activities()[0].service_name + + handle = ActivityHandle(object_id=self.object_id) + if self.metadata['activity_id']: + handle.activity_id = self.metadata['activity_id'] + + activityfactory.create(service_name, handle) def get(object_id): logging.debug('datastore.get')