Cleanup and document session creation and activity registry
This commit is contained in:
		
							parent
							
								
									e959a6f37f
								
							
						
					
					
						commit
						ca2b08f8b6
					
				@ -1,3 +1,4 @@
 | 
			
		||||
[Activity]
 | 
			
		||||
name = com.redhat.Sugar.BrowserActivity
 | 
			
		||||
class = BrowserActivity.BrowserActivity
 | 
			
		||||
name = Web
 | 
			
		||||
id = com.redhat.Sugar.BrowserActivity
 | 
			
		||||
python_module = BrowserActivity.BrowserActivity
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import gtk
 | 
			
		||||
import dbus
 | 
			
		||||
import dbus.service
 | 
			
		||||
 | 
			
		||||
class ConsoleLogger(dbus.service.Object):
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										119
									
								
								shell/Session.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								shell/Session.py
									
									
									
									
									
										Normal file
									
								
							@ -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()
 | 
			
		||||
@ -1,4 +0,0 @@
 | 
			
		||||
sugardir = $(pkgdatadir)/shell/session
 | 
			
		||||
sugar_PYTHON =		\
 | 
			
		||||
	__init__.py	\
 | 
			
		||||
	session.py
 | 
			
		||||
@ -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)
 | 
			
		||||
							
								
								
									
										54
									
								
								shell/sugar
									
									
									
									
									
								
							
							
						
						
									
										54
									
								
								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()
 | 
			
		||||
 | 
			
		||||
@ -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"
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user