From ca2b08f8b6fb1bc54a4e4f9cfc457f57cf958c7f Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Wed, 12 Jul 2006 13:20:41 +0200 Subject: [PATCH] Cleanup and document session creation and activity registry --- activities/browser/browser.activity | 5 +- configure.ac | 1 - shell/ActivityRegistry.py | 72 +++++++++++++---- shell/ConsoleLogger.py | 2 +- shell/Makefile.am | 3 +- shell/Session.py | 119 ++++++++++++++++++++++++++++ shell/session/Makefile.am | 4 - shell/session/__init__.py | 0 shell/session/session.py | 70 ---------------- shell/sugar | 54 +------------ sugar/activity/Activity.py | 2 +- 11 files changed, 184 insertions(+), 148 deletions(-) create mode 100644 shell/Session.py delete mode 100644 shell/session/Makefile.am delete mode 100644 shell/session/__init__.py delete mode 100644 shell/session/session.py diff --git a/activities/browser/browser.activity b/activities/browser/browser.activity index 227d3f5a..238a6c52 100644 --- a/activities/browser/browser.activity +++ b/activities/browser/browser.activity @@ -1,3 +1,4 @@ [Activity] -name = com.redhat.Sugar.BrowserActivity -class = BrowserActivity.BrowserActivity +name = Web +id = com.redhat.Sugar.BrowserActivity +python_module = BrowserActivity.BrowserActivity diff --git a/configure.ac b/configure.ac index 649efea7..65369173 100644 --- a/configure.ac +++ b/configure.ac @@ -27,7 +27,6 @@ activities/Makefile activities/browser/Makefile activities/chat/Makefile shell/Makefile -shell/session/Makefile sugar/Makefile sugar/__installed__.py sugar/activity/Makefile diff --git a/shell/ActivityRegistry.py b/shell/ActivityRegistry.py index 96ec3b15..9f1e857d 100644 --- a/shell/ActivityRegistry.py +++ b/shell/ActivityRegistry.py @@ -1,29 +1,73 @@ -import dbus +import logging -class ActivityInfo: - def __init__(self, name, title): +class ActivityModule: + """Info about an activity module. Wraps a .activity file.""" + + def __init__(self, name, activity_id, activity_exec, directory): self._name = name - self._title = title + self._id = activity_id + self._directory = directory + self._exec = activity_exec def get_name(self): + """Get the activity user visible name.""" return self._name - def get_title(self): - return self._title + def get_id(self): + """Get the activity identifier""" + return self._id -class ActivityRegistry(dbus.service.Object): - """Dbus service that tracks the available activities""" + def get_class(self): + """Get the activity executable""" + return self._class + + def get_directory(self): + """Get the path to activity directory.""" + return self._directory + +class ActivityRegistry: + """Service that tracks the available activities""" def __init__(self): self._activities = [] - bus = dbus.SessionBus() - bus_name = dbus.service.BusName('com.redhat.Sugar.ActivityRegistry', bus = bus) - dbus.service.Object.__init__(self, bus_name, '/com/redhat/Sugar/ActivityRegistry') + def scan_directory(self, path): + """Scan a directory for activities and add them to the registry.""" + if os.path.isdir(base_dir): + for filename in os.listdir(base_dir): + activity_dir = os.path.join(base_dir, filename) + if os.path.isdir(activity_dir): + for filename in os.listdir(activity_dir): + if filename.endswith(".activity"): + self.add(os.path.join(activity_dir, filename)) - @dbus.service.method("com.redhat.Sugar.ActivityRegistry") - def add(self, name, title): - self._activities.append(ActivityInfo(name, title)) + def add(self, path): + """Add an activity to the registry. The path points to a .activity file.""" + cp = ConfigParser() + cp.read([path]) + + directory = os.path.dirname(path) + + try: + activity_id = cp.get('Activity', 'id') + name = cp.get('Activity', 'name') + except NoOptionError: + logging.error('%s miss a required option' % (path)) + + if cp.has_option('Activity', 'exec'): + activity_exec = cp.get('Activity', 'exec') + elif cp.has_option('Activity', 'python_module'): + python_module = cp.get('Activity', 'python_module') + activity_exec = 'python -m sugar/activity/Activity %s %s' \ + % (name, python_module) + else: + logging.error('%s must specifiy exec or python_module' % (path)) + + module = ActivityModule(name, activity_id, activity_exec, directory) + self._activities.append(module) + + return True def list_activities(self): + """Enumerate the registered activities as an ActivityModule list.""" return self._activities diff --git a/shell/ConsoleLogger.py b/shell/ConsoleLogger.py index fc431ecb..4c3eee2e 100644 --- a/shell/ConsoleLogger.py +++ b/shell/ConsoleLogger.py @@ -1,5 +1,5 @@ import gtk -import dbus +import dbus.service class ConsoleLogger(dbus.service.Object): def __init__(self): diff --git a/shell/Makefile.am b/shell/Makefile.am index 6410546e..486c4973 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -1,5 +1,3 @@ -SUBDIRS = session - bin_SCRIPTS = sugar sugardir = $(pkgdatadir)/shell @@ -10,6 +8,7 @@ sugar_PYTHON = \ Owner.py \ HomeWindow.py \ PresenceWindow.py \ + Session.py \ Shell.py EXTRA_DIST = sugar diff --git a/shell/Session.py b/shell/Session.py new file mode 100644 index 00000000..5f85c104 --- /dev/null +++ b/shell/Session.py @@ -0,0 +1,119 @@ +import os +import signal + +import gobject + +from Shell import Shell + +class Process: + def __init__(self, command): + self._pid = None + self._command = command + + def get_name(self): + return self._command + + def start(self): + splitted_cmd = self._command.split() + try: + self._pid = os.spawnvp(os.P_NOWAIT, splitted_cmd[0], splitted_cmd) + except Exception, e: + logging.error('Cannot run %s' % (self.get_name())) + + def stop(self): + # FIXME Obviously we want to notify the processes to + # shut down rather then killing them down forcefully. + print 'Stopping %s (%d)' % (self.get_name(), self._pid) + os.kill(self._pid, signal.SIGTERM) + +class ActivityProcess(Process): + def __init__(self, module): + Process.__init__(self, module.get_exec()) + self._module = module + + def get_name(self): + return self._module.get_name() + +class DbusProcess(Process): + def __init__(self): + Process.__init__(self, "/bin/dbus-daemon --session --print-address") + + def get_name(self): + return 'Dbus' + + def start(self): + args = self._command.split() + (self._pid, ign1, dbus_stdout, ign3) = gobject.spawn_async( + args, flags=gobject.SPAWN_STDERR_TO_DEV_NULL, standard_output=True) + + dbus_file = os.fdopen(dbus_stdout) + addr = dbus_file.readline() + addr = addr.strip() + dbus_file.close() + os.environ["DBUS_SESSION_BUS_ADDRESS"] = addr + +class MatchboxProcess(Process): + def __init__(self): + Process.__init__(self, 'matchbox-window-manager -use_titlebar no') + + def get_name(self): + return 'Matchbox' + +class XephyrProcess(Process): + def __init__(self): + # FIXME How to pick a free display number? + self._display = 100 + cmd = 'Xephyr :%d -ac -screen 640x480' % (self._display) + Process.__init__(self, cmd) + + def get_name(self): + return 'Xephyr' + + def start(self): + Process.start(self) + os.environ['DISPLAY'] = ":%d" % (self._display) + +class Session: + """Takes care of running the shell and all the sugar processes""" + + def __init__(self): + self._processes = [] + + self._shell = Shell() + self._shell.connect('close', self._shell_close_cb) + self._shell.start() + + def start(self): + """Start the session""" + # FIXME We should not start this on the olpc + process = XephyrProcess() + self._processes.insert(0, process) + process.start() + + process = DbusProcess() + self._processes.insert(0, process) + process.start() + + process = MatchboxProcess() + self._processes.insert(0, process) + process.start() + + registry = self._shell.get_registry() + for activity_module in registry.list_activities(): + process = ActivityProcess(activity_module) + self._processes.insert(0, process) + process.start() + + try: + import gtk + gtk.main() + except KeyboardInterrupt: + print 'Ctrl+C pressed, exiting...' + self.shutdown() + + def _shell_close_cb(self, shell): + self.shutdown() + + def shutdown(self): + for process in self._processes: + process.stop() diff --git a/shell/session/Makefile.am b/shell/session/Makefile.am deleted file mode 100644 index 23e4194e..00000000 --- a/shell/session/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -sugardir = $(pkgdatadir)/shell/session -sugar_PYTHON = \ - __init__.py \ - session.py diff --git a/shell/session/__init__.py b/shell/session/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/shell/session/session.py b/shell/session/session.py deleted file mode 100644 index d996aa76..00000000 --- a/shell/session/session.py +++ /dev/null @@ -1,70 +0,0 @@ -import os -import signal -from ConfigParser import ConfigParser - -import pygtk -pygtk.require('2.0') -import gtk - -from sugar.activity import Activity -from sugar import env - -from Shell import Shell - -class Session: - def __init__(self): - self._activity_processes = {} - - def start(self): - shell = Shell() - shell.connect('close', self._shell_close_cb) - shell.start() - - self._run_activities() - - try: - gtk.main() - except KeyboardInterrupt: - print 'Ctrl+C pressed, exiting...' - self.shutdown() - - def _run_activities(self): - base_dirs = [] - - base_dirs.append(env.get_activities_dir()) - base_dirs.append(os.path.join(env.get_user_dir(), 'activities')) - - for base_dir in base_dirs: - if os.path.isdir(base_dir): - for filename in os.listdir(base_dir): - activity_dir = os.path.join(base_dir, filename) - if os.path.isdir(activity_dir): - self._run_activity(os.path.abspath(activity_dir)) - - def _run_activity(self, activity_dir): - env.add_to_python_path(activity_dir) - - for filename in os.listdir(activity_dir): - if filename.endswith(".activity"): - path = os.path.join(activity_dir, filename) - cp = ConfigParser() - cp.read([path]) - - activity_name = cp.get('Activity', "name") - activity_class = cp.get('Activity', "class") - - args = [ 'python', '-m', 'sugar/activity/Activity' ] - args.append(activity_name) - args.append(activity_class) - pid = os.spawnvp(os.P_NOWAIT, 'python', args) - self._activity_processes[activity_name] = pid - - def _shell_close_cb(self, shell): - self.shutdown() - - def shutdown(self): - # FIXME Obviously we want to notify the activities to - # shutt down rather then killing them down forcefully. - for name in self._activity_processes.keys(): - print 'Shutting down %s' % (name) - os.kill(self._activity_processes[name], signal.SIGTERM) diff --git a/shell/sugar b/shell/sugar index d352442c..1a5d1ad0 100755 --- a/shell/sugar +++ b/shell/sugar @@ -5,11 +5,6 @@ import os import pwd import random -import gobject - -# FIXME How to pick a good display number -XEPHYR_DISPLAY = 100 - def add_to_python_path(path): sys.path.insert(0, path) if os.environ.has_key('PYTHONPATH'): @@ -18,54 +13,13 @@ def add_to_python_path(path): else: os.environ['PYTHONPATH'] = path -def start_dbus(): - curdir = os.path.dirname(__file__) - args = "/bin/dbus-daemon --session --print-address".split() - (dbus_pid, ign1, dbus_stdout, ign3) = gobject.spawn_async(args, flags=gobject.SPAWN_STDERR_TO_DEV_NULL, standard_output=True) - dbus_file = os.fdopen(dbus_stdout) - addr = dbus_file.readline() - addr = addr.strip() - dbus_file.close() - - os.environ["DBUS_SESSION_BUS_ADDRESS"] = addr - - return dbus_pid - -def stop_dbus(dbus_pid): - try: - print 'Closing dbus-daemon, pid %d' % (dbus_pid) - os.kill(dbus_pid, 9) - except OSError: - pass - -def start_xephyr(): - command = 'Xephyr :%d -ac -screen 640x480' % (XEPHYR_DISPLAY) - xephyr_pid = os.spawnvp(os.P_NOWAIT, 'Xephyr', command.split()) - -def stop_xephyr(): - os.kill(xephyr_pid) - -def start_matchbox(): - command = 'matchbox-window-manager -use_titlebar no' - xephyr_pid = os.spawnvp(os.P_NOWAIT, 'matchbox-window-manager', command.split()) - -def stop_matchbox(): - os.kill(xephyr_pid) - -start_xephyr() -os.environ['DISPLAY'] = ":%d" % (XEPHYR_DISPLAY) -start_matchbox() - i = 0 -dbus_daemon_pid = None for arg in sys.argv: if arg == '--test-user': user = sys.argv[i + 1] user_dir = os.path.expanduser('~/.sugar-' + user) os.environ['SUGAR_NICK_NAME'] = user os.environ['SUGAR_USER_DIR'] = user_dir - dbus_daemon_pid = start_dbus() - started_dbus = True i += 1 if not os.environ.has_key("SUGAR_NICK_NAME"): @@ -89,13 +43,7 @@ else: print 'Redirecting output to the console, press Ctrl+Down to open it.' -from session.session import Session +from Session import Session session = Session() session.start() - -if dbus_daemon_pid: - stop_dbus(dbus_daemon_pid) - -stop_matchbox() -stop_xephyr() diff --git a/sugar/activity/Activity.py b/sugar/activity/Activity.py index b397d154..bbccb9c7 100644 --- a/sugar/activity/Activity.py +++ b/sugar/activity/Activity.py @@ -12,7 +12,7 @@ from sugar.LogWriter import LogWriter from sugar import keybindings import sugar.util -SHELL_SERVICE_NAME = "com.redhat.Sugar.Shell" +SHELL_SERVICE_NAME = "caom.redhat.Sugar.Shell" SHELL_SERVICE_PATH = "/com/redhat/Sugar/Shell" ACTIVITY_SERVICE_NAME = "com.redhat.Sugar.Activity"