Skip to content
Permalink
Browse files

Set limit to open activities and open instances

At the request of OLPC AU (in an effort to reduce OOM freezes) this
patch uses gconf to set a maximum number of open activities [1]. An
alert is shown if the user tries to launch more activities than the
maximum asking them to close an activity before opening a new one. If
maximum_number_of_open_activites is not set or == 0, then there is no
maximum limit applied.

Further, Some activities don't behave well if more than one instance
is open (e.g., SL #4554). This patch sets a limit on the number open
instances of an activity based on a new field in activity.info:
maximum_instances.

If and only if the maximum_instances field is present in
activity.info, is it used to set the limit of open instances.

NOTE: there is a patch to bundleactivity.py in the toolkit necessary
for this patch to be used.

[1] /desktop/sugar/maximum_number_of_open_activities
  • Loading branch information...
walterbender committed Sep 13, 2013
1 parent 90f8ba3 commit 3fea62baf20a30e11015a014aeb94a16fba58554
@@ -24,6 +24,7 @@

from sugar3.graphics import style
from sugar3.graphics import palettegroup
from sugar3.graphics.alert import ErrorAlert

from jarabe.desktop.meshbox import MeshBox
from jarabe.desktop.homebox import HomeBox
@@ -97,8 +98,35 @@ def __init__(self):
self._transition_box.connect('completed',
self._transition_completed_cb)

shell.get_model().zoom_level_changed.connect(
self.__zoom_level_changed_cb)
self._alert = None
shell_model = shell.get_model()
shell_model.zoom_level_changed.connect(self.__zoom_level_changed_cb)
shell_model.connect('open-activity-error',
self.__open_activity_error_cb)

def add_alert(self, alert):
if self._alert is not None:
self.remove_alert()
self._alert = alert
self._box.pack_start(alert, False, True, 0)
self._box.reorder_child(alert, 1)

def remove_alert(self):
self._box.remove(self._alert)
self._alert = None

def __open_activity_error_cb(self, model, title, message):
logging.error('%s: %s' % (title, message))
if self._alert is None:
self._alert = ErrorAlert()
self._alert.connect('response', self.__alert_response_cb)
self.add_alert(self._alert)
self._alert.show()
self._alert.props.title = title
self._alert.props.msg = message

def __alert_response_cb(self, alert, response_id):
self.remove_alert()

def _deactivate_view(self, level):
group = palettegroup.get_group('default')
@@ -45,7 +45,7 @@
from jarabe.journal import model
from jarabe.journal.journalwindow import JournalWindow

from jarabe.model import session
from jarabe.model import session, shell


J_DBUS_SERVICE = 'org.laptop.Journal'
@@ -173,17 +173,38 @@ def __init__(self):
self._critical_space_alert = None
self._check_available_space()

self._alert = None
shell_model = shell.get_model()
shell_model.connect('open-activity-error',
self.__open_activity_error_cb)

session.get_session_manager().shutdown_signal.connect(
self._session_manager_shutdown_cb)

def volume_error_cb(self, gobject, message, severity):
if self._alert is not None:
# Volume-error alert should override maximum-reached alert
self.remove_alert(self._alert)
self._alert = None

alert = ErrorAlert(title=severity, msg=message)
alert.connect('response', self.__alert_response_cb)
self.add_alert(alert)
alert.show()

def __alert_response_cb(self, alert, response_id):
self.remove_alert(alert)
self._alert = None

def __open_activity_error_cb(self, model, title, message):
logging.error('%s: %s' % (title, message))
if self._alert is None:
self._alert = ErrorAlert()
self._alert.connect('response', self.__alert_response_cb)
self.add_alert(self._alert)
self._alert.show()
self._alert.props.title = title
self._alert.props.msg = message

def __realize_cb(self, window):
xid = window.get_window().get_xid()
@@ -222,9 +222,16 @@ def resume(metadata, bundle_id=None, force_bundle_downgrade=False):

def launch(bundle, activity_id=None, object_id=None, uri=None, color=None,
invited=False):
shell_model = shell.get_model()
if shell_model.reached_maximum_number_of_open_activities():
return

if activity_id is None or not activity_id:
activity_id = activityfactory.create_activity_id()

if shell_model.reached_maximum_number_of_open_instances(bundle):
return

logging.debug('launch bundle_id=%s activity_id=%s object_id=%s uri=%s',
bundle.get_bundle_id(), activity_id, object_id, uri)

@@ -239,7 +246,6 @@ def launch(bundle, activity_id=None, object_id=None, uri=None, color=None,
bundle = activities[0]
logging.debug('Launching content bundle with uri %s', uri)

shell_model = shell.get_model()
activity = shell_model.get_activity_by_id(activity_id)
if activity is not None:
logging.debug('re-launch %r', activity.get_window())
@@ -17,6 +17,7 @@

import logging
import time
from gettext import gettext as _

from gi.repository import GConf
from gi.repository import Wnck
@@ -39,6 +40,14 @@

_model = None

_ACTIVITY_ALERT_TITLE = _('Activity launcher')
_MAX_NUMBER_OF_ACTIVITIES_MESSAGE = _('The maximum number of open activities \
has been reached. Please close an activity before launching a new one.')
_MORE_THAN_ONE_INSTANCE_MESSAGE = _('%s is already running. Please stop %s \
before launching it again.')
_MAX_NUMBER_OF_INSTANCES_MESSAGE = _('Too many instances of %s are running. \
Please close one before launching a new one.')


class Activity(GObject.GObject):
"""Activity which appears in the "Home View" of the Sugar shell
@@ -259,6 +268,13 @@ def get_bundle_path(self):
else:
return self._activity_info.get_path()

def get_bundle_id(self):
"""Returns the activity's bundle id"""
if self._activity_info is None:
return None
else:
return self._activity_info.get_bundle_id()

def get_activity_name(self):
"""Returns the activity's bundle name"""
if self._activity_info is None:
@@ -358,6 +374,8 @@ class ShellModel(GObject.GObject):
"""

__gsignals__ = {
'open-activity-error': (GObject.SignalFlags.RUN_FIRST, None,
([str, str])),
'activity-added': (GObject.SignalFlags.RUN_FIRST, None,
([GObject.TYPE_PYOBJECT])),
'activity-removed': (GObject.SignalFlags.RUN_FIRST, None,
@@ -403,6 +421,10 @@ def __init__(self):

self._screen.toggle_showing_desktop(True)

client = GConf.Client.get_default()
self._maximum_number_of_open_activities = client.get_int(
'/desktop/sugar/maximum_number_of_open_activities')

def get_launcher(self, activity_id):
return self._launchers.get(str(activity_id))

@@ -645,6 +667,41 @@ def _active_window_changed_cb(self, screen, previous_window=None):

self._update_zoom_level(window)

def reached_maximum_number_of_open_instances(self, bundle):
activities = self._get_activities_with_window()
maximum_instances = bundle.get_maximum_instances()
if maximum_instances is not None:
bundle_id = bundle.get_bundle_id()
count = 1
name = ''
for activity in self._get_activities_with_window():
if activity.get_bundle_id() == bundle_id:
name = activity.get_activity_name()
count += 1
if count > maximum_instances:
if maximum_instances == 1:
self.emit('open-activity-error',
_ACTIVITY_ALERT_TITLE,
_MORE_THAN_ONE_INSTANCE_MESSAGE %
(name, name))
else:
self.emit('open-activity-error',
_ACTIVITY_ALERT_TITLE,
_MAX_NUMBER_OF_INSTANCES_MESSAGE %
(name))
return True
return False

def reached_maximum_number_of_open_activities(self):
activities = self._get_activities_with_window()
if self._maximum_number_of_open_activities > 0 and \
len(activities) > self._maximum_number_of_open_activities:
self.emit('open-activity-error', _ACTIVITY_ALERT_TITLE,
_MAX_NUMBER_OF_ACTIVITIES_MESSAGE)
return True
else:
return False

def _add_activity(self, home_activity):
self._activities.append(home_activity)
self.emit('activity-added', home_activity)
@@ -120,6 +120,9 @@ def setup():
def add_launcher(activity_id, icon_path, icon_color):
model = shell.get_model()

if model.reached_maximum_number_of_open_activities():
return

if model.get_launcher(activity_id) is not None:
return

0 comments on commit 3fea62b

Please sign in to comment.
You can’t perform that action at this time.