[Sugar-devel] [PATCH] sugar-activity: make independent of sugar-toolkit GTK versions

Daniel Drake dsd at laptop.org
Fri Dec 9 16:25:28 EST 2011


As we move to adding support for a second UI toolkit (GTK+ 3.x),
the sugar-activity binary used by all activities must become
backend-toolkit-independent. It would be wasteful to have two backend
toolkits loaded in memory, and in the GTK2/GTK3 case, it is impossible
(importing both results in an instant crash).

To achieve this, we split the existing sugar-toolkit activity/main.py:main()
functionality into two parts, moving it into the sugar-activity binary and
the Activity class as follows:
 1. All toolkit-specific stuff is moved into the Activity class (i.e.
    everything that interacts with GTK)
 2. Everything that can be reasonably/easily moved into the Activity class
    is also moved.
 3. What remains is the stuff that is inherently involved with the
    construction of the Activity object, not related to UI toolkits. This
    is moved into the sugar-activity binary.

main.py is then removed from sugar-toolkit.

With this work done, the one remaining question is how to invoke the main
loop. An optional run_main_loop() method is added to the activity class,
for GTK2 this will run the GTK2 main loop, for GTK3 the GTK3 main loop will
be run, etc.

This patch is accompanied by a sugar-toolkit patch titled
"Restructure for new /usr/bin/sugar-activity behaviour"
which adapts the GTK2 sugar-toolkit to these changes.

Signed-off-by: Daniel Drake <dsd at laptop.org>
---
 bin/sugar-activity |  130 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 128 insertions(+), 2 deletions(-)

diff --git a/bin/sugar-activity b/bin/sugar-activity
index 4abdd80..2b1b9b3 100644
--- a/bin/sugar-activity
+++ b/bin/sugar-activity
@@ -16,6 +16,132 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-from sugar.activity import main
+import os
+import sys
+import gettext
+from optparse import OptionParser
 
-main.main()
+import dbus
+import dbus.service
+import dbus.glib
+
+import sugar
+from sugar.activity import activityhandle
+from sugar.bundle.activitybundle import ActivityBundle
+from sugar import logger
+
+
+def create_activity_instance(constructor, handle):
+    activity = constructor(handle)
+    activity.show()
+    return activity
+
+
+def get_single_process_name(bundle_id):
+    return bundle_id
+
+
+def get_single_process_path(bundle_id):
+    return '/' + bundle_id.replace('.', '/')
+
+
+class SingleProcess(dbus.service.Object):
+
+    def __init__(self, name_service, constructor):
+        self.constructor = constructor
+
+        bus = dbus.SessionBus()
+        bus_name = dbus.service.BusName(name_service, bus=bus)
+        object_path = get_single_process_path(name_service)
+        dbus.service.Object.__init__(self, bus_name, object_path)
+
+    @dbus.service.method('org.laptop.SingleProcess', in_signature='a{sv}')
+    def create(self, handle_dict):
+        handle = activityhandle.create_from_dict(handle_dict)
+        create_activity_instance(self.constructor, handle)
+
+def main():
+    parser = OptionParser()
+    parser.add_option('-b', '--bundle-id', dest='bundle_id',
+                      help='identifier of the activity bundle')
+    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')
+    parser.add_option('-i', '--invited', dest='invited',
+                      action='store_true', default=False,
+                      help='the activity is being launched for handling an '
+                           'invite from the network')
+    (options, args) = parser.parse_args()
+
+    logger.start()
+
+    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)
+
+    os.environ['SUGAR_BUNDLE_ID'] = bundle.get_bundle_id()
+    os.environ['SUGAR_BUNDLE_NAME'] = bundle.get_name()
+    os.environ['SUGAR_BUNDLE_VERSION'] = str(bundle.get_activity_version())
+
+    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)
+
+    activity_constructor = getattr(module, class_name)
+    activity_handle = activityhandle.ActivityHandle(
+            activity_id=options.activity_id,
+            object_id=options.object_id, uri=options.uri,
+            invited=options.invited)
+
+    if options.single_process is True:
+        sessionbus = dbus.SessionBus()
+
+        service_name = get_single_process_name(options.bundle_id)
+        service_path = get_single_process_path(options.bundle_id)
+
+        bus_object = sessionbus.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:
+            SingleProcess(service_name, activity_constructor)
+        else:
+            single_process = sessionbus.get_object(service_name, service_path)
+            single_process.create(activity_handle.get_dict(),
+                                  dbus_interface='org.laptop.SingleProcess')
+
+            print 'Created %s in a single process.' % service_name
+            sys.exit(0)
+
+    if hasattr(module, 'start'):
+        module.start()
+
+    instance = create_activity_instance(activity_constructor, activity_handle)
+
+    if hasattr(instance, 'run_main_loop'):
+        instance.run_main_loop()
+
+main()
-- 
1.7.7.3



More information about the Sugar-devel mailing list