In preparation of enabling rainbow by default, remove
the factory service from the public API. The Exec field will now launch an activity instance. Add a -s argument to sugar-activity to enable the single process mode for activities that really need it.
This commit is contained in:
		
							parent
							
								
									6a4f83d37c
								
							
						
					
					
						commit
						6ebe910e93
					
				| @ -1,16 +1,9 @@ | ||||
| sugardir = $(pkgdatadir)/bin | ||||
| sugar_SCRIPTS = sugar-activity-factory | ||||
| 
 | ||||
| bin_PROGRAMS = sugar-native-factory | ||||
| 
 | ||||
| sugar_native_factory_SOURCE = sugar-native-factory.c | ||||
| sugar_native_factory_CFLAGS = $(NATIVE_FACTORY_CFLAGS) | ||||
| sugar_native_factory_LDADD = $(NATIVE_FACTORY_LIBS) | ||||
| 
 | ||||
| bin_SCRIPTS = 			\
 | ||||
| 	sugar			\
 | ||||
| 	sugar-activity		\
 | ||||
| 	sugar-activity-factory	\
 | ||||
| 	sugar-install-bundle | ||||
| 
 | ||||
| EXTRA_DIST =                    \
 | ||||
|  | ||||
| @ -16,67 +16,126 @@ | ||||
| # along with this program; if not, write to the Free Software | ||||
| # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| 
 | ||||
| import sys | ||||
| import os | ||||
| from ConfigParser import ConfigParser | ||||
| import sys | ||||
| import gettext | ||||
| from optparse import OptionParser | ||||
| 
 | ||||
| import pygtk | ||||
| pygtk.require('2.0') | ||||
| 
 | ||||
| from sugar import activity | ||||
| from sugar import env | ||||
| 
 | ||||
| # Setup the environment so that we run inside the Sugar shell | ||||
| cp = ConfigParser() | ||||
| cp.read([env.get_profile_path("session.info")]) | ||||
| os.environ['DBUS_SESSION_BUS_ADDRESS'] = cp.get('Session', 'dbus_address') | ||||
| os.environ['DISPLAY'] = cp.get('Session', 'display') | ||||
| del cp | ||||
| 
 | ||||
| import gtk | ||||
| import dbus | ||||
| import dbus.glib | ||||
| 
 | ||||
| from sugar.activity import activityfactory | ||||
| from sugar.activity import activityfactoryservice | ||||
| from sugar import logger | ||||
| from sugar.activity import activityhandle | ||||
| from sugar.bundle.activitybundle import ActivityBundle | ||||
| from sugar import _sugarext | ||||
| 
 | ||||
| def _success_cb(handler, exit): | ||||
|     if exit: | ||||
| activity_instances = [] | ||||
| 
 | ||||
| def activity_destroy_cb(window): | ||||
|     activity_instances.remove(window) | ||||
|     if len(activity_instances) == 0: | ||||
|         gtk.main_quit() | ||||
| 
 | ||||
| def _error_cb(handler, err): | ||||
|     print err | ||||
|     gtk.main_quit() | ||||
| def create_activity_instance(constructor, handle): | ||||
|     activity = constructor(handle) | ||||
|     activity.connect('destroy', activity_destroy_cb) | ||||
|     activity.show() | ||||
| 
 | ||||
| def print_help(self): | ||||
|     sys.exit(0) | ||||
| activity_info = None | ||||
|     activity_instances.append(activity) | ||||
| 
 | ||||
| if len(sys.argv) > 1: | ||||
|     activities = activity.get_registry().find_activity(sys.argv[1]) | ||||
|     if len(activities) > 0: | ||||
|         activity_info = activities[0] | ||||
| def get_single_process_path(service_name): | ||||
|     return '/' + service_name.replace('.', '/') | ||||
| 
 | ||||
| if activity_info == None: | ||||
|     print 'Usage:\n\n' \ | ||||
|           'sugar-activity [bundle]\n\n' \ | ||||
|           'Bundle can be a part of the service name or of bundle name.' | ||||
|     sys.exit(0) | ||||
| class SingleProcess(dbus.service.Object): | ||||
|     def __init__(self, service_name, constructor): | ||||
|         self.constructor = constructor | ||||
|      | ||||
|         bus = dbus.SessionBus() | ||||
|         bus_name = dbus.service.BusName(service_name, bus = bus) | ||||
|         object_path = get_single_process_path(service_name) | ||||
|         dbus.service.Object.__init__(self, bus_name, object_path) | ||||
| 
 | ||||
| bus = dbus.SessionBus() | ||||
| bus_object = bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus') | ||||
| try: | ||||
|     name = bus_object.GetNameOwner( | ||||
|         activity_info.service_name, dbus_interface='org.freedesktop.DBus') | ||||
| except  dbus.DBusException: | ||||
|     name = None | ||||
|     @dbus.service.method("org.laptop.SingleProcess", in_signature="a{ss}") | ||||
|     def create(self, handle_dict): | ||||
|         handle = activityhandle.create_from_dict(handle_dict) | ||||
|         create_activity_instance(self.constructor, handle) | ||||
| 
 | ||||
| if name: | ||||
|     service_name = activity_info.service_name | ||||
|     print '%s is already running, creating a new instance.' % service_name | ||||
| else: | ||||
|     activityfactoryservice.run(activity_info.path) | ||||
| parser = OptionParser() | ||||
| parser.add_option("-a", "--activity-id", dest="activity_id", | ||||
|                   help="identifier of the activity instance") | ||||
| parser.add_option("-o", "--object-id", dest="object_id", | ||||
|                   help="identifier of the associated datastore object") | ||||
| parser.add_option("-u", "--uri", dest="uri", | ||||
|                   help="URI to load") | ||||
| parser.add_option('-s', '--single-process', dest='single_process', | ||||
|                   action='store_true', | ||||
|                   help='start all the instances in the same process') | ||||
| (options, args) = parser.parse_args() | ||||
| 
 | ||||
| activityfactory.create(activity_info.service_name) | ||||
| if 'SUGAR_BUNDLE_PATH' not in os.environ: | ||||
|     print 'SUGAR_BUNDLE_PATH is not defined in the environment.' | ||||
|     sys.exit(1) | ||||
| 
 | ||||
| if len(args) == 0: | ||||
|     print 'A python class must be specified as first argument.' | ||||
|     sys.exit(1)     | ||||
| 
 | ||||
| bundle_path = os.environ['SUGAR_BUNDLE_PATH'] | ||||
| sys.path.append(bundle_path) | ||||
| 
 | ||||
| bundle = ActivityBundle(bundle_path) | ||||
| 
 | ||||
| logger.start(bundle.get_service_name()) | ||||
| 
 | ||||
| gettext.bindtextdomain(bundle.get_service_name(), | ||||
|                        bundle.get_locale_path()) | ||||
| gettext.textdomain(bundle.get_service_name()) | ||||
| 
 | ||||
| gtk.icon_theme_get_default().append_search_path(bundle.get_icons_path()) | ||||
| 
 | ||||
| _sugarext.set_prgname(bundle.get_service_name()) | ||||
| _sugarext.set_application_name(bundle.get_name()) | ||||
| 
 | ||||
| splitted_module = args[0].rsplit('.', 1) | ||||
| module_name = splitted_module[0] | ||||
| class_name = splitted_module[1] | ||||
| 
 | ||||
| module = __import__(module_name)         | ||||
| for comp in module_name.split('.')[1:]: | ||||
|     module = getattr(module, comp) | ||||
|     if hasattr(module, 'start'): | ||||
|         module.start() | ||||
| constructor = getattr(module, class_name) | ||||
| 
 | ||||
| handle = activityhandle.ActivityHandle( | ||||
|             activity_id=options.activity_id, | ||||
|             object_id=options.object_id, uri=options.uri) | ||||
| 
 | ||||
| if options.single_process is True: | ||||
|     bus = dbus.SessionBus() | ||||
|     service_name = bundle.get_service_name() | ||||
| 
 | ||||
|     bus_object = bus.get_object( | ||||
|             'org.freedesktop.DBus', '/org/freedesktop/DBus') | ||||
|     try: | ||||
|         name = bus_object.GetNameOwner( | ||||
|                 service_name, dbus_interface='org.freedesktop.DBus') | ||||
|     except  dbus.DBusException: | ||||
|         name = None | ||||
| 
 | ||||
|     if not name: | ||||
|         service = SingleProcess(service_name, constructor) | ||||
|     else: | ||||
|         single_process = bus.get_object( | ||||
|                 service_name, get_single_process_path(service_name)) | ||||
|         single_process.create(handle.get_dict()) | ||||
| 
 | ||||
|         print 'Created %s in a single process.' % service_name | ||||
|         sys.exit(0) | ||||
| 
 | ||||
| create_activity_instance(constructor, handle) | ||||
| 
 | ||||
| gtk.main() | ||||
|  | ||||
| @ -1,348 +0,0 @@ | ||||
| /*
 | ||||
| Copyright (c) 2007 Bert Freudenberg | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in | ||||
| all copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
| THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <signal.h> | ||||
| #include <errno.h> | ||||
| #include <sys/wait.h> | ||||
| #include <dbus/dbus.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| char* prog; | ||||
| 
 | ||||
| /* command and arguments for activity instance*/ | ||||
| static char* inst_argv[100]; | ||||
| static int   inst_argc = 0; | ||||
| 
 | ||||
| /* instance process ids */ | ||||
| static pid_t pidv[100]; | ||||
| static int   pidc = 0; | ||||
| 
 | ||||
| /* instance process id that exited before it was added */ | ||||
| static pid_t exited = 0; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* add and remove instances, quit when last instance exits*/ | ||||
| 
 | ||||
| static void | ||||
| quit() | ||||
| { | ||||
|   fprintf(stderr, "%s: quitting\n", prog); | ||||
|   exit(0); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void | ||||
| add_pid(pid_t pid) | ||||
| { | ||||
|   if (pid == exited) | ||||
|     { | ||||
|       fprintf(stderr, "%s: ign instance pid %i\n", prog, pid); | ||||
|       exited = 0; | ||||
|       if (pidc == 0) | ||||
| 	quit(); | ||||
|       return; | ||||
|     } | ||||
|   pidv[pidc++] = pid; | ||||
|   fprintf(stderr, "%s: add instance pid %i\n", prog, pid); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void | ||||
| remove_pid(pid_t pid) | ||||
| { | ||||
|   int i; | ||||
|   for (i=0; i<pidc; i++)  | ||||
|     if (pidv[i]==pid) | ||||
|       break; | ||||
|   if (i==pidc) | ||||
|     { | ||||
|       exited = pid; | ||||
|       return; | ||||
|     } | ||||
|   pidc--; | ||||
|   for ( ; i<pidc; i++) | ||||
|     pidv[i] = pidv[i+1]; | ||||
| 
 | ||||
|   fprintf(stderr, "%s: del instance pid %i\n", prog, pid); | ||||
| 
 | ||||
|   if (pidc == 0) | ||||
|     quit(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void | ||||
| sigchld_handler(int signum) | ||||
| { | ||||
|   int pid; | ||||
|   int status; | ||||
|   while (1) | ||||
|     { | ||||
|       pid = waitpid(WAIT_ANY, &status, WNOHANG); | ||||
|       if (pid <= 0) | ||||
| 	break; | ||||
|       remove_pid(pid); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* fork and exit a new activity instance */ | ||||
| 
 | ||||
| static void | ||||
| create_instance(int argc) | ||||
| { | ||||
|   pid_t pid = fork(); | ||||
|   | ||||
|   if (pid<0) | ||||
|     { | ||||
|       perror("fork failed"); | ||||
|       exit(1); | ||||
|     } | ||||
| 
 | ||||
|   inst_argv[argc] = NULL; | ||||
|   if (pid == 0) | ||||
|     { | ||||
|       execvp(inst_argv[0], inst_argv); | ||||
|       perror(inst_argv[0]); | ||||
|       exit(1); | ||||
|     } | ||||
| 
 | ||||
|   add_pid(pid); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* handle dbus Introspect() call */ | ||||
| 
 | ||||
| static DBusHandlerResult | ||||
| handle_introspect(DBusConnection *connection, DBusMessage* message) | ||||
| { | ||||
|   DBusMessage *reply; | ||||
|   const char *introspect_xml = | ||||
|     DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE | ||||
|     "<node>\n" | ||||
|     "	<interface name=\"org.freedesktop.DBus.Introspectable\">\n" | ||||
|     "		<method name=\"Introspect\">\n" | ||||
|     "			<arg direction=\"out\" type=\"s\" />\n" | ||||
|     "		</method>\n" | ||||
|     "	</interface>\n" | ||||
|     "	<interface name=\"org.laptop.ActivityFactory\">\n" | ||||
|     "		<method name=\"create\">\n" | ||||
|     "			<arg direction=\"in\" type=\"a{ss}\" />\n" | ||||
|     "		</method>\n" | ||||
|     "	</interface>\n" | ||||
|     "</node>\n"; | ||||
| 
 | ||||
|   reply = dbus_message_new_method_return(message); | ||||
|   dbus_message_append_args(reply, | ||||
| 			   DBUS_TYPE_STRING, &introspect_xml, | ||||
| 			   DBUS_TYPE_INVALID); | ||||
| 
 | ||||
|   dbus_connection_send(connection, reply, NULL); | ||||
|   dbus_message_unref(reply); | ||||
| 
 | ||||
|   return DBUS_HANDLER_RESULT_HANDLED; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* handle dbus create() call */ | ||||
| 
 | ||||
| static DBusHandlerResult | ||||
| handle_create(DBusConnection *connection, DBusMessage* message) | ||||
| { | ||||
|   DBusMessage *reply; | ||||
|   DBusMessageIter iter_arss, iter_rss, iter_ss; | ||||
|   char *key, *value; | ||||
|   char *activity_id = 0; | ||||
|   int   argc = inst_argc; | ||||
| 
 | ||||
|   dbus_message_iter_init(message, &iter_arss); | ||||
|   if (strcmp("a{ss}", dbus_message_iter_get_signature(&iter_arss))) | ||||
|     { | ||||
|       reply = dbus_message_new_error(message,  | ||||
| 				     DBUS_ERROR_INVALID_ARGS,  | ||||
| 				     "signature a{ss} expected"); | ||||
|       dbus_connection_send(connection, reply, NULL); | ||||
|       dbus_message_unref(reply); | ||||
|       return DBUS_HANDLER_RESULT_HANDLED; | ||||
|     } | ||||
| 
 | ||||
|   dbus_message_iter_recurse(&iter_arss, &iter_rss); | ||||
| 
 | ||||
|   do | ||||
|     { | ||||
|       dbus_message_iter_recurse(&iter_rss, &iter_ss); | ||||
|       dbus_message_iter_get_basic(&iter_ss, &key); | ||||
|       dbus_message_iter_next(&iter_ss); | ||||
|       dbus_message_iter_get_basic(&iter_ss, &value);  | ||||
| 
 | ||||
|       inst_argv[argc++] = key; | ||||
|       inst_argv[argc++] = value; | ||||
| 
 | ||||
|       if (!strcmp("activity_id", key)) | ||||
| 	activity_id = value; | ||||
| 
 | ||||
|     } while(dbus_message_iter_next(&iter_rss)); | ||||
| 
 | ||||
|   if (!activity_id) | ||||
|     { | ||||
|       reply = dbus_message_new_error(message,  | ||||
| 				     DBUS_ERROR_INVALID_ARGS,  | ||||
| 				     "'activity_id' expected"); | ||||
|       dbus_connection_send(connection, reply, NULL); | ||||
|       dbus_message_unref(reply); | ||||
|       return DBUS_HANDLER_RESULT_HANDLED; | ||||
|     } | ||||
| 
 | ||||
|   create_instance(argc); | ||||
| 
 | ||||
|   reply = dbus_message_new_method_return(message); | ||||
|   dbus_connection_send(connection, reply, NULL); | ||||
|   dbus_message_unref(reply); | ||||
| 
 | ||||
|   return DBUS_HANDLER_RESULT_HANDLED; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* activity factory dbus service */ | ||||
| 
 | ||||
| static void | ||||
| factory_unregistered_func(DBusConnection  *connection, | ||||
| 			  void            *user_data) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static DBusHandlerResult | ||||
| factory_message_func(DBusConnection  *connection, | ||||
| 		     DBusMessage     *message, | ||||
| 		     void            *user_data) | ||||
| { | ||||
|   if (dbus_message_is_method_call(message, | ||||
| 				  "org.freedesktop.DBus.Introspectable", | ||||
| 				  "Introspect")) | ||||
|     return handle_introspect(connection, message); | ||||
|   else if (dbus_message_is_method_call(message, | ||||
| 				       "org.laptop.ActivityFactory", | ||||
| 				       "create")) | ||||
|     return handle_create(connection, message); | ||||
|   else | ||||
|     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static DBusObjectPathVTable | ||||
| factory_vtable = { | ||||
|   factory_unregistered_func, | ||||
|   factory_message_func, | ||||
|   NULL, | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* register service and run main loop */ | ||||
| 
 | ||||
| static char* | ||||
| dots_to_slashes(char* dotted) | ||||
| { | ||||
|     char* slashed = (char*) malloc(strlen(dotted)+2); | ||||
|     char* p = slashed; | ||||
|     *p++ = '/'; | ||||
|     strcpy(p, dotted); | ||||
|     while (*++p) if (*p == '.') *p = '/'; | ||||
|     return slashed; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
|   DBusConnection *connection; | ||||
|   DBusError error; | ||||
|   int result; | ||||
|   int i; | ||||
|   char* service; | ||||
|   | ||||
|   if (argc < 3)  | ||||
|     { | ||||
|       printf("Usage: %s org.laptop.MyActivity cmd args\n", argv[0]); | ||||
|       printf("\twhere cmd will be invoked as\n"); | ||||
|       printf("\tcmd args                           \\\n"); | ||||
|       printf("\t   bundle_id org.laptop.MyActivity \\\n"); | ||||
|       printf("\t   activity_id 123ABC...           \\\n"); | ||||
|       printf("\t   object_id 456DEF...             \\\n"); | ||||
|       printf("\t   pservice_id 789ACE..            \\\n"); | ||||
|       printf("\t   uri file:///path/to/file\n"); | ||||
|       printf("\tas given in the org.laptop.ActivityFactory.create() call\n"); | ||||
|       exit(1); | ||||
|     } | ||||
|   prog = argv[0]; | ||||
|   service = argv[1]; | ||||
| 
 | ||||
|   for (i = 2; i<argc; i++) | ||||
|     inst_argv[inst_argc++] = argv[i]; | ||||
|   inst_argv[inst_argc++] = "bundle_id"; | ||||
|   inst_argv[inst_argc++] = service; | ||||
|    | ||||
|   signal(SIGCHLD, sigchld_handler); | ||||
| 
 | ||||
|   dbus_error_init(&error); | ||||
| 
 | ||||
|   connection = dbus_bus_get(DBUS_BUS_SESSION, &error); | ||||
|   if (dbus_error_is_set(&error)) | ||||
|     { | ||||
|       fprintf(stderr, "%s: could not get bus connection: %s\n", prog, error.message); | ||||
|       exit(1); | ||||
|     } | ||||
| 
 | ||||
|   result = dbus_bus_request_name(connection,  | ||||
| 				 service,  | ||||
| 				 DBUS_NAME_FLAG_DO_NOT_QUEUE,  | ||||
| 				 &error); | ||||
|   if (dbus_error_is_set(&error)) | ||||
|     { | ||||
|       fprintf(stderr, "%s: could not aquire name %s: %s\n", prog, service, error.message); | ||||
|       exit(1); | ||||
|     } | ||||
|   if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) | ||||
|     { | ||||
|       fprintf(stderr, "%s: could not become primary owner of %s\n", prog, service); | ||||
|       exit(1); | ||||
|    } | ||||
|    | ||||
|   dbus_connection_register_object_path(connection,  | ||||
| 				       dots_to_slashes(service),  | ||||
| 				       &factory_vtable,  | ||||
| 				       NULL); | ||||
| 
 | ||||
|   while (dbus_connection_read_write_dispatch(connection, -1)) | ||||
|      ; | ||||
| 
 | ||||
|   _exit(0); | ||||
| } | ||||
| @ -114,6 +114,7 @@ class ActivityRegistry(dbus.service.Object): | ||||
|                 'icon': bundle.get_icon(), | ||||
|                 'service_name': bundle.get_service_name(), | ||||
|                 'path': bundle.get_path(), | ||||
|                 'command': bundle.get_command(), | ||||
|                 'show_launcher': bundle.get_show_launcher()} | ||||
| 
 | ||||
|     def _bundle_added_cb(self, bundle_registry, bundle): | ||||
|  | ||||
| @ -3,7 +3,6 @@ sugar_PYTHON =				\ | ||||
| 	__init__.py			\
 | ||||
| 	activity.py			\
 | ||||
| 	activityfactory.py		\
 | ||||
| 	activityfactoryservice.py	\
 | ||||
| 	activityhandle.py		\
 | ||||
| 	activityservice.py		\
 | ||||
| 	bundlebuilder.py		\
 | ||||
|  | ||||
| @ -17,6 +17,8 @@ | ||||
| # Boston, MA 02111-1307, USA. | ||||
| 
 | ||||
| import logging | ||||
| import subprocess | ||||
| import signal | ||||
| 
 | ||||
| import dbus | ||||
| import gobject | ||||
| @ -24,11 +26,14 @@ import gtk | ||||
| 
 | ||||
| from sugar.presence import presenceservice | ||||
| from sugar.activity.activityhandle import ActivityHandle | ||||
| from sugar.activity import registry | ||||
| from sugar.datastore import datastore | ||||
| from sugar import util | ||||
| 
 | ||||
| import os | ||||
| 
 | ||||
| signal.signal(signal.SIGCHLD, signal.SIG_IGN) | ||||
| 
 | ||||
| # #3903 - this constant can be removed and assumed to be 1 when dbus-python | ||||
| # 0.82.3 is the only version used | ||||
| if dbus.version >= (0, 82, 3): | ||||
| @ -148,11 +153,21 @@ class ActivityCreationHandler(gobject.GObject): | ||||
|                     error_handler=self._notify_launch_error_handler) | ||||
| 
 | ||||
|         if not os.path.exists('/etc/olpc-security'): | ||||
|             handle = self._handle.get_dict()  | ||||
|             self._factory.create(dbus.Dictionary(handle, signature='ss'), | ||||
|                                  timeout=120 * DBUS_PYTHON_TIMEOUT_UNITS_PER_SECOND, | ||||
|                                  reply_handler=self._no_reply_handler, | ||||
|                                  error_handler=self._create_error_handler) | ||||
|             activity_registry = registry.get_registry() | ||||
|             activity = activity_registry.get_activity(self._service_name) | ||||
|             if activity: | ||||
|                 env = os.environ.copy() | ||||
|                 env['SUGAR_BUNDLE_PATH'] = activity.path | ||||
| 
 | ||||
|                 command = activity.command | ||||
|                 if self._handle.activity_id is not None: | ||||
|                     command += ' -a %s' % self._handle.activity_id | ||||
|                 if self._handle.object_id is not None: | ||||
|                     command += ' -o %s' % self._handle.object_id | ||||
|                 if self._handle.uri is not None: | ||||
|                     command += ' -u %s' % self._handle.uri | ||||
| 
 | ||||
|                 process = subprocess.Popen(command, env=env, shell=True) | ||||
|         else: | ||||
|             system_bus = dbus.SystemBus() | ||||
|             factory = system_bus.get_object(_RAINBOW_SERVICE_NAME, | ||||
|  | ||||
| @ -1,175 +0,0 @@ | ||||
| # Copyright (C) 2006-2007 Red Hat, Inc. | ||||
| # | ||||
| # This library is free software; you can redistribute it and/or | ||||
| # modify it under the terms of the GNU Lesser General Public | ||||
| # License as published by the Free Software Foundation; either | ||||
| # version 2 of the License, or (at your option) any later version. | ||||
| # | ||||
| # This library is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
| # Lesser General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU Lesser General Public | ||||
| # License along with this library; if not, write to the | ||||
| # Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||||
| # Boston, MA 02111-1307, USA. | ||||
| 
 | ||||
| import os | ||||
| import sys | ||||
| from optparse import OptionParser | ||||
| import gettext | ||||
| import traceback | ||||
| import logging | ||||
| 
 | ||||
| import gobject | ||||
| import gtk | ||||
| import dbus | ||||
| import dbus.service | ||||
| import dbus.glib | ||||
| 
 | ||||
| from sugar.bundle.activitybundle import ActivityBundle | ||||
| from sugar.activity import activityhandle | ||||
| from sugar import logger | ||||
| from sugar import _sugarext | ||||
| from sugar import env | ||||
| 
 | ||||
| # Work around for dbus mutex locking issue | ||||
| gobject.threads_init() | ||||
| dbus.glib.threads_init() | ||||
| 
 | ||||
| _ACTIVITY_FACTORY_INTERFACE = "org.laptop.ActivityFactory" | ||||
| 
 | ||||
| class ActivityFactoryService(dbus.service.Object): | ||||
|     """D-Bus service that creates instances of Python activities | ||||
|      | ||||
|     The ActivityFactoryService is a dbus service created for  | ||||
|     each Python based activity type (that is, each activity  | ||||
|     bundle which declares a "class" in its activity.info file, | ||||
|     rather than an "exec"). | ||||
|      | ||||
|     The ActivityFactoryService is the actual process which  | ||||
|     instantiates the Python classes for Sugar interfaces.  That | ||||
|     is, your Python code runs in the same process as the  | ||||
|     ActivityFactoryService itself. | ||||
|      | ||||
|     The "service" process is created at the moment Sugar first  | ||||
|     attempts to create an instance of the activity type.  It | ||||
|     then remains in memory until the last instance of the  | ||||
|     activity type is terminated. | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, service_name, activity_class): | ||||
|         """Initialize the service to create activities of this type | ||||
|          | ||||
|         service_name -- bundle's service name, this is used  | ||||
|             to construct the dbus service name used to access | ||||
|             the created service. | ||||
|         activity_class -- dotted Python class name for the  | ||||
|             Activity class which is to be instantiated by  | ||||
|             the service.  Assumed to be composed of a module  | ||||
|             followed by a class. | ||||
|              | ||||
|         if the module specified has a "start" attribute this object | ||||
|         will be called on service initialisation (before first  | ||||
|         instance is created). | ||||
|          | ||||
|         if the module specified has a "stop" attribute this object  | ||||
|         will be called after every instance exits (note: may be  | ||||
|         called multiple times for each time start is called!) | ||||
|         """ | ||||
|         self._activities = [] | ||||
|         self._service_name = service_name | ||||
| 
 | ||||
|         splitted_module = activity_class.rsplit('.', 1) | ||||
|         module_name = splitted_module[0] | ||||
|         class_name = splitted_module[1] | ||||
| 
 | ||||
|         module = __import__(module_name)         | ||||
|         for comp in module_name.split('.')[1:]: | ||||
|             module = getattr(module, comp) | ||||
|         if hasattr(module, 'start'): | ||||
|             module.start() | ||||
| 
 | ||||
|         self._module = module | ||||
|         self._constructor = getattr(module, class_name) | ||||
|      | ||||
|         bus = dbus.SessionBus() | ||||
|         bus_name = dbus.service.BusName(service_name, bus = bus) | ||||
|         object_path = '/' + service_name.replace('.', '/') | ||||
|         dbus.service.Object.__init__(self, bus_name, object_path) | ||||
| 
 | ||||
|     @dbus.service.method("org.laptop.ActivityFactory", in_signature="a{ss}") | ||||
|     def create(self, handle): | ||||
|         """Create a new instance of this activity  | ||||
|          | ||||
|         handle -- sugar.activity.activityhandle.ActivityHandle | ||||
|             compatible dictionary providing the instance-specific | ||||
|             values for the new instance  | ||||
|          | ||||
|         returns xid for the created instance' root window | ||||
|         """ | ||||
|         activity_handle = activityhandle.create_from_dict(handle) | ||||
| 
 | ||||
|         try: | ||||
|             activity = self._constructor(activity_handle) | ||||
|         except Exception, e: | ||||
|             logging.error(traceback.format_exc()) | ||||
|             sys.exit(1) | ||||
| 
 | ||||
|         activity.present() | ||||
| 
 | ||||
|         self._activities.append(activity) | ||||
|         activity.connect('destroy', self._activity_destroy_cb) | ||||
| 
 | ||||
|         return activity.window.xid | ||||
| 
 | ||||
|     def _activity_destroy_cb(self, activity): | ||||
|         """On close of an instance's root window | ||||
|          | ||||
|         Removes the activity from the tracked activities. | ||||
|          | ||||
|         If our implementation module has a stop, calls  | ||||
|         that. | ||||
|          | ||||
|         If there are no more tracked activities, closes  | ||||
|         the activity. | ||||
|         """ | ||||
|         self._activities.remove(activity) | ||||
| 
 | ||||
|         if hasattr(self._module, 'stop'): | ||||
|             self._module.stop() | ||||
| 
 | ||||
|         if len(self._activities) == 0: | ||||
|             gtk.main_quit() | ||||
| 
 | ||||
| def run_with_args(args): | ||||
|     """Start the activity factory.""" | ||||
|     parser = OptionParser() | ||||
|     parser.add_option("-p", "--bundle-path", dest="bundle_path", | ||||
|                       help="path to the activity bundle") | ||||
|     (options, args) = parser.parse_args() | ||||
| 
 | ||||
|     run(options.bundle_path) | ||||
| 
 | ||||
| def run(bundle_path): | ||||
|     sys.path.append(bundle_path) | ||||
| 
 | ||||
|     bundle = ActivityBundle(bundle_path) | ||||
| 
 | ||||
|     logger.start(bundle.get_service_name()) | ||||
| 
 | ||||
|     gettext.bindtextdomain(bundle.get_service_name(), | ||||
|                            bundle.get_locale_path()) | ||||
|     gettext.textdomain(bundle.get_service_name()) | ||||
| 
 | ||||
|     gtk.icon_theme_get_default().append_search_path(bundle.get_icons_path()) | ||||
| 
 | ||||
|     os.environ['SUGAR_BUNDLE_PATH'] = bundle_path | ||||
|     os.environ['SUGAR_ACTIVITY_ROOT'] = env.get_profile_path(bundle.get_service_name()) | ||||
| 
 | ||||
|     _sugarext.set_prgname(bundle.get_service_name()) | ||||
|     _sugarext.set_application_name(bundle.get_name()) | ||||
| 
 | ||||
|     factory = ActivityFactoryService(bundle.get_service_name(), | ||||
|                                      bundle.activity_class) | ||||
| @ -30,14 +30,16 @@ def _activity_info_from_dict(info_dict): | ||||
|         return None | ||||
|     return ActivityInfo(info_dict['name'], info_dict['icon'], | ||||
|                         info_dict['service_name'], info_dict['path'], | ||||
|                         info_dict['show_launcher']) | ||||
|                         info_dict['show_launcher'], info_dict['command']) | ||||
| 
 | ||||
| class ActivityInfo(object): | ||||
|     def __init__(self, name, icon, service_name, path, show_launcher): | ||||
|     def __init__(self, name, icon, service_name, | ||||
|                  path, show_launcher, command): | ||||
|         self.name = name | ||||
|         self.icon = icon | ||||
|         self.service_name = service_name | ||||
|         self.path = path | ||||
|         self.command = command | ||||
|         self.show_launcher = show_launcher | ||||
| 
 | ||||
| class ActivityRegistry(gobject.GObject): | ||||
|  | ||||
| @ -26,8 +26,6 @@ from sugar.bundle.bundle import Bundle, MalformedBundleException | ||||
| from sugar import activity | ||||
| from sugar import env | ||||
| 
 | ||||
| _PYTHON_FACTORY='sugar-activity-factory' | ||||
| 
 | ||||
| class ActivityBundle(Bundle): | ||||
|     """A Sugar activity bundle | ||||
|      | ||||
| @ -81,6 +79,7 @@ class ActivityBundle(Bundle): | ||||
|             raise MalformedBundleException( | ||||
|                 'Activity bundle %s does not specify a name' % self._path) | ||||
| 
 | ||||
|         # FIXME class is deprecated | ||||
|         if cp.has_option(section, 'class'): | ||||
|             self.activity_class = cp.get(section, 'class') | ||||
|         elif cp.has_option(section, 'exec'): | ||||
| @ -181,12 +180,9 @@ class ActivityBundle(Bundle): | ||||
|     def get_command(self): | ||||
|         """Get the command to execute to launch the activity factory""" | ||||
|         if self.bundle_exec: | ||||
|             command = os.path.join(self._path, self.bundle_exec) | ||||
|             command = command.replace('$SUGAR_BUNDLE_PATH', self._path) | ||||
|             command = os.path.expandvars(command) | ||||
|             command = os.path.expandvars(self.bundle_exec) | ||||
|         else: | ||||
|             command = '%s --bundle-path="%s"' % ( | ||||
|                   env.get_bin_path(_PYTHON_FACTORY), self._path) | ||||
|             command = 'sugar-activity ' + self.activity_class | ||||
| 
 | ||||
|         return command | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Marco Pesenti Gritti
						Marco Pesenti Gritti