[Sugar-devel] [PATCH TypingTurtle 2/2] Port to Gtk3 SL #3772

Manuel Kaufmann humitos at gmail.com
Thu Aug 2 09:45:16 EDT 2012


This commit ports Typing Turtle to its Gtk3 version.

Signed-off-by: Manuel Kaufmann <humitos at gmail.com>
---
 balloongame.py          | 161 +++++++++++++------------
 editlessonlistscreen.py | 100 ++++++++--------
 editlessonscreen.py     | 309 ++++++++++++++++++++++++------------------------
 keyboard.py             | 127 ++++++++++----------
 keybuilder.py           |  30 ++---
 lessonbuilder.py        |   8 +-
 lessonscreen.py         |  94 ++++++++-------
 mainscreen.py           | 101 ++++++++--------
 medalscreen.py          |  86 +++++++-------
 port/chooser.py         |   8 +-
 setup.py                |   2 +-
 titlescene.py           |  54 +++++----
 typingturtle.py         |  99 ++++++++--------
 13 files changed, 600 insertions(+), 579 deletions(-)

diff --git a/balloongame.py b/balloongame.py
index 7224893..2380e95 100644
--- a/balloongame.py
+++ b/balloongame.py
@@ -16,11 +16,14 @@
 
 import math
 import random, datetime
-import pangocairo
 
 from gettext import gettext as _
 
-import gobject, pygtk, gtk, pango
+from gi.repository import Gtk
+from gi.repository import Gdk
+from gi.repository import GObject
+from gi.repository import Pango
+from gi.repository import PangoCairo
 
 import medalscreen
 
@@ -41,37 +44,37 @@ class Balloon:
         self.size = max(100, 50 + len(word) * 20) 
         self.color = random.choice(BALLOON_COLORS)
 
-class BalloonGame(gtk.VBox):
+class BalloonGame(Gtk.VBox):
     def __init__(self, lesson, activity):
-        gtk.VBox.__init__(self)
+        GObject.GObject.__init__(self)
         
         self.lesson = lesson
         self.activity = activity
         
         # Build title bar.
-        title = gtk.Label()
+        title = Gtk.Label()
         title.set_markup("<span size='20000'><b>" + lesson['name'] + "</b></span>")
         title.set_alignment(1.0, 0.0)
         
-        stoplabel = gtk.Label(_('Go Back'))
-        stopbtn =  gtk.Button()
+        stoplabel = Gtk.Label(label=_('Go Back'))
+        stopbtn =  Gtk.Button()
         stopbtn.add(stoplabel)
         stopbtn.connect('clicked', self.stop_cb)
         
-        hbox = gtk.HBox()
+        hbox = Gtk.HBox()
         hbox.pack_start(stopbtn, False, False, 10)
         hbox.pack_end(title, False, False, 10)
         
         # Build the game drawing area.
-        self.area = gtk.DrawingArea()
-        self.area.connect("expose-event", self.expose_cb)
+        self.area = Gtk.DrawingArea()
+        self.draw_cb_id = self.area.connect("draw", self.draw_cb)
 
         # Connect keyboard grabbing and releasing callbacks.        
         self.area.connect('realize', self.realize_cb)
         self.area.connect('unrealize', self.unrealize_cb)
 
         self.pack_start(hbox, False, False, 10)
-        self.pack_start(self.area, True, True)
+        self.pack_start(self.area, True, True, 0)
         
         self.show_all()
         
@@ -88,16 +91,16 @@ class BalloonGame(gtk.VBox):
         self.finished = False
 
         # Start the animation loop running.        
-        self.update_timer = gobject.timeout_add(20, self.tick, priority=gobject.PRIORITY_HIGH_IDLE+30)
+        self.update_timer = GObject.timeout_add(20, self.tick, priority=GObject.PRIORITY_HIGH_IDLE+30)
     
     def realize_cb(self, widget):
-        self.activity.add_events(gtk.gdk.KEY_PRESS_MASK)
+        self.activity.add_events(Gdk.EventMask.KEY_PRESS_MASK)
         self.key_press_cb_id = self.activity.connect('key-press-event', self.key_cb)
 
         # Clear the mouse cursor. 
-        #pixmap = gtk.gdk.Pixmap(widget.window, 10, 10)
-        #color = gtk.gdk.Color()
-        #cursor = gtk.gdk.Cursor(pixmap, pixmap, color, color, 5, 5)
+        #pixmap = Gdk.Pixmap(widget.window, 10, 10)
+        #color = Gdk.Color()
+        #cursor = Gdk.Cursor.new(pixmap, pixmap, color, color, 5, 5)
         #widget.window.set_cursor(cursor)
         
     def unrealize_cb(self, widget):
@@ -106,21 +109,21 @@ class BalloonGame(gtk.VBox):
     def stop_cb(self, widget):
         # Stop the animation loop.
         if self.update_timer:
-            gobject.source_remove(self.update_timer)
+            GObject.source_remove(self.update_timer)
         
         self.activity.pop_screen()
 
     def key_cb(self, widget, event):
         # Ignore hotkeys.
-        if event.state & (gtk.gdk.CONTROL_MASK | gtk.gdk.MOD1_MASK):
+        if event.get_state() & (Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.MOD1_MASK):
             return False
 
         # Extract information about the key pressed.
-        key = gtk.gdk.keyval_to_unicode(event.keyval)
+        key = Gdk.keyval_to_unicode(event.keyval)
         if key != 0: key = unichr(key)
 
         if self.finished:
-            key_name = gtk.gdk.keyval_name(event.keyval)
+            key_name = Gdk.keyval_name(event.keyval)
             if key_name == 'Return':
                 self.activity.pop_screen()
 
@@ -159,7 +162,7 @@ class BalloonGame(gtk.VBox):
     
     def tick(self):
         if self.finished:
-            return
+            return False
 
         self.bounds = self.area.get_allocation()
             
@@ -213,17 +216,19 @@ class BalloonGame(gtk.VBox):
         # Draw text
         title = _('You finished!') + '\n'
 
-        pango_cr = pangocairo.CairoContext(cr)
-        pango_cr.set_source_rgb(0, 0, 0)
-        pango_layout = cr.create_layout()
-        pango_layout.set_font_description(pango.FontDescription('Serif Bold 16'))
-        pango_layout.set_text(title)
+        cr.set_source_rgb(0, 0, 0)
+        pango_layout = PangoCairo.create_layout(cr)
+        fd = Pango.FontDescription('Serif Bold')
+        fd.set_size(16 * Pango.SCALE)
+        pango_layout.set_font_description(fd)
+        pango_layout.set_text(title.encode('utf-8'),
+                              len(title.encode('utf-8')))
         size = pango_layout.get_size()
-        tx = x + (w / 2) - (size[0] / pango.SCALE) / 2
+        tx = x + (w / 2) - (size[0] / Pango.SCALE) / 2
         ty = y + 100
-        pango_cr.move_to(tx, ty)
-        pango_cr.show_layout(pango_layout)
-        pango_cr.stroke()
+        cr.move_to(tx, ty)
+        PangoCairo.update_layout(cr, pango_layout)
+        PangoCairo.show_layout(cr, pango_layout)
 
         report = ''
         report += _('Your score was %(score)d.') % { 'score': self.score } + '\n'
@@ -232,18 +237,18 @@ class BalloonGame(gtk.VBox):
         report += '\n'
         report += _('Press the ENTER key to continue.')
     
-        pango_cr = pangocairo.CairoContext(cr)
-        pango_cr.set_source_rgb(0, 0, 0)
-        pango_layout = cr.create_layout()
-        pango_layout.set_font_description(pango.FontDescription('Times 12'))
-        pango_layout.set_text(report)
+        cr.set_source_rgb(0, 0, 0)
+        pango_layout = PangoCairo.create_layout(cr)
+        fd = Pango.FontDescription('Times')
+        fd.set_size(12 * Pango.SCALE)
+        pango_layout.set_font_description(fd)
+        pango_layout.set_text(report, len(report))
         size = pango_layout.get_size()
-        sx = x + w / 2 - (size[0] / pango.SCALE) / 2
+        sx = x + w / 2 - (size[0] / Pango.SCALE) / 2
         sy = y + 200
-        pango_cr.move_to(sx, sy)
-        pango_cr.show_layout(pango_layout)
-        pango_cr.stroke()
-
+        cr.move_to(sx, sy)
+        PangoCairo.update_layout(cr, pango_layout)
+        PangoCairo.show_layout(cr, pango_layout)
 
     def finish_game(self):
         self.finished = True
@@ -323,17 +328,19 @@ class BalloonGame(gtk.VBox):
         cr.fill()
         cr.restore()
 
-        pango_cr = pangocairo.CairoContext(cr)
-        pango_cr.set_source_rgb(0, 0, 0)
-        pango_layout = cr.create_layout()
-        pango_layout.set_font_description(pango.FontDescription('Sans 12'))
-        pango_layout.set_text(unicode(b.word))
+        cr.set_source_rgb(0, 0, 0)
+
+        pango_layout = PangoCairo.create_layout(cr)
+        fd = Pango.FontDescription('Sans')
+        fd.set_size(12 * Pango.SCALE)
+        pango_layout.set_font_description(fd)
+        pango_layout.set_text(b.word, len(b.word))
         size = pango_layout.get_size()
-        x = x - (size[0] / pango.SCALE) / 2
-        y = y - (size[1] / pango.SCALE) / 2
-        pango_cr.move_to(x, y)
-        pango_cr.show_layout(pango_layout)
-        pango_cr.stroke()
+        x = x - (size[0] / Pango.SCALE) / 2
+        y = y - (size[1] / Pango.SCALE) / 2
+        cr.move_to(x, y)
+        PangoCairo.update_layout(cr, pango_layout)
+        PangoCairo.show_layout(cr, pango_layout)
 
     def add_score(self, num):
         self.score += num
@@ -341,44 +348,45 @@ class BalloonGame(gtk.VBox):
 
     def queue_draw_score(self):
         layout = self.area.create_pango_layout(_('SCORE: %d') % self.score)
-        layout.set_font_description(pango.FontDescription('Times 14'))    
+        layout.set_font_description(Pango.FontDescription('Times 14'))
         size = layout.get_size()
-        x = self.bounds.width-20-size[0]/pango.SCALE
+        x = self.bounds.width-20-size[0]/Pango.SCALE
         y = 20
         self.queue_draw_area(x, y, x+size[0], y+size[1])
 
     def draw_score(self, cr):
-        pango_cr = pangocairo.CairoContext(cr)
-        pango_cr.set_source_rgb(0, 0, 0)
-        pango_layout = cr.create_layout()
-        pango_layout.set_font_description(pango.FontDescription('Times 14'))
-        pango_layout.set_text(_('SCORE: %d') % self.score)
+        cr.set_source_rgb(0, 0, 0)
+        pango_layout = PangoCairo.create_layout(cr)
+        fd = Pango.FontDescription('Times')
+        fd.set_size(14 * Pango.SCALE)
+        pango_layout.set_font_description(fd)
+        text = _('SCORE: %d') % self.score
+        pango_layout.set_text(text, len(text))
+
         size = pango_layout.get_size()
-        x = self.bounds.width - 20 - size[0] / pango.SCALE
+        x = self.bounds.width - 20 - size[0] / Pango.SCALE
         y = 20
-        pango_cr.move_to(x, y)
-        pango_cr.show_layout(pango_layout)
-        pango_cr.stroke()
+        cr.move_to(x, y)
+        PangoCairo.update_layout(cr, pango_layout)
+        PangoCairo.show_layout(cr, pango_layout)
 
     def draw_instructions(self, cr):
         # Draw instructions.
-        pango_cr = pangocairo.CairoContext(cr)
-        pango_cr.set_source_rgb(0, 0, 0)
-        pango_layout = cr.create_layout()
-        pango_layout.set_font_description(pango.FontDescription('Times 14'))
-        pango_layout.set_text(_('Type the words to pop the balloons!'))
+        cr.set_source_rgb(0, 0, 0)
+        pango_layout = PangoCairo.create_layout(cr)
+        pango_layout.set_font_description(Pango.FontDescription('Times 14'))
+        text = _('Type the words to pop the balloons!')
+        pango_layout.set_text(text, len(text))
         size = pango_layout.get_size()
-        x = (self.bounds.width - size[0] / pango.SCALE) / 2
-        y = self.bounds.height - 20 - size[1] / pango.SCALE
-        pango_cr.move_to(x, y)
-        pango_cr.show_layout(pango_layout)
-        pango_cr.stroke()
+        x = (self.bounds.width - size[0] / Pango.SCALE) / 2
+        y = self.bounds.height - 20 - size[1] / Pango.SCALE
+        cr.move_to(x, y)
+        PangoCairo.update_layout(cr, pango_layout)
+        PangoCairo.show_layout(cr, pango_layout)
 
-    def draw(self):
+    def draw(self, cr):
         self.bounds = self.area.get_allocation()
 
-        cr = self.area.window.cairo_create()
-
         # Draw background.
         cr.set_source_rgb(0.915, 0.915, 1)
         cr.rectangle(0, 0, self.bounds.width, self.bounds.height)
@@ -390,11 +398,10 @@ class BalloonGame(gtk.VBox):
 
         if self.finished:
             self.draw_results(cr)
-
         else:
             self.draw_instructions(cr)
 
             self.draw_score(cr)
 
-    def expose_cb(self, area, event):
-        self.draw()
+    def draw_cb(self, area, cr):
+        self.draw(cr)
diff --git a/editlessonlistscreen.py b/editlessonlistscreen.py
index af67020..6ac2c34 100644
--- a/editlessonlistscreen.py
+++ b/editlessonlistscreen.py
@@ -22,42 +22,42 @@ from gettext import gettext as _
 from port import json
 from port import chooser
 
-# Import PyGTK.
-import gobject, pygtk, gtk, pango
+from gi.repository import Gtk
+from gi.repository import GObject
 
 # Import Sugar UI modules.
-import sugar.activity.activity
-import sugar.graphics.style
-import sugar.graphics.alert
-import sugar.mime
-import sugar.datastore.datastore
+import sugar3.activity.activity
+import sugar3.graphics.style
+import sugar3.graphics.alert
+import sugar3.mime
+import sugar3.datastore.datastore
 
 # Import activity modules.
 import editlessonscreen
 
-class EditLessonListScreen(gtk.VBox):
+class EditLessonListScreen(Gtk.VBox):
     def __init__(self, activity, lessons):
-        gtk.VBox.__init__(self)
+        GObject.GObject.__init__(self)
 
         self.activity = activity
         self.lessons = lessons
 
         # Add the header.
-        title = gtk.Label()
+        title = Gtk.Label()
         title.set_markup("<span size='20000'><b>" + _("Edit Lessons") + "</b></span>")
         title.set_alignment(1.0, 0.0)
         
-        stoplabel = gtk.Label(_('Go Back'))
-        stopbtn = gtk.Button()
+        stoplabel = Gtk.Label(label=_('Go Back'))
+        stopbtn = Gtk.Button()
         stopbtn.add(stoplabel)
         stopbtn.connect('clicked', self.stop_clicked_cb)
        
-        titlebox = gtk.HBox()
+        titlebox = Gtk.HBox()
         titlebox.pack_start(stopbtn, False, False, 10)
         titlebox.pack_end(title, False, False, 10)
 
         # Add the lesson list.
-        self.treeview = gtk.TreeView()
+        self.treeview = Gtk.TreeView()
         self.treeview.set_rules_hint(True)
         self.treeview.set_enable_search(False)
 
@@ -66,73 +66,73 @@ class EditLessonListScreen(gtk.VBox):
 
         # Note that the only thing we store in our liststore is the lesson id.
         # All the actual data is in the lessons list.
-        self.liststore = gtk.ListStore(gobject.TYPE_INT)
+        self.liststore = Gtk.ListStore(GObject.TYPE_INT)
         self.treeview.set_model(self.liststore)
 
         # Construct the columns.
-        renderer = gtk.CellRendererText()
-        col = gtk.TreeViewColumn(_('Name'), renderer)
+        renderer = Gtk.CellRendererText()
+        col = Gtk.TreeViewColumn(_('Name'), renderer)
         col.set_cell_data_func(renderer, self.name_render_cb) 
         self.treeview.append_column(col)
 
-        renderer = gtk.CellRendererText()
-        col = gtk.TreeViewColumn(_('Description'), renderer)
+        renderer = Gtk.CellRendererText()
+        col = Gtk.TreeViewColumn(_('Description'), renderer)
         col.set_cell_data_func(renderer, self.description_render_cb) 
         col.set_expand(True)
         self.treeview.append_column(col)
 
-        renderer = gtk.CellRendererText()
-        col = gtk.TreeViewColumn(_('Type'), renderer)
+        renderer = Gtk.CellRendererText()
+        col = Gtk.TreeViewColumn(_('Type'), renderer)
         col.set_cell_data_func(renderer, self.type_render_cb) 
         col.set_expand(False)
         self.treeview.append_column(col)
 
-        scroll = gtk.ScrolledWindow()
-        scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+        scroll = Gtk.ScrolledWindow()
+        scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
         scroll.add(self.treeview)
 
-        importlabel = gtk.Label(_('Import Lessons from Journal'))
-        self.importbtn = gtk.Button()
+        importlabel = Gtk.Label(label=_('Import Lessons from Journal'))
+        self.importbtn = Gtk.Button()
         self.importbtn.add(importlabel)
         self.importbtn.connect('clicked', self.import_clicked_cb)
         
-        exportlabel = gtk.Label(_('Export Lessons to Journal'))
-        self.exportbtn = gtk.Button()
+        exportlabel = Gtk.Label(label=_('Export Lessons to Journal'))
+        self.exportbtn = Gtk.Button()
         self.exportbtn.add(exportlabel)
         self.exportbtn.connect('clicked', self.export_clicked_cb)
         
-        exportlabel = gtk.Label(_('Save Lessons to Activity'))
-        self.defaultsbtn = gtk.Button()
+        exportlabel = Gtk.Label(label=_('Save Lessons to Activity'))
+        self.defaultsbtn = Gtk.Button()
         self.defaultsbtn.add(exportlabel)
         self.defaultsbtn.connect('clicked', self.set_default_clicked_cb)
         
-        self.addbtn = gtk.Button()
-        self.addbtn.add(sugar.graphics.icon.Icon(icon_name='list-add'))
+        self.addbtn = Gtk.Button()
+        self.addbtn.add(sugar3.graphics.icon.Icon(icon_name='list-add'))
         self.addbtn.connect('clicked', self.add_lesson_clicked_cb)
-        self.delbtn = gtk.Button()
-        self.delbtn.add(sugar.graphics.icon.Icon(icon_name='list-remove'))
+        self.delbtn = Gtk.Button()
+        self.delbtn.add(sugar3.graphics.icon.Icon(icon_name='list-remove'))
         self.delbtn.connect('clicked', self.del_lesson_clicked_cb)
         self.delbtn.set_sensitive(False)
-        self.moveupbtn = gtk.Button()
-        self.moveupbtn.add(sugar.graphics.icon.Icon(icon_name='go-up'))
+        self.moveupbtn = Gtk.Button()
+        self.moveupbtn.add(sugar3.graphics.icon.Icon(icon_name='go-up'))
         self.moveupbtn.connect('clicked', self.move_lesson_up_clicked_cb)
         self.moveupbtn.set_sensitive(False)
-        self.movedownbtn = gtk.Button()
-        self.movedownbtn.add(sugar.graphics.icon.Icon(icon_name='go-down'))
+        self.movedownbtn = Gtk.Button()
+        self.movedownbtn.add(sugar3.graphics.icon.Icon(icon_name='go-down'))
         self.movedownbtn.connect('clicked', self.move_lesson_down_clicked_cb)
         self.movedownbtn.set_sensitive(False)
 
-        btnbox = gtk.HBox()
+        btnbox = Gtk.HBox()
         btnbox.pack_start(self.importbtn, False, False, 10)
-        btnbox.pack_start(self.exportbtn, False, False)
+        btnbox.pack_start(self.exportbtn, False, False, 0)
         btnbox.pack_start(self.defaultsbtn, False, False, 10)
-        btnbox.pack_end(self.addbtn, False, False)
-        btnbox.pack_end(self.delbtn, False, False)
-        btnbox.pack_end(self.moveupbtn, False, False)
-        btnbox.pack_end(self.movedownbtn, False, False)
+        btnbox.pack_end(self.addbtn, False, False, 0)
+        btnbox.pack_end(self.delbtn, False, False, 0)
+        btnbox.pack_end(self.moveupbtn, False, False, 0)
+        btnbox.pack_end(self.movedownbtn, False, False, 0)
 
         self.pack_start(titlebox, False, False, 10)
-        self.pack_start(gtk.HSeparator(), False, False, 0)
+        self.pack_start(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL), False, False, 0)
         self.pack_start(scroll, True, True, 10)
         self.pack_start(btnbox, False, False, 10)
 
@@ -197,13 +197,13 @@ class EditLessonListScreen(gtk.VBox):
         if len(self.lessons) > 1:
             path = self.treeview.get_cursor()[0]
             if path:
-                msg = sugar.graphics.alert.ConfirmationAlert()
+                msg = sugar3.graphics.alert.ConfirmationAlert()
                 msg.props.title = _('Delete Lesson?')
                 msg.props.msg = _('Deleting the lesson will erase the lesson content.')
         
                 def alert_response_cb(alert, response_id, self, id):
                     self.activity.remove_alert(alert)
-                    if response_id is gtk.RESPONSE_OK:
+                    if response_id is Gtk.ResponseType.OK:
                         self.lessons.pop(id)
                         del self.liststore[id]
                         self.treeview.get_selection().select_path(id)
@@ -294,7 +294,7 @@ class EditLessonListScreen(gtk.VBox):
     
     def export_clicked_cb(self, btn):
         # Create the new journal entry
-        fileObject = sugar.datastore.datastore.create()
+        fileObject = sugar3.datastore.datastore.create()
 
         meta = self.activity.metadata
         fileObject.metadata['title'] = meta['title'] + _(' (Exported Lessons)')
@@ -312,13 +312,13 @@ class EditLessonListScreen(gtk.VBox):
         finally:
             fd.close()
         
-        sugar.datastore.datastore.write(fileObject, transfer_ownership=True)
+        sugar3.datastore.datastore.write(fileObject, transfer_ownership=True)
         fileObject.destroy()
         del fileObject
 
     def set_default_clicked_cb(self, btn):
         code = locale.getdefaultlocale()[0] or 'en_US'
-        path = sugar.activity.activity.get_bundle_path() + '/lessons/%s.lessons' % code
+        path = sugar3.activity.activity.get_bundle_path() + '/lessons/%s.lessons' % code
         
         fd = open(path, 'w')
         
@@ -328,4 +328,4 @@ class EditLessonListScreen(gtk.VBox):
             
         finally:
             fd.close()
-            
\ No newline at end of file
+            
diff --git a/editlessonscreen.py b/editlessonscreen.py
index 4c7ef0b..e5ce0b4 100644
--- a/editlessonscreen.py
+++ b/editlessonscreen.py
@@ -20,20 +20,21 @@
 import logging, os, math, time, copy, locale, datetime, random, re
 from gettext import gettext as _
 
-# Import PyGTK.
-import gobject, pygtk, gtk, pango
+from gi.repository import Gtk
+from gi.repository import GObject
+from gi.repository import Pango
 
 # Import Sugar UI modules.
-import sugar.activity.activity
-import sugar.graphics.style
-import sugar.graphics.icon
+import sugar3.activity.activity
+import sugar3.graphics.style
+import sugar3.graphics.icon
 
 # Import lessonbuilder functions.
 import lessonbuilder
 
-class EditLessonScreen(gtk.VBox):
+class EditLessonScreen(Gtk.VBox):
     def __init__(self, activity, lesson):
-        gtk.VBox.__init__(self)
+        GObject.GObject.__init__(self)
         self.set_border_width(10)
 
         self.activity = activity
@@ -42,27 +43,27 @@ class EditLessonScreen(gtk.VBox):
         self.in_build = False
         
         # Add the header.
-        title = gtk.Label()
+        title = Gtk.Label()
         title.set_markup("<span size='20000'><b>" + _("Edit a Lesson") + "</b></span>")
         title.set_alignment(1.0, 0.0)
         
-        stoplabel = gtk.Label(_('Go Back'))
-        stopbtn = gtk.Button()
+        stoplabel = Gtk.Label(label=_('Go Back'))
+        stopbtn = Gtk.Button()
         stopbtn.add(stoplabel)
         stopbtn.connect('clicked', self.stop_clicked_cb)
                
-        titlebox = gtk.HBox()
+        titlebox = Gtk.HBox()
         titlebox.pack_start(stopbtn, False, False, 10)
         titlebox.pack_end(title, False, False, 10)
 
-        self.vp = gtk.Viewport()
+        self.vp = Gtk.Viewport()
 
-        self.scroll = gtk.ScrolledWindow()
-        self.scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+        self.scroll = Gtk.ScrolledWindow()
+        self.scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
         self.scroll.add(self.vp)
 
         self.pack_start(titlebox, False, False, 10)
-        self.pack_start(gtk.HSeparator(), False, False, 0)
+        self.pack_start(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL), False, False, 0)
         self.pack_start(self.scroll, True, True, 0)
 
         self.build()
@@ -70,62 +71,62 @@ class EditLessonScreen(gtk.VBox):
         self.show_all()
 
     def build_generate(self):
-        generatebox = gtk.VBox()
+        generatebox = Gtk.VBox()
         generatebox.set_spacing(5)
 
-        newlabel = gtk.Label(_('New keys'))       
-        knownlabel = gtk.Label(_('Known keys'))
-        lengthlabel = gtk.Label(_('Length'))       
+        newlabel = Gtk.Label(label=_('New keys'))
+        knownlabel = Gtk.Label(label=_('Known keys'))
+        lengthlabel = Gtk.Label(label=_('Length'))
         
-        generatebox.newkeysent = gtk.Entry()
+        generatebox.newkeysent = Gtk.Entry()
         generatebox.newkeysent.set_width_chars(8)
-        generatebox.knownkeysent = gtk.Entry()
+        generatebox.knownkeysent = Gtk.Entry()
         generatebox.knownkeysent.set_width_chars(15)
-        generatebox.lengthent = gtk.Entry()
+        generatebox.lengthent = Gtk.Entry()
         generatebox.lengthent.set_width_chars(5)
         generatebox.lengthent.set_text('60')
         
-        oklabel = gtk.Label()
+        oklabel = Gtk.Label()
         oklabel.set_markup(_('Generate!'))
-        okbtn = gtk.Button()
+        okbtn = Gtk.Button()
         okbtn.add(oklabel)
         okbtn.connect('clicked', self.generate_ok_clicked_cb, generatebox)
         okbtn.set_alignment(0.5, 0.5)
 
-        box = gtk.HBox()
+        box = Gtk.HBox()
         box.set_spacing(10)
-        box.pack_start(newlabel, expand=False)
-        box.pack_start(generatebox.newkeysent, expand=False)
-        box.pack_start(knownlabel, expand=False)
-        box.pack_start(generatebox.knownkeysent, expand=False)
-        box.pack_start(lengthlabel, expand=False)
-        box.pack_start(generatebox.lengthent, expand=False)
-        box.pack_end(okbtn, expand=False)
+        box.pack_start(newlabel, False, True, 0)
+        box.pack_start(generatebox.newkeysent, False, True, 0)
+        box.pack_start(knownlabel, False, True, 0)
+        box.pack_start(generatebox.knownkeysent, False, True, 0)
+        box.pack_start(lengthlabel, False, True, 0)
+        box.pack_start(generatebox.lengthent, False, True, 0)
+        box.pack_end(okbtn, False, True, 0)
         box.show_all()
         
-        wordslabel = gtk.Label()
+        wordslabel = Gtk.Label()
         wordslabel.set_markup(_('Edit Word List'))
-        wordsbtn = gtk.Button()
+        wordsbtn = Gtk.Button()
         wordsbtn.add(wordslabel)
         wordsbtn.connect('clicked', self.generate_words_clicked_cb)
         wordsbtn.set_alignment(0.5, 0.5)
 
-        generatebox.pack_start(box)
-        generatebox.pack_start(wordsbtn, expand=False, fill=False)               
+        generatebox.pack_start(box, True, True, 0)
+        generatebox.pack_start(wordsbtn, expand=False, fill=False, padding=0)
         
         return generatebox
 
     def build_step(self, step, idx):
-        stepbox = gtk.VBox()
+        stepbox = Gtk.VBox()
         stepbox.set_spacing(5)
 
-        steplabel = gtk.Label()
+        steplabel = Gtk.Label()
         steplabel.set_markup("<span size='x-large' weight='bold'>" + (_('Step #%d') % (idx+1)) + "</span>")
         steplabel.set_alignment(0.0, 0.5)
         steplabel.set_padding(10, 0)
 
         # Build the step type combo box.
-        stepbox.typecombo = gtk.combo_box_new_text()
+        stepbox.typecombo = Gtk.ComboBoxText()
         stepbox.typecombo.append_text(_('Keys'))
         stepbox.typecombo.append_text(_('Words'))
 
@@ -136,17 +137,17 @@ class EditLessonScreen(gtk.VBox):
             stepbox.typecombo.set_active(1)
         
         # Build the tool buttons.
-        delstepbtn = gtk.Button()
-        delstepbtn.add(sugar.graphics.icon.Icon(icon_name='list-remove'))
+        delstepbtn = Gtk.Button()
+        delstepbtn.add(sugar3.graphics.icon.Icon(icon_name='list-remove'))
         delstepbtn.connect('clicked', self.del_step_clicked_cb, idx)
-        addstepbtn = gtk.Button()
-        addstepbtn.add(sugar.graphics.icon.Icon(icon_name='list-add'))
+        addstepbtn = Gtk.Button()
+        addstepbtn.add(sugar3.graphics.icon.Icon(icon_name='list-add'))
         addstepbtn.connect('clicked', self.add_step_clicked_cb, idx)
-        moveupbtn = gtk.Button()
-        moveupbtn.add(sugar.graphics.icon.Icon(icon_name='go-up'))
+        moveupbtn = Gtk.Button()
+        moveupbtn.add(sugar3.graphics.icon.Icon(icon_name='go-up'))
         moveupbtn.connect('clicked', self.move_step_up_clicked_cb, idx)
-        movedownbtn = gtk.Button()
-        movedownbtn.add(sugar.graphics.icon.Icon(icon_name='go-down'))
+        movedownbtn = Gtk.Button()
+        movedownbtn.add(sugar3.graphics.icon.Icon(icon_name='go-down'))
         movedownbtn.connect('clicked', self.move_step_down_clicked_cb, idx)
 
         if idx == 0:
@@ -154,203 +155,203 @@ class EditLessonScreen(gtk.VBox):
         if idx == len(self.lesson['steps']) - 1:
             movedownbtn.set_sensitive(False)
 
-        btnbox = gtk.HBox()
-        btnbox.pack_start(steplabel, False, False)
+        btnbox = Gtk.HBox()
+        btnbox.pack_start(steplabel, False, False, 0)
         btnbox.pack_start(stepbox.typecombo, expand=False, padding=10)
-        btnbox.pack_end(addstepbtn, False, False)
-        btnbox.pack_end(delstepbtn, False, False)
-        btnbox.pack_end(moveupbtn, False, False)
-        btnbox.pack_end(movedownbtn, False, False)
+        btnbox.pack_end(addstepbtn, False, False, 0)
+        btnbox.pack_end(delstepbtn, False, False, 0)
+        btnbox.pack_end(moveupbtn, False, False, 0)
+        btnbox.pack_end(movedownbtn, False, False, 0)
 
         # Build the instructions entry.
-        instlabel = gtk.Label()
+        instlabel = Gtk.Label()
         instlabel.set_markup("<span size='large' weight='bold'>" + _('Instructions') + "</span>")
         instlabel.set_alignment(0.0, 0.5)
         instlabel.set_padding(20, 0)
 
         self.labelsizegroup.add_widget(instlabel)
 
-        stepbox.insttext = gtk.TextView(gtk.TextBuffer())
-        stepbox.insttext.props.wrap_mode = gtk.WRAP_WORD
-        stepbox.insttext.modify_font(pango.FontDescription('Monospace'))
-        instscroll = gtk.ScrolledWindow()
-        instscroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+        stepbox.insttext = Gtk.TextView(Gtk.TextBuffer())
+        stepbox.insttext.props.wrap_mode = Gtk.WrapMode.WORD
+        stepbox.insttext.modify_font(Pango.FontDescription('Monospace'))
+        instscroll = Gtk.ScrolledWindow()
+        instscroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
         instscroll.add(stepbox.insttext)
         instscroll.set_size_request(-1, 75)
         stepbox.insttext.get_buffer().set_text(step['instructions'])
 
-        instbox = gtk.HBox()
-        instbox.pack_start(instlabel, False, False)
-        instbox.pack_start(instscroll, True, True)
+        instbox = Gtk.HBox()
+        instbox.pack_start(instlabel, False, False, 0)
+        instbox.pack_start(instscroll, True, True, 0)
 
         # Build the text entry.
-        textlabel = gtk.Label()
+        textlabel = Gtk.Label()
         textlabel.set_markup("<span size='large' weight='bold'>" + _('Text') + "</span>")
         textlabel.set_alignment(0.0, 0.5)
         textlabel.set_padding(20, 0)
 
         self.labelsizegroup.add_widget(textlabel)
 
-        stepbox.texttext = gtk.TextView(gtk.TextBuffer())
-        stepbox.texttext.props.wrap_mode = gtk.WRAP_WORD
-        stepbox.texttext.modify_font(pango.FontDescription('monospace'))
-        textscroll = gtk.ScrolledWindow()
-        textscroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+        stepbox.texttext = Gtk.TextView(Gtk.TextBuffer())
+        stepbox.texttext.props.wrap_mode = Gtk.WrapMode.WORD
+        stepbox.texttext.modify_font(Pango.FontDescription('monospace'))
+        textscroll = Gtk.ScrolledWindow()
+        textscroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
         textscroll.add(stepbox.texttext)
         textscroll.set_size_request(-1, 100)
         stepbox.texttext.get_buffer().set_text(step['text'])
 
-        textbox = gtk.HBox()
-        textbox.pack_start(textlabel, expand=False)
-        textbox.pack_start(textscroll)
+        textbox = Gtk.HBox()
+        textbox.pack_start(textlabel, False, True, 0)
+        textbox.pack_start(textscroll, True, True, 0)
 
-        sizegroup = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)   
+        sizegroup = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL)
         sizegroup.add_widget(instlabel)
         sizegroup.add_widget(textlabel)    
 
-        stepbox.pack_start(btnbox, expand=False)
-        stepbox.pack_start(instbox, expand=False)
-        stepbox.pack_start(textbox, expand=False)
+        stepbox.pack_start(btnbox, False, True, 0)
+        stepbox.pack_start(instbox, False, True, 0)
+        stepbox.pack_start(textbox, False, True, 0)
         
         return stepbox
 
     def build_medal(self, medal, name):
-        box = gtk.HBox()
+        box = Gtk.HBox()
 
-        label = gtk.Label()
+        label = Gtk.Label()
         label.set_markup("<span size='large' weight='bold'>" + name + "</span>")
         label.set_alignment(0.0, 0.5)
         label.set_padding(20, 0)
 
         self.labelsizegroup.add_widget(label)
         
-        box.pack_start(label, False, False)
+        box.pack_start(label, False, False, 0)
 
         if self.lesson['type'] == 'normal':
-            acclabel = gtk.Label(_('Accuracy'))       
-            wpmlabel = gtk.Label(_('WPM'))
+            acclabel = Gtk.Label(label=_('Accuracy'))
+            wpmlabel = Gtk.Label(label=_('WPM'))
             
-            box.accent = gtk.Entry()
-            box.wpment = gtk.Entry()
+            box.accent = Gtk.Entry()
+            box.wpment = Gtk.Entry()
 
             box.accent.set_text(str(medal['accuracy']))
             box.wpment.set_text(str(medal['wpm']))
         
             box.pack_start(acclabel, False, False, 10)
-            box.pack_start(box.accent, False, False)
+            box.pack_start(box.accent, False, False, 0)
             box.pack_start(wpmlabel, False, False, 10)
-            box.pack_start(box.wpment, False, False)
+            box.pack_start(box.wpment, False, False, 0)
         
         elif self.lesson['type'] == 'balloon':
-            scorelabel = gtk.Label(_('Score'))
+            scorelabel = Gtk.Label(label=_('Score'))
             
-            box.scoreent = gtk.Entry()
+            box.scoreent = Gtk.Entry()
             box.scoreent.set_text(str(medal['score']))
         
             box.pack_start(scorelabel, False, False, 10)
-            box.pack_start(box.scoreent, False, False)
+            box.pack_start(box.scoreent, False, False, 0)
             
         return box
       
     def build(self):
         self.in_build = True
         
-        self.vbox = gtk.VBox()
+        self.vbox = Gtk.VBox()
         self.vbox.set_border_width(20)
         self.vbox.set_spacing(5)
         
-        self.labelsizegroup = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)   
+        self.labelsizegroup = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL)
 
         # Lesson details widgets.
-        detailslabel = gtk.Label()
+        detailslabel = Gtk.Label()
         detailslabel.set_markup("<span size='x-large'><b>" + _('Lesson Details') + "</b></span>")
         detailslabel.set_alignment(0.0, 0.5)
         detailslabel.set_padding(10, 0)
 
-        namelabel = gtk.Label()
+        namelabel = Gtk.Label()
         namelabel.set_markup("<span size='large' weight='bold'>" + _('Name') + "</span>")
         namelabel.set_alignment(0.0, 0.5)
         namelabel.set_padding(20, 0)
 
-        self.nameent = gtk.Entry()
+        self.nameent = Gtk.Entry()
         self.nameent.set_text(self.lesson['name'])
 
-        namebox = gtk.HBox()
-        namebox.pack_start(namelabel, expand=False)
-        namebox.pack_start(self.nameent)
+        namebox = Gtk.HBox()
+        namebox.pack_start(namelabel, False, True, 0)
+        namebox.pack_start(self.nameent, True, True, 0)
         
-        typelabel = gtk.Label()
+        typelabel = Gtk.Label()
         typelabel.set_markup("<span size='large' weight='bold'>" + _('Type') + "</span>")
         typelabel.set_alignment(0.0, 0.5)
         typelabel.set_padding(20, 0)
 
-        self.textradio = gtk.RadioButton(None, _('Normal Lesson'))
+        self.textradio = Gtk.RadioButton(None, _('Normal Lesson'))
         self.textradio.connect('toggled', self.type_toggled_cb)
         
-        self.balloonradio = gtk.RadioButton(self.textradio, _('Balloon Game'))
+        self.balloonradio = Gtk.RadioButton(self.textradio, _('Balloon Game'))
         self.balloonradio.connect('toggled', self.type_toggled_cb)
         
         self.textradio.set_active(self.lesson['type'] == 'normal')
         self.balloonradio.set_active(self.lesson['type'] == 'balloon')        
 
-        typebox = gtk.HBox()
-        typebox.pack_start(typelabel, expand=False)
-        typebox.pack_start(self.textradio, expand=False)
-        typebox.pack_start(self.balloonradio, expand=False)
+        typebox = Gtk.HBox()
+        typebox.pack_start(typelabel, False, True, 0)
+        typebox.pack_start(self.textradio, False, True, 0)
+        typebox.pack_start(self.balloonradio, False, True, 0)
         
-        desclabel = gtk.Label()
+        desclabel = Gtk.Label()
         desclabel.set_markup("<span size='large' weight='bold'>" + _('Description') + "</span>")
         desclabel.set_alignment(0.0, 0.5)
         desclabel.set_padding(20, 0)
 
-        self.desctext = gtk.TextView(gtk.TextBuffer())
-        self.desctext.props.wrap_mode = gtk.WRAP_WORD
-        descscroll = gtk.ScrolledWindow()
-        descscroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+        self.desctext = Gtk.TextView(Gtk.TextBuffer())
+        self.desctext.props.wrap_mode = Gtk.WrapMode.WORD
+        descscroll = Gtk.ScrolledWindow()
+        descscroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
         descscroll.add(self.desctext)
         descscroll.set_size_request(-1, 75)
         self.desctext.get_buffer().set_text(self.lesson['description'])
 
-        descbox = gtk.HBox()
-        descbox.pack_start(desclabel, expand=False)
-        descbox.pack_start(descscroll)
+        descbox = Gtk.HBox()
+        descbox.pack_start(desclabel, False, True, 0)
+        descbox.pack_start(descscroll, True, True, 0)
 
         # Build the options.
-        optslabel = gtk.Label()
+        optslabel = Gtk.Label()
         optslabel.set_markup("<span size='large' weight='bold'>" + _('Options') + "</span>")
         optslabel.set_alignment(0.0, 0.5)
         optslabel.set_padding(20, 0)
 
-        self.mistakescheck = gtk.CheckButton(_('Allow Mistakes'))
+        self.mistakescheck = Gtk.CheckButton(_('Allow Mistakes'))
         self.mistakescheck.set_active(self.lesson.get('options', {}).get('mistakes', True))
-        self.backspacecheck = gtk.CheckButton(_('Allow Backspace'))
+        self.backspacecheck = Gtk.CheckButton(_('Allow Backspace'))
         self.backspacecheck.set_active(self.lesson.get('options', {}).get('backspace', True))
 
-        optsbox = gtk.HBox()
-        optsbox.pack_start(optslabel, expand=False)
-        optsbox.pack_start(self.backspacecheck, expand=False)
-        optsbox.pack_start(self.mistakescheck, expand=False)
+        optsbox = Gtk.HBox()
+        optsbox.pack_start(optslabel, False, True, 0)
+        optsbox.pack_start(self.backspacecheck, False, True, 0)
+        optsbox.pack_start(self.mistakescheck, False, True, 0)
             
         self.labelsizegroup.add_widget(namelabel)
         self.labelsizegroup.add_widget(typelabel)    
         self.labelsizegroup.add_widget(desclabel)    
         self.labelsizegroup.add_widget(optslabel)    
   
-        self.vbox.pack_start(detailslabel, expand=False)        
-        self.vbox.pack_start(namebox, expand=False)
-        self.vbox.pack_start(typebox, expand=False)
-        self.vbox.pack_start(descbox, expand=False)
-        self.vbox.pack_start(optsbox, expand=False)
+        self.vbox.pack_start(detailslabel, False, True, 0)
+        self.vbox.pack_start(namebox, False, True, 0)
+        self.vbox.pack_start(typebox, False, True, 0)
+        self.vbox.pack_start(descbox, False, True, 0)
+        self.vbox.pack_start(optsbox, False, True, 0)
 
         # Build the generator.
-        generatelabel = gtk.Label()
+        generatelabel = Gtk.Label()
         generatelabel.set_markup("<span size='x-large'><b>" + _('Automatic Lesson Generator') + "</b></span>")
         generatelabel.set_alignment(0.0, 0.5)
         generatelabel.set_padding(10, 0)
 
         generatebox = self.build_generate()
         self.vbox.pack_start(generatelabel, expand=False, padding=10)      
-        self.vbox.pack_start(generatebox, expand=False)       
+        self.vbox.pack_start(generatebox, False, True, 0)
         
         self.has_normal_widgets = False
         self.has_balloon_widgets = False
@@ -369,7 +370,7 @@ class EditLessonScreen(gtk.VBox):
                 stepbox = self.build_step(step, len(self.stepboxes))
                 self.stepboxes.append(stepbox)
                 
-                self.vbox.pack_start(stepbox, expand=False)
+                self.vbox.pack_start(stepbox, False, True, 0)
                 
         if self.lesson['type'] == 'balloon':
             self.has_balloon_widgets = True
@@ -377,30 +378,30 @@ class EditLessonScreen(gtk.VBox):
             if not self.lesson.has_key('words') or len(self.lesson['words']) == 0:
                 self.lesson['words'] = []
             
-            textlabel = gtk.Label()
+            textlabel = Gtk.Label()
             textlabel.set_markup("<span size='large' weight='bold'>" + _('Words') + "</span>")
             textlabel.set_alignment(0.0, 0.5)
             textlabel.set_padding(20, 0)
 
             self.labelsizegroup.add_widget(textlabel)
 
-            self.wordstext = gtk.TextView(gtk.TextBuffer())
-            self.wordstext.props.wrap_mode = gtk.WRAP_WORD
-            self.wordstext.modify_font(pango.FontDescription('Monospace'))
-            textscroll = gtk.ScrolledWindow()
-            textscroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+            self.wordstext = Gtk.TextView(Gtk.TextBuffer())
+            self.wordstext.props.wrap_mode = Gtk.WrapMode.WORD
+            self.wordstext.modify_font(Pango.FontDescription('Monospace'))
+            textscroll = Gtk.ScrolledWindow()
+            textscroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
             textscroll.add(self.wordstext)
             textscroll.set_size_request(-1, 200)
             self.wordstext.get_buffer().set_text(' '.join(self.lesson['words']))
     
-            textbox = gtk.HBox()
-            textbox.pack_start(textlabel, expand=False)
-            textbox.pack_start(textscroll)
+            textbox = Gtk.HBox()
+            textbox.pack_start(textlabel, False, True, 0)
+            textbox.pack_start(textscroll, True, True, 0)
             
-            self.vbox.pack_start(textbox, expand=False)
+            self.vbox.pack_start(textbox, False, True, 0)
 
         # Medal requirements widgets.
-        medalslabel = gtk.Label()
+        medalslabel = Gtk.Label()
         medalslabel.set_markup("<span size='x-large'><b>" + _('Medal Requirements') + "</b></span>")
         medalslabel.set_alignment(0.0, 0.5)
         medalslabel.set_padding(10, 0)
@@ -412,9 +413,9 @@ class EditLessonScreen(gtk.VBox):
         self.medalboxes.append(self.build_medal(self.lesson['medals'][1], _('Silver')))
         self.medalboxes.append(self.build_medal(self.lesson['medals'][2], _('Gold')))
         
-        self.vbox.pack_start(self.medalboxes[0], expand=False)
-        self.vbox.pack_start(self.medalboxes[1], expand=False)
-        self.vbox.pack_start(self.medalboxes[2], expand=False)
+        self.vbox.pack_start(self.medalboxes[0], False, True, 0)
+        self.vbox.pack_start(self.medalboxes[1], False, True, 0)
+        self.vbox.pack_start(self.medalboxes[2], False, True, 0)
 
         self.vbox.show_all()
         
@@ -555,43 +556,43 @@ class EditLessonScreen(gtk.VBox):
     def generate_words_clicked_cb(self, btn):
         self.activity.push_screen(WordListScreen(self.activity))
 
-class WordListScreen(gtk.VBox):
+class WordListScreen(Gtk.VBox):
     def __init__(self, activity):
-        gtk.VBox.__init__(self)
+        GObject.GObject.__init__(self)
         self.set_border_width(10)
 
         self.activity = activity
         
         # Add the header.
-        title = gtk.Label()
+        title = Gtk.Label()
         title.set_markup("<span size='20000'><b>" + _("Edit Word List") + "</b></span>")
         title.set_alignment(1.0, 0.0)
         
-        stoplabel = gtk.Label(_('Go Back'))
-        stopbtn = gtk.Button()
+        stoplabel = Gtk.Label(label=_('Go Back'))
+        stopbtn = Gtk.Button()
         stopbtn.add(stoplabel)
         stopbtn.connect('clicked', self.stop_clicked_cb)
        
-        titlebox = gtk.HBox()
+        titlebox = Gtk.HBox()
         titlebox.pack_start(stopbtn, False, False, 10)
         titlebox.pack_end(title, False, False, 10)
 
-        subtitle = gtk.Label()
+        subtitle = Gtk.Label()
         subtitle.set_markup("<span size='10000'>" + _("Type or paste words here, for the Automatic Lesson Generator.  If empty, the dictionary will be used.") + "</span>")
         subtitle.set_alignment(1.0, 0.0)
 
-        self.wordlisttext = gtk.TextView(gtk.TextBuffer())
-        self.wordlisttext.props.wrap_mode = gtk.WRAP_WORD
-        wordlistscroll = gtk.ScrolledWindow()
-        wordlistscroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+        self.wordlisttext = Gtk.TextView(Gtk.TextBuffer())
+        self.wordlisttext.props.wrap_mode = Gtk.WrapMode.WORD
+        wordlistscroll = Gtk.ScrolledWindow()
+        wordlistscroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
         wordlistscroll.add(self.wordlisttext)
         wordlistscroll.set_size_request(-1, 75)
         self.wordlisttext.get_buffer().set_text(' '.join(self.activity.wordlist))
 
-        self.pack_start(titlebox, expand=False)
-        self.pack_start(subtitle, expand=False)
-        self.pack_start(gtk.HSeparator(), expand=False)
-        self.pack_start(wordlistscroll)
+        self.pack_start(titlebox, False, True, 0)
+        self.pack_start(subtitle, False, True, 0)
+        self.pack_start(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL), expand=False, padding=0)
+        self.pack_start(wordlistscroll, True, True, 0)
         
         self.show_all()
 
diff --git a/keyboard.py b/keyboard.py
index 25e870e..90cbf98 100644
--- a/keyboard.py
+++ b/keyboard.py
@@ -16,13 +16,17 @@
 #!/usr/bin/env python
 # vi:sw=4 et 
 
-import gtk
 import cairo
 import copy
-import rsvg
 import os, glob, re
-import pango
-import pangocairo
+
+from gi.repository import Gtk
+from gi.repository import Pango
+from gi.repository import PangoCairo
+from gi.repository import Gdk
+from gi.repository import GObject
+from gi.repository import GdkPixbuf
+
 import StringIO
 from port import json
 import subprocess
@@ -132,7 +136,8 @@ class KeyboardImages:
             scale_width = int(scale_width * 1.1625)
 
         for filename in glob.iglob('images/OLPC*.svg'):
-            image = rsvg.Handle(file=filename)
+            image = GdkPixbuf.Pixbuf.new_from_file_at_scale(
+                filename, scale_width, self.height, False)
             name = os.path.basename(filename)
             self.images[name] = image
 
@@ -145,7 +150,7 @@ class KeyboardData:
         self.letter_map = {}
         
         # Access the current GTK keymap.
-        self.keymap = gtk.gdk.keymap_get_default()
+        self.keymap = Gdk.Keymap.get_default()
 
     def set_layout(self, layout): 
         self._build_key_list(layout)
@@ -235,9 +240,9 @@ class KeyboardData:
 
     def format_key_sig(self, scan, state, group):
         sig = 'scan%d' % scan
-        if state & gtk.gdk.SHIFT_MASK:
+        if state & Gdk.ModifierType.SHIFT_MASK:
             sig += ' shift'
-        if state & gtk.gdk.MOD5_MASK:
+        if state & Gdk.ModifierType.MOD5_MASK:
             sig += ' altgr'
         if group != 0:
             sig += ' group%d' % group
@@ -250,9 +255,9 @@ class KeyboardData:
 
         state = 0
         if m.group('shift'):
-            state |= gtk.gdk.SHIFT_MASK
+            state |= Gdk.ModifierType.SHIFT_MASK
         if m.group('altgr'):
-            state |= gtk.gdk.MOD5_MASK
+            state |= Gdk.ModifierType.MOD5_MASK
 
         scan = int(m.group('scan'))
 
@@ -278,13 +283,13 @@ class KeyboardData:
         best_result = None
         
         for sig, l in self.letter_map.items():
-            if unicode(l) == unicode(letter):
+            if l == letter:
                 scan, state, group = self.parse_key_sig(sig)
                 
                 # Choose the key with the fewest modifiers.
                 score = 0
-                if state & gtk.gdk.SHIFT_MASK: score += 1
-                if state & gtk.gdk.MOD5_MASK: score += 1
+                if state & Gdk.ModifierType.SHIFT_MASK: score += 1
+                if state & Gdk.ModifierType.MOD5_MASK: score += 1
                 if score < best_score:
                     best_score = score
                     best_result = scan, state, group
@@ -295,19 +300,19 @@ class KeyboardData:
                     return k, best_result[1], best_result[2]
 
         # Try the GDK keymap.
-        keyval = gtk.gdk.unicode_to_keyval(ord(letter))
-        entries = self.keymap.get_entries_for_keyval(keyval)
+        keyval = Gdk.unicode_to_keyval(ord(letter))
+        valid, entries = self.keymap.get_entries_for_keyval(keyval)
         for e in entries:
             for k in self.keys:
-                if k['key-scan'] == e[0]:
+                if k['key-scan'] == e.keycode:
                     # TODO: Level -> state calculations are hardcoded to what the XO keyboard does.
                     # They were discovered through experimentation.
                     state = 0
-                    if e[2] & 1: 
-                        state |= gtk.gdk.SHIFT_MASK
-                    if e[2] & 2: 
-                        state |= gtk.gdk.MOD5_MASK
-                    return k, state, e[1]
+                    if e.level & 1:
+                        state |= Gdk.ModifierType.SHIFT_MASK
+                    if e.level & 2:
+                        state |= Gdk.ModifierType.MOD5_MASK
+                    return k, state, e.group
 
         # Fail!
         return None, None, None
@@ -317,19 +322,21 @@ class KeyboardData:
         if self.letter_map.has_key(sig):
             return self.letter_map[sig]
         else:
-            t = self.keymap.translate_keyboard_state(key['key-scan'], self.active_state, self.active_group)
-            if t:
-                return unichr(gtk.gdk.keyval_to_unicode(t[0]))
+            success, keyval, effective_group, level, consumed_modifiers = \
+                self.keymap.translate_keyboard_state(
+                    key['key-scan'], self.active_state, self.active_group)
+            if success:
+                return unichr(Gdk.keyval_to_unicode(keyval)).encode('utf-8')
 
         return ''
 
-class KeyboardWidget(KeyboardData, gtk.DrawingArea):
+class KeyboardWidget(KeyboardData, Gtk.DrawingArea):
     """A GTK widget which implements an interactive visual keyboard, with support
        for custom data driven layouts."""
 
     def __init__(self, image, root_window, poll_keys=False):
         KeyboardData.__init__(self)
-        gtk.DrawingArea.__init__(self)
+        GObject.GObject.__init__(self)
         
         self.image = image
         self.root_window = root_window
@@ -337,9 +344,9 @@ class KeyboardWidget(KeyboardData, gtk.DrawingArea):
         # Match the image cache in dimensions.
         self.set_size_request(image.width, image.height)
 
-        self.connect("expose-event", self._expose_cb)
+        self.connect("draw", self._draw_cb)
         
-        #self.modify_font(pango.FontDescription('Monospace 10'))
+        #self.modify_font(Pango.FontDescription('Monospace 10'))
         
         # Active language group and modifier state.
         # See http://www.pygtk.org/docs/pygtk/class-gdkkeymap.html for more
@@ -354,7 +361,7 @@ class KeyboardWidget(KeyboardData, gtk.DrawingArea):
         
         self.draw_hands = False
         
-        self.modify_bg(gtk.STATE_NORMAL, self.get_colormap().alloc_color('#d0d0d0'))
+        self.modify_bg(Gtk.StateType.NORMAL, Gdk.Color.parse('#d0d0d0')[1])
 
         # Connect keyboard grabbing and releasing callbacks.        
         if poll_keys:
@@ -363,7 +370,7 @@ class KeyboardWidget(KeyboardData, gtk.DrawingArea):
 
     def _realize_cb(self, widget):
         # Setup keyboard event snooping in the root window.
-        self.root_window.add_events(gtk.gdk.KEY_PRESS_MASK | gtk.gdk.KEY_RELEASE_MASK)
+        self.root_window.add_events(Gdk.EventMask.KEY_PRESS_MASK | Gdk.EventMask.KEY_RELEASE_MASK)
         self.key_press_cb_id = self.root_window.connect('key-press-event', self.key_press_release_cb)
         self.key_release_cb_id = self.root_window.connect('key-release-event', self.key_press_release_cb)
 
@@ -412,20 +419,16 @@ class KeyboardWidget(KeyboardData, gtk.DrawingArea):
             (x1 + corner, y2),
             (x1, y2 - corner),
             (x1, y1 + corner)
-            ]
+        ]
 
-        cr.save()
         cr.new_path()
         cr.set_source_rgb(0.396, 0.698, 0.392)
         cr.set_line_width(2)
-        cr.move_to(*points[0])
         for point in points:
             cr.line_to(*point)
-        cr.line_to(*points[0])
         cr.close_path()
         cr.fill_preserve()
         cr.stroke()
-        cr.restore()
 
         text = ''
         if k['key-label']:
@@ -434,16 +437,16 @@ class KeyboardWidget(KeyboardData, gtk.DrawingArea):
             text = self.get_letter_for_key_state_group(
                 k, self.active_state, self.active_group)
 
-        pango_context = pangocairo.CairoContext(cr)
-        pango_context.set_source_rgb(0, 0, 0)
+        cr.set_source_rgb(0, 0, 0)
+        pango_layout = PangoCairo.create_layout(cr)
+        fd = Pango.FontDescription('Monospace')
+        fd.set_size(10 * Pango.SCALE)
+        pango_layout.set_font_description(fd)
+        pango_layout.set_text(text, len(text))
 
-        pango_layout = pango_context.create_layout()
-        pango_layout.set_font_description(pango.FontDescription('Monospace'))
-        pango_layout.set_text(unicode(text))
-
-        pango_context.move_to(x1 + 8, y2 - 23)
-        pango_context.show_layout(pango_layout)
-        cr.stroke()
+        cr.move_to(x1 + 8, y2 - 23)
+        PangoCairo.update_layout(cr, pango_layout)
+        PangoCairo.show_layout(cr, pango_layout)
 
     def _expose_hands(self, cr):
         lhand_image = self.image.images['OLPC_Lhand_HOMEROW.svg']
@@ -463,7 +466,7 @@ class KeyboardWidget(KeyboardData, gtk.DrawingArea):
                         rhand_image = handle
 
                 # Put the other hand on the SHIFT key if needed.
-                if state & gtk.gdk.SHIFT_MASK:
+                if state & Gdk.ModifierType.SHIFT_MASK:
                     if finger[0] == 'L':
                         rhand_image = self.image.images['OLPC_Rhand_SHIFT.svg']
                     else:
@@ -471,25 +474,21 @@ class KeyboardWidget(KeyboardData, gtk.DrawingArea):
 
                 # TODO: Do something about ALTGR.
 
-        # bounds = self.get_allocation()
-        # screen_x = int(bounds.width-self.image.width)/2
-        # screen_y = int(bounds.height-self.image.height)/2
+        bounds = self.get_allocation()
 
-        # README: these values (cairo.Matrix) are taken seeing the image on the
-        # screen, I think we should find a way to calculate them
         cr.save()
-        matrix = cairo.Matrix(xx=0.3, yy=0.2, x0=10, y0=-20)
-        cr.transform(matrix)
-        lhand_image.render_cairo(cr)
+        Gdk.cairo_set_source_pixbuf(cr, lhand_image, 0, 0)
+        cr.rectangle(0, 0, lhand_image.get_width(),
+                     lhand_image.get_height())
+        cr.paint()
 
         cr.restore()
-        matrix = cairo.Matrix(xx=0.325, yy=0.2, x0=-5, y0=-20)
-        cr.transform(matrix)
-        rhand_image.render_cairo(cr)
-
-    def _expose_cb(self, area, event):
-        cr = self.window.cairo_create()
+        Gdk.cairo_set_source_pixbuf(cr, rhand_image, 0, 0)
+        cr.rectangle(0, 0, rhand_image.get_width(),
+                     rhand_image.get_height())
+        cr.paint()
 
+    def _draw_cb(self, area, cr):
         # Draw the keys.
         for k in self.keys:
             self._draw_key(k, cr)
@@ -502,14 +501,14 @@ class KeyboardWidget(KeyboardData, gtk.DrawingArea):
     def key_press_release_cb(self, widget, event):
         key = self.key_scan_map.get(event.hardware_keycode)
         if key:
-            key['key-pressed'] = event.type == gtk.gdk.KEY_PRESS
+            key['key-pressed'] = event.type == Gdk.EventType.KEY_PRESS
 
         # Hack to get the current modifier state - which will not be represented by the event.
-        state = gtk.gdk.device_get_core_pointer().get_state(self.window)[1]
+        # state = Gdk.device_get_core_pointer().get_state(self.get_window())[1]
 
-        if self.active_group != event.group or self.active_state != state:
+        if self.active_group != event.group or self.active_state != event.state:
             self.active_group = event.group
-            self.active_state = state
+            self.active_state = event.state
 
             self.queue_draw()
 
@@ -556,7 +555,7 @@ class KeyboardWidget(KeyboardData, gtk.DrawingArea):
         # Convert cairo.Surface to Pixbuf
         pixbuf_data = StringIO.StringIO()
         surface.write_to_png(pixbuf_data)
-        pxb_loader = gtk.gdk.PixbufLoader(image_type='png')
+        pxb_loader = GdkPixbuf.PixbufLoader.new_with_type('png')
         pxb_loader.write(pixbuf_data.getvalue())
         temp_pix = pxb_loader.get_pixbuf()
         pxb_loader.close()
diff --git a/keybuilder.py b/keybuilder.py
index bceab0d..28f6f97 100755
--- a/keybuilder.py
+++ b/keybuilder.py
@@ -19,11 +19,11 @@
 import sys
 import keyboard
 
-import gtk
+from gi.repository import Gtk
 
-window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+window = Gtk.Window(Gtk.WindowType.TOPLEVEL)
 window.set_title("keyboard widget")
-window.connect("destroy", lambda w: gtk.main_quit())
+window.connect("destroy", lambda w: Gtk.main_quit())
 window.show_all()
 window.realize()
 
@@ -37,24 +37,24 @@ except:
     pass
 k.set_layout(keyboard.get_layout())
 
-savebtn = gtk.Button()
-savebtn.add(gtk.Label('Save Keys'))
+savebtn = Gtk.Button()
+savebtn.add(Gtk.Label(label='Save Keys'))
 savebtn.connect('clicked', lambda w: k.save_letter_map(sys.argv[1]))
 
-quitbtn = gtk.Button()
-quitbtn.add(gtk.Label('Quit'))
-quitbtn.connect('clicked', lambda w: gtk.main_quit())
+quitbtn = Gtk.Button()
+quitbtn.add(Gtk.Label(label='Quit'))
+quitbtn.connect('clicked', lambda w: Gtk.main_quit())
 
-hbox = gtk.HBox()
-hbox.pack_start(savebtn)
-hbox.pack_start(quitbtn)
+hbox = Gtk.HBox()
+hbox.pack_start(savebtn, True, True, 0)
+hbox.pack_start(quitbtn, True, True, 0)
 
-vbox = gtk.VBox()
-vbox.pack_start(k)
-vbox.pack_start(hbox)
+vbox = Gtk.VBox()
+vbox.pack_start(k, True, True, 0)
+vbox.pack_start(hbox, True, True, 0)
 
 window.add(vbox)
 window.show_all()
 
-gtk.main()
+Gtk.main()
 
diff --git a/lessonbuilder.py b/lessonbuilder.py
index b33a34e..c7c4d1a 100755
--- a/lessonbuilder.py
+++ b/lessonbuilder.py
@@ -21,7 +21,7 @@ from gettext import gettext as _
 from port import json
 
 # For modifier constants.
-import gtk
+from gi.repository import Gtk
 
 # Set up remote debugging.
 #import dbgp.client
@@ -338,7 +338,7 @@ def build_key_steps(
 #        except:
 #            error("The '%s' letter (scan code %x) does not have a finger assigned." % (letter, key['key-scan']))
 #
-#        if state == gtk.gdk.SHIFT_MASK:
+#        if state == Gdk.ModifierType.SHIFT_MASK:
 #            # Choose the finger to press the SHIFT key with.
 #            if key['key-finger'][0] == 'R':
 #                shift_finger = FINGERS['LP']
@@ -348,11 +348,11 @@ def build_key_steps(
 #            instructions = _('Press and hold the SHIFT key with your %(finger)s finger, ') % { 'finger': shift_finger }
 #            instructions += _('then press the %(letter)s key with your %(finger)s finger.') % { 'letter': letter, 'finger': finger }
 #
-#        elif state == gtk.gdk.MOD5_MASK:
+#        elif state == Gdk.ModifierType.MOD5_MASK:
 #            instructions = _('Press and hold the ALTGR key, ') 
 #            instructions += _('then press the %(letter)s key with your %(finger)s finger.') % { 'letter': letter, 'finger': finger }
 #
-#        elif state == gtk.gdk.SHIFT_MASK | gtk.gdk.MOD5_MASK:
+#        elif state == Gdk.ModifierType.SHIFT_MASK | Gdk.ModifierType.MOD5_MASK:
 #            instructions = _('Press and hold the ALTGR and SHIFT keys, ')
 #            instructions += _('then press the %(letter)s key with your %(finger)s finger.') % { 'letter': letter, 'finger': finger }
 #
diff --git a/lessonscreen.py b/lessonscreen.py
index cc75ef4..fb38bff 100644
--- a/lessonscreen.py
+++ b/lessonscreen.py
@@ -19,12 +19,13 @@
 import logging, os, math, time, copy, locale, datetime, random, re
 from gettext import gettext as _
 
-# Import PyGTK.
-import gobject, pygtk, gtk, pango
+from gi.repository import Gtk
+from gi.repository import Gdk
+from gi.repository import GObject
 
 # Import Sugar UI modules.
-import sugar.activity.activity
-from sugar.graphics import *
+import sugar3.activity.activity
+from sugar3.graphics import *
 
 # Import activity modules.
 import keyboard, medalscreen
@@ -48,84 +49,84 @@ FINGERS = {
     'RT': _('right thumb'),
 }
 
-class LessonScreen(gtk.VBox):
+class LessonScreen(Gtk.VBox):
     def __init__(self, lesson, keyboard_images, activity):
-        gtk.VBox.__init__(self)
+        GObject.GObject.__init__(self)
         
         self.lesson = lesson
         self.keyboard_images = keyboard_images
         self.activity = activity
         
         # Build the user interface.
-        title = gtk.Label()
+        title = Gtk.Label()
         title.set_markup("<span size='x-large' weight='bold'>" + lesson['name'] + "</span>")
         title.set_alignment(1.0, 0.0)
         
-        stoplabel = gtk.Label(_('Go Back'))
-        stopbtn =  gtk.Button()
+        stoplabel = Gtk.Label(label=_('Go Back'))
+        stopbtn =  Gtk.Button()
         stopbtn.add(stoplabel)
         stopbtn.connect('clicked', self.stop_cb)
         
-        # TODO- These will be replaced by graphical displays using gtk.DrawingArea.
+        # TODO- These will be replaced by graphical displays using Gtk.DrawingArea.
         self.wpm = 0
         self.accuracy = 0
         
-        self.wpmlabel = gtk.Label()
-        self.accuracylabel = gtk.Label()
+        self.wpmlabel = Gtk.Label()
+        self.accuracylabel = Gtk.Label()
         
-        #self.wpmarea = gtk.DrawingArea()
+        #self.wpmarea = Gtk.DrawingArea()
         #self.wpmarea.connect('expose-event', self.wpm_expose_cb)
-        #self.accuracyarea = gtk.DrawingArea()
+        #self.accuracyarea = Gtk.DrawingArea()
         #self.accuracyarea.connect('expose-event', self.accuracy_expose_cb)
         
-        hbox = gtk.HBox()
+        hbox = Gtk.HBox()
         hbox.pack_start(stopbtn, False, False, 10)
         hbox.pack_start(self.wpmlabel, True, False, 10)
         hbox.pack_start(self.accuracylabel, True, False, 10)
         hbox.pack_end(title, False, False, 10)
         
         # Set up font styles.
-        self.tagtable = gtk.TextTagTable()
-        instructions_tag = gtk.TextTag('instructions')
-        instructions_tag.props.justification = gtk.JUSTIFY_CENTER
+        self.tagtable = Gtk.TextTagTable()
+        instructions_tag = Gtk.TextTag.new('instructions')
+        instructions_tag.props.justification = Gtk.Justification.CENTER
         self.tagtable.add(instructions_tag)
 
-        text_tag = gtk.TextTag('text')
+        text_tag = Gtk.TextTag.new('text')
         text_tag.props.family = 'Monospace'
         self.tagtable.add(text_tag)
         
-        spacer_tag = gtk.TextTag('spacer')
+        spacer_tag = Gtk.TextTag.new('spacer')
         spacer_tag.props.size = 3000
         self.tagtable.add(spacer_tag)
         
-        image_tag = gtk.TextTag('image')
-        image_tag.props.justification = gtk.JUSTIFY_CENTER
+        image_tag = Gtk.TextTag.new('image')
+        image_tag.props.justification = Gtk.Justification.CENTER
         self.tagtable.add(image_tag)
         
-        correct_copy_tag = gtk.TextTag('correct-copy')
+        correct_copy_tag = Gtk.TextTag.new('correct-copy')
         correct_copy_tag.props.family = 'Monospace'
         correct_copy_tag.props.foreground = '#0000ff'
         self.tagtable.add(correct_copy_tag)
         
-        incorrect_copy_tag = gtk.TextTag('incorrect-copy')
+        incorrect_copy_tag = Gtk.TextTag.new('incorrect-copy')
         incorrect_copy_tag.props.family = 'Monospace'
         incorrect_copy_tag.props.foreground = '#ff0000'
         self.tagtable.add(incorrect_copy_tag)
         
         # Set up the scrolling lesson text view.
-        self.lessonbuffer = gtk.TextBuffer(self.tagtable)
-        self.lessontext = gtk.TextView(self.lessonbuffer)
+        self.lessonbuffer = Gtk.TextBuffer.new(self.tagtable)
+        self.lessontext = Gtk.TextView.new_with_buffer(self.lessonbuffer)
         self.lessontext.set_editable(False)
         self.lessontext.set_left_margin(20)
         self.lessontext.set_right_margin(20)
-        self.lessontext.set_wrap_mode(gtk.WRAP_WORD)
-        self.lessontext.modify_base(gtk.STATE_NORMAL, self.get_colormap().alloc_color('#ffffcc'))
+        self.lessontext.set_wrap_mode(Gtk.WrapMode.WORD)
+        self.lessontext.modify_base(Gtk.StateType.NORMAL, Gdk.Color.parse('#ffffcc')[1])
         
-        self.lessonscroll = gtk.ScrolledWindow()
-        self.lessonscroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
+        self.lessonscroll = Gtk.ScrolledWindow()
+        self.lessonscroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.ALWAYS)
         self.lessonscroll.add(self.lessontext)
         
-        frame = gtk.Frame()
+        frame = Gtk.Frame()
         frame.add(self.lessonscroll)
         
         self.keyboard = keyboard.KeyboardWidget(self.keyboard_images, self.activity)
@@ -140,8 +141,8 @@ class LessonScreen(gtk.VBox):
         self.keyboard.set_layout(keyboard.get_layout())
 
         self.pack_start(hbox, False, False, 10)
-        self.pack_start(frame, True, True)
-        self.pack_start(self.keyboard, False)
+        self.pack_start(frame, True, True, 0)
+        self.pack_start(self.keyboard, False, True, 0)
         
         # Connect keyboard grabbing and releasing callbacks.        
         self.connect('realize', self.realize_cb)
@@ -154,7 +155,7 @@ class LessonScreen(gtk.VBox):
         self.begin_lesson()
         
     def realize_cb(self, widget):
-        self.activity.add_events(gtk.gdk.KEY_PRESS_MASK|gtk.gdk.KEY_RELEASE_MASK)
+        self.activity.add_events(Gdk.EventMask.KEY_PRESS_MASK|Gdk.EventMask.KEY_RELEASE_MASK)
         self.key_press_cb_id = self.activity.connect('key-press-event', self.key_cb)
         self.key_release_cb_id = self.activity.connect('key-release-event', self.key_cb)
         
@@ -164,11 +165,11 @@ class LessonScreen(gtk.VBox):
 
     def start_timer(self):
         self.start_time = time.time()
-        self.timer_id = gobject.timeout_add(1000, self.timer_cb)
+        self.timer_id = GObject.timeout_add(1000, self.timer_cb)
 
     def stop_timer(self):
         if self.timer_id:
-            gobject.source_remove(self.timer_id)
+            GObject.source_remove(self.timer_id)
         self.start_time = None
         self.timer_id = None
 
@@ -349,20 +350,20 @@ class LessonScreen(gtk.VBox):
 
         # Extract information about the key pressed.
         key = event.string
-        key_name = gtk.gdk.keyval_name(event.keyval)
+        key_name = Gdk.keyval_name(event.keyval)
         
         # Ignore events which don't produce a character, except backspace.
         if not (key_name == 'BackSpace' or key):
             return True
 
         # Ignore either press or release events, depending on mode.
-        if self.mode == 'key' and event.type == gtk.gdk.KEY_PRESS:
+        if self.mode == 'key' and event.type == Gdk.EventType.KEY_PRESS:
             return True 
-        if self.mode != 'key' and event.type == gtk.gdk.KEY_RELEASE:
+        if self.mode != 'key' and event.type == Gdk.EventType.KEY_RELEASE:
             return True
         
         # Ignore hotkeys.
-        if event.state & (gtk.gdk.CONTROL_MASK | gtk.gdk.MOD1_MASK):
+        if event.get_state() & (Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.MOD1_MASK):
             return True
         
         # Convert Return keys to paragraph symbols.
@@ -474,7 +475,8 @@ class LessonScreen(gtk.VBox):
             self.lessontext.grab_focus()
             
             # Scroll the TextView so the cursor is on screen.
-            self.lessontext.scroll_to_mark(self.lessonbuffer.get_insert(), 0)
+            self.lessontext.scroll_to_mark(self.lessonbuffer.get_insert(), 0,
+                                           use_align=False, xalign=0.5, yalign=0.5)
 
         # In Key mode, display the finger hint and the key image.
         if self.mode == 'key':
@@ -499,7 +501,7 @@ class LessonScreen(gtk.VBox):
                 except:
                     finger = ''
         
-                if state == gtk.gdk.SHIFT_MASK:
+                if state == Gdk.ModifierType.SHIFT_MASK:
                     # Choose the finger to press the SHIFT key with.
                     if key['key-finger'][0] == 'R':
                         shift_finger = FINGERS['LP']
@@ -509,11 +511,11 @@ class LessonScreen(gtk.VBox):
                     instructions = _('Press and hold the shift key with your %(finger)s, ') % { 'finger': shift_finger }
                     instructions += _('then press the %(letter)s key with your %(finger)s.') % { 'letter': letter, 'finger': finger }
         
-                elif state == gtk.gdk.MOD5_MASK:
+                elif state == Gdk.ModifierType.MOD5_MASK:
                     instructions = _('Press and hold the altgr key, ') 
                     instructions += _('then press the %(letter)s key with your %(finger)s.') % { 'letter': letter, 'finger': finger }
         
-                elif state == gtk.gdk.SHIFT_MASK | gtk.gdk.MOD5_MASK:
+                elif state == Gdk.ModifierType.SHIFT_MASK | Gdk.ModifierType.MOD5_MASK:
                     instructions = _('Press and hold the altgr and shift keys, ')
                     instructions += _('then press the %(letter)s key with your %(finger)s.') % { 'letter': letter, 'finger': finger }
         
@@ -522,13 +524,13 @@ class LessonScreen(gtk.VBox):
 
                 self.lessonbuffer.insert(self.lessonbuffer.get_end_iter(), instructions + '\n\n')
 
-                if state & gtk.gdk.SHIFT_MASK:
+                if state & Gdk.ModifierType.SHIFT_MASK:
                     shift_key = self.keyboard.find_key_by_label('shift')
                     pixbuf = self.keyboard.get_key_pixbuf(shift_key, scale=1)
                     self.lessonbuffer.insert_pixbuf(self.lessonbuffer.get_end_iter(), pixbuf)
                     self.lessonbuffer.insert(self.lessonbuffer.get_end_iter(), ' ')
                 
-                if state & gtk.gdk.MOD5_MASK:
+                if state & Gdk.ModifierType.MOD5_MASK:
                     altgr_key = self.keyboard.find_key_by_label('altgr')
                     pixbuf = self.keyboard.get_key_pixbuf(altgr_key, scale=1)
                     self.lessonbuffer.insert_pixbuf(self.lessonbuffer.get_end_iter(), pixbuf)
diff --git a/mainscreen.py b/mainscreen.py
index 2762baf..7f540f0 100644
--- a/mainscreen.py
+++ b/mainscreen.py
@@ -19,12 +19,14 @@ import logging, os, math, time, copy, locale, datetime, random, re, glob
 from gettext import gettext as _
 from port import json
 
-# Import PyGTK.
-import gobject, pygtk, gtk, pango
+from gi.repository import Gtk
+from gi.repository import Gdk
+from gi.repository import GdkPixbuf
+from gi.repository import GObject
 
 # Import Sugar UI modules.
-import sugar.activity.activity
-from sugar.graphics import *
+import sugar3.activity.activity
+from sugar3.graphics import *
 
 # Import activity modules.
 import lessonscreen, medalscreen
@@ -38,9 +40,9 @@ import keyboard
 # http://commons.wikimedia.org/wiki/File:Silver_medal_world_centered.svg
 # http://commons.wikimedia.org/wiki/File:Bronze_medal_world_centered.svg
 
-class MainScreen(gtk.VBox):
+class MainScreen(Gtk.VBox):
     def __init__(self, activity):
-        gtk.VBox.__init__(self)
+        GObject.GObject.__init__(self)
         
         self.activity = activity
         
@@ -48,37 +50,37 @@ class MainScreen(gtk.VBox):
         self.titlescene = titlescene.TitleScene()
         
         # Build lessons list.
-        self.lessonbox = gtk.HBox()
+        self.lessonbox = Gtk.HBox()
         
-        #nexticon = sugar.graphics.icon.Icon(icon_name='go-next')
+        #nexticon = sugar3.graphics.icon.Icon(icon_name='go-next')
         #self.nextlessonbtn.add(nexticon)
-        nextlabel = gtk.Label()
+        nextlabel = Gtk.Label()
         nextlabel.set_markup("<span size='large'>" + _('Next') + "</span>")
 
-        self.nextlessonbtn = gtk.Button()
+        self.nextlessonbtn = Gtk.Button()
         self.nextlessonbtn.add(nextlabel)
         self.nextlessonbtn.connect('clicked', self.next_lesson_clicked_cb)
         
-        #previcon = sugar.graphics.icon.Icon(icon_name='go-previous')
+        #previcon = sugar3.graphics.icon.Icon(icon_name='go-previous')
         #self.prevlessonbtn.add(previcon)
-        prevlabel = gtk.Label()
+        prevlabel = Gtk.Label()
         prevlabel.set_markup("<span size='large'>" + _('Previous') + "</span>")
 
-        self.prevlessonbtn = gtk.Button()
+        self.prevlessonbtn = Gtk.Button()
         self.prevlessonbtn.add(prevlabel)
         self.prevlessonbtn.connect('clicked', self.prev_lesson_clicked_cb)
         
-        lessonlabel = gtk.Label()
+        lessonlabel = Gtk.Label()
         lessonlabel.set_markup("<span size='x-large' weight='bold'>" + _('Start Lesson') + "</span>")
         
-        lessonbtn = gtk.Button()
+        lessonbtn = Gtk.Button()
         lessonbtn.add(lessonlabel)
         lessonbtn.connect('clicked', self.lesson_clicked_cb)
-        lessonbtn.modify_bg(gtk.STATE_NORMAL, self.get_colormap().alloc_color('#60b060'))
+        lessonbtn.modify_bg(Gtk.StateType.NORMAL, Gdk.Color.parse('#60b060')[1])
         
         # Load lessons for this language.
         code = locale.getdefaultlocale()[0] or 'en_US'
-        lessons_path = os.path.join(sugar.activity.activity.get_bundle_path(), 'lessons')
+        lessons_path = os.path.join(sugar3.activity.activity.get_bundle_path(), 'lessons')
         lessons_file = os.path.join(lessons_path, code + '.lessons')
         if os.path.isfile(lessons_file):
             self.load_lessons(lessons_file)
@@ -99,24 +101,25 @@ class MainScreen(gtk.VBox):
         self.lessons.sort(lambda x, y: x.get('order', 0) - y.get('order', 0))
 
         # Load all the keyboard images.
-        width = int(gtk.gdk.screen_width())
-        height = int(gtk.gdk.screen_height()*0.3)
+        width = int(Gdk.Screen.width())
+        height = int(Gdk.Screen.height()*0.3)
+
         self.keyboard_images = keyboard.KeyboardImages(width, height)
         self.keyboard_images.load_images()
         
-        navbox = gtk.HBox()
+        navbox = Gtk.HBox()
         navbox.set_spacing(10)
-        navbox.pack_start(self.prevlessonbtn, True)
-        navbox.pack_start(lessonbtn, True)
-        navbox.pack_start(self.nextlessonbtn, True)
+        navbox.pack_start(self.prevlessonbtn, True, True, 0)
+        navbox.pack_start(lessonbtn, True, True, 0)
+        navbox.pack_start(self.nextlessonbtn, True, True, 0)
         
-        lessonbox = gtk.VBox()
+        lessonbox = Gtk.VBox()
         lessonbox.set_spacing(10)
-        lessonbox.pack_start(navbox, False)
-        lessonbox.pack_start(self.lessonbox)
+        lessonbox.pack_start(navbox, False, True, 0)
+        lessonbox.pack_start(self.lessonbox, True, True, 0)
         
         self.pack_start(self.titlescene, False, True, 10)
-        self.pack_start(lessonbox, True)
+        self.pack_start(lessonbox, True, True, 0)
         
         self.show_next_lesson()
 
@@ -165,10 +168,10 @@ class MainScreen(gtk.VBox):
             medal_type = self.activity.data['medals'][lesson['name']]['type']
         
         # Create the lesson button.
-        namelabel = gtk.Label()
+        namelabel = Gtk.Label()
         namelabel.set_alignment(0.5, 0.5)
         namelabel.set_markup("<span size='x-large' weight='bold'>" + lesson['name'] + "</span>")
-        desclabel = gtk.Label()
+        desclabel = Gtk.Label()
         desclabel.set_alignment(0.5, 0.5)
         desclabel.set_markup("<span size='large' color='#606060'>" + lesson['description'] + "</span>")
         
@@ -177,16 +180,16 @@ class MainScreen(gtk.VBox):
         else:
             hint = ''
                 
-        #hintlabel = gtk.Label()
+        #hintlabel = Gtk.Label()
         #hintlabel.set_alignment(0.0, 0.8)
         #hintlabel.set_markup("<span size='8000' color='#606020'>" + hint + "</span>")
         
-        labelbox = gtk.VBox()
+        labelbox = Gtk.VBox()
         labelbox.set_spacing(10)
         labelbox.set_border_width(20)
-        labelbox.pack_start(namelabel, False)
-        labelbox.pack_start(desclabel, False)
-        #labelbox.pack_start(hintlabel)
+        labelbox.pack_start(namelabel, False, True, 0)
+        labelbox.pack_start(desclabel, False, True, 0)
+        #labelbox.pack_start(hintlabel, True, True, 0)
 
         # Create the medal image.
         images = {
@@ -196,11 +199,11 @@ class MainScreen(gtk.VBox):
             'gold':   'images/gold-medal.svg'
         }
 
-        medal_size = int(2.0 * sugar.graphics.style.GRID_CELL_SIZE)
-        medalpixbuf = gtk.gdk.pixbuf_new_from_file(images[medal_type])
-        medalpixbuf = medalpixbuf.scale_simple(medal_size, medal_size, gtk.gdk.INTERP_BILINEAR)
+        medal_size = int(2.0 * sugar3.graphics.style.GRID_CELL_SIZE)
+        medalpixbuf = GdkPixbuf.Pixbuf.new_from_file(images[medal_type])
+        medalpixbuf = medalpixbuf.scale_simple(medal_size, medal_size, GdkPixbuf.InterpType.BILINEAR)
         
-        medalimage = gtk.Image()
+        medalimage = Gtk.Image()
         medalimage.set_from_pixbuf(medalpixbuf)
         
         names = {
@@ -209,30 +212,30 @@ class MainScreen(gtk.VBox):
             'silver': _('Silver Medal'),
             'gold':   _('Gold Medal'),
         }
-        medallabel = gtk.Label(names[medal_type])
+        medallabel = Gtk.Label(label=names[medal_type])
         
-        medalbox = gtk.VBox()
-        medalbox.pack_start(medalimage)
-        medalbox.pack_start(medallabel)
+        medalbox = Gtk.VBox()
+        medalbox.pack_start(medalimage, True, True, 0)
+        medalbox.pack_start(medallabel, True, True, 0)
         
-        medalbtn = gtk.Button()
+        medalbtn = Gtk.Button()
         medalbtn.add(medalbox)
         medalbtn.connect('clicked', self.medal_clicked_cb)
         
         # Hilite the button in the direction of the first unmedaled lesson.
         next_index = self.get_next_lesson()
         if next_index > self.lesson_index and index < len(self.lessons)-1:
-            self.nextlessonbtn.modify_bg(gtk.STATE_NORMAL, self.get_colormap().alloc_color('#ff8080'))
+            self.nextlessonbtn.modify_bg(Gtk.StateType.NORMAL, Gdk.Color.parse('#ff8080')[1])
         else:
-            self.nextlessonbtn.modify_bg(gtk.STATE_NORMAL, self.get_colormap().alloc_color('#40a040'))
+            self.nextlessonbtn.modify_bg(Gtk.StateType.NORMAL, Gdk.Color.parse('#40a040')[1])
         if next_index < self.lesson_index and index > 0:
-            self.prevlessonbtn.modify_bg(gtk.STATE_NORMAL, self.get_colormap().alloc_color('#ff8080'))
+            self.prevlessonbtn.modify_bg(Gtk.StateType.NORMAL, Gdk.Color.parse('#ff8080')[1])
         else:
-            self.prevlessonbtn.modify_bg(gtk.STATE_NORMAL, self.get_colormap().alloc_color('#40a040'))
+            self.prevlessonbtn.modify_bg(Gtk.StateType.NORMAL, Gdk.Color.parse('#40a040')[1])
         
-        self.lessonbox.pack_start(labelbox, True)
+        self.lessonbox.pack_start(labelbox, True, True, 0)
         if medal_type != 'none':
-            self.lessonbox.pack_start(medalbtn, False)
+            self.lessonbox.pack_start(medalbtn, False, True, 0)
 
         self.lessonbox.show_all()
     
diff --git a/medalscreen.py b/medalscreen.py
index a1d881a..d9cf410 100644
--- a/medalscreen.py
+++ b/medalscreen.py
@@ -18,20 +18,22 @@
 import logging, os, math, time, copy, locale, datetime, random, re
 from gettext import gettext as _
 
-# Import PyGTK.
-import gobject, pygtk, gtk, pango
+from gi.repository import Gtk
+from gi.repository import Gdk
+from gi.repository import GdkPixbuf
+from gi.repository import GObject
 
 # Import Sugar UI modules.
-import sugar.activity.activity
-import sugar.graphics.style
+import sugar3.activity.activity
+import sugar3.graphics.style
 
-class MedalScreen(gtk.EventBox):
-    MEDAL_SIZE = int(4.5 * sugar.graphics.style.GRID_CELL_SIZE)
+class MedalScreen(Gtk.EventBox):
+    MEDAL_SIZE = int(4.5 * sugar3.graphics.style.GRID_CELL_SIZE)
 
     def __init__(self, medal, activity):
-        gtk.EventBox.__init__(self)
+        GObject.GObject.__init__(self)
         
-        self.modify_bg(gtk.STATE_NORMAL, self.get_colormap().alloc_color('#ffffff'))
+        self.modify_bg(Gtk.StateType.NORMAL, Gdk.Color.parse('#ffffff')[1])
         
         self.medal = medal
         self.activity = activity
@@ -43,80 +45,80 @@ class MedalScreen(gtk.EventBox):
             'silver': 'images/silver-medal.svg',
             'gold':   'images/gold-medal.svg'
         }
-        medalpixbuf = gtk.gdk.pixbuf_new_from_file(images[medal_type])
-        medalpixbuf = medalpixbuf.scale_simple(MedalScreen.MEDAL_SIZE, MedalScreen.MEDAL_SIZE, gtk.gdk.INTERP_BILINEAR)
+        medalpixbuf = GdkPixbuf.Pixbuf.new_from_file(images[medal_type])
+        medalpixbuf = medalpixbuf.scale_simple(MedalScreen.MEDAL_SIZE, MedalScreen.MEDAL_SIZE, GdkPixbuf.InterpType.BILINEAR)
         
-        medalimage = gtk.Image()
+        medalimage = Gtk.Image()
         medalimage.set_from_pixbuf(medalpixbuf)
 
         # Certifications section.
-        title = gtk.Label()
+        title = Gtk.Label()
         title.set_markup(_("<span font_desc='Serif Bold Italic 28'>Certificate of Achievement</span>"))
         
-        text0 = gtk.Label()
+        text0 = Gtk.Label()
         text0.set_markup(_("<span font_desc='Sans 16'>This certifies that</span>"))
 
-        text1 = gtk.Label()
+        text1 = Gtk.Label()
         text1.set_markup(_("<span font_desc='Sans 16'><b><u><i>%(nick)s</i></u></b></span>") % medal)
 
-        text2 = gtk.Label()
+        text2 = Gtk.Label()
         text2.set_markup(_("<span font_desc='Sans 16'>earned a %(type)s medal in </span>") % medal)
 
-        text3 = gtk.Label()
+        text3 = Gtk.Label()
         text3.set_markup(_("<span font_desc='Sans 16'>in <b><u><i>%(lesson)s</i></u></b></span>") % medal)
 
-        text4 = gtk.Label()
+        text4 = Gtk.Label()
         text4.set_markup(_("<span font_desc='Sans 16'>on <b><u><i>%(date)s</i></u></b>.</span>") % medal)
 
-        textbox = gtk.VBox()
-        textbox.pack_start(text0)
-        textbox.pack_start(text1)
-        textbox.pack_start(text2)
-        textbox.pack_start(text3)
-        textbox.pack_start(text4)
+        textbox = Gtk.VBox()
+        textbox.pack_start(text0, True, True, 0)
+        textbox.pack_start(text1, True, True, 0)
+        textbox.pack_start(text2, True, True, 0)
+        textbox.pack_start(text3, True, True, 0)
+        textbox.pack_start(text4, True, True, 0)
 
-        medalbox = gtk.HBox()
-        medalbox.pack_start(textbox)
-        medalbox.pack_end(medalimage)
+        medalbox = Gtk.HBox()
+        medalbox.pack_start(textbox, True, True, 0)
+        medalbox.pack_end(medalimage, True, True, 0)
 
         # Stats section.
-        statbox = gtk.HBox()
+        statbox = Gtk.HBox()
         if medal.has_key('wpm'):
-            stat1 = gtk.Label()
+            stat1 = Gtk.Label()
             stat1.set_markup("<span size='18000'>" + (_('<b>Words Per Minute:</b> %(wpm)d') % medal) + "</span>" )
-            statbox.pack_start(stat1, True)
+            statbox.pack_start(stat1, True, True, 0)
         
-            stat2 = gtk.Label()
+            stat2 = Gtk.Label()
             stat2.set_markup("<span size='18000'>" + (_('<b>Accuracy:</b> %(accuracy)d%%') % medal) + "</span>" )
-            statbox.pack_start(stat2, True)
+            statbox.pack_start(stat2, True, True, 0)
 
         elif medal.has_key('score'):
-            stat1 = gtk.Label()
+            stat1 = Gtk.Label()
             stat1.set_markup("<span size='18000'>" + (_('<b>SCORE:</b> %(score)d') % medal) + "</span>" )
-            statbox.pack_start(stat1, True)
+            statbox.pack_start(stat1, True, True, 0)
         
-        oklabel = gtk.Label()
+        oklabel = Gtk.Label()
         oklabel.set_markup("<span size='10000'>" + _('Press the ENTER key to continue.') + '</span>')
-        self.okbtn = gtk.Button()
+        self.okbtn = Gtk.Button()
         self.okbtn.add(oklabel)
         self.okbtn.connect('clicked', self.ok_cb)
 
-        btnbox = gtk.HBox()
+        btnbox = Gtk.HBox()
         btnbox.pack_start(self.okbtn, True, True, 100)
         
-        vbox = gtk.VBox()
+        vbox = Gtk.VBox()
         
         vbox.pack_start(title, False, False, 0)
         vbox.pack_start(medalbox, True, False, 0)
-        vbox.pack_start(gtk.HSeparator(), False, False, 20)
+        vbox.pack_start(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL), False, False, 20)
         vbox.pack_start(statbox, False, False, 0)
         
-        frame = gtk.Frame()
+        frame = Gtk.Frame()
         frame.add(vbox)
         frame.set_border_width(10)
 
-        box = gtk.VBox() 
-        box.pack_start(frame, True, True)
+        box = Gtk.VBox()
+        box.pack_start(frame, True, True, 0)
         box.pack_start(btnbox, False, False, 40)
 
         self.add(box)
@@ -127,7 +129,7 @@ class MedalScreen(gtk.EventBox):
 
     def realize_cb(self, widget):
         # For some odd reason, if I do this in the constructor, nothing happens.
-        self.okbtn.set_flags(gtk.CAN_DEFAULT)
+        self.okbtn.set_can_default(True)
         self.okbtn.grab_default()
 
     def ok_cb(self, widget):
diff --git a/port/chooser.py b/port/chooser.py
index e2df259..1391942 100644
--- a/port/chooser.py
+++ b/port/chooser.py
@@ -14,11 +14,11 @@
 
 """Object chooser method"""
 
-import gtk
+from gi.repository import Gtk
 import logging
 
-from sugar import mime
-from sugar.graphics.objectchooser import ObjectChooser
+from sugar3 import mime
+from sugar3.graphics.objectchooser import ObjectChooser
 
 TEXT  = hasattr(mime, 'GENERIC_TYPE_TEXT') and mime.GENERIC_TYPE_TEXT or None
 IMAGE = hasattr(mime, 'GENERIC_TYPE_IMAGE') and mime.GENERIC_TYPE_IMAGE or None
@@ -45,7 +45,7 @@ def pick(cb=None, default=None, parent=None, what=None):
     out = None
 
     try:
-        if chooser.run() == gtk.RESPONSE_ACCEPT:
+        if chooser.run() == Gtk.ResponseType.ACCEPT:
             jobject = chooser.get_selected_object()
             logging.debug('ObjectChooser: %r' % jobject)
 
diff --git a/setup.py b/setup.py
index 77fda74..c17ead5 100755
--- a/setup.py
+++ b/setup.py
@@ -1,4 +1,4 @@
 #!/usr/bin/env python
-from sugar.activity import bundlebuilder
+from sugar3.activity import bundlebuilder
 if __name__ == "__main__":
     bundlebuilder.start()
diff --git a/titlescene.py b/titlescene.py
index 4dc6ae4..9739152 100644
--- a/titlescene.py
+++ b/titlescene.py
@@ -18,12 +18,15 @@
 import random
 from gettext import gettext as _
 
-# Import PyGTK.
-import gobject, pygtk, gtk, pango
-import pangocairo
+from gi.repository import Gtk
+from gi.repository import Gdk
+from gi.repository import GObject
+from gi.repository import Pango
+from gi.repository import PangoCairo
+from gi.repository import GdkPixbuf
 
 
-class TitleScene(gtk.DrawingArea):
+class TitleScene(Gtk.DrawingArea):
     # Maximum portion of the screen the background can fill vertically.
     BACKGROUND_HEIGHT_RATIO = 0.6
 
@@ -34,58 +37,61 @@ class TitleScene(gtk.DrawingArea):
     TITLE_FONT = 'Times 45'
 
     def __init__(self):
-        gtk.DrawingArea.__init__(self)
+        Gtk.DrawingArea.__init__(self)
 
-        pbuf = gtk.gdk.pixbuf_new_from_file('images/main-background.jpg')
+        pbuf = GdkPixbuf.Pixbuf.new_from_file('images/main-background.jpg')
 
-        width_ratio = float(gtk.gdk.screen_width()) / pbuf.get_width()
-        height_ratio = float(gtk.gdk.screen_height()*TitleScene.BACKGROUND_HEIGHT_RATIO) / pbuf.get_height()
+        width_ratio = float(Gdk.Screen.width()) / pbuf.get_width()
+        height_ratio = float(Gdk.Screen.height()*TitleScene.BACKGROUND_HEIGHT_RATIO) / pbuf.get_height()
 
         ratio = min(width_ratio, height_ratio)
-        self.backgroundpixbuf = pbuf.scale_simple(int(pbuf.get_width()*ratio), int(pbuf.get_height()*ratio), gtk.gdk.INTERP_BILINEAR)
+        self.backgroundpixbuf = pbuf.scale_simple(int(pbuf.get_width()*ratio), int(pbuf.get_height()*ratio), GdkPixbuf.InterpType.BILINEAR)
  
         self.set_size_request(self.backgroundpixbuf.get_width(), self.backgroundpixbuf.get_height())
         
-        self.connect("expose-event", self.expose_cb)
+        self.connect("draw", self.draw_cb)
         
         self.title_original = _('Typing Turtle')
         self.title_src = self.title_original
         self.title_text = ''
 
-    def expose_cb(self, area, event):
+    def draw_cb(self, area, cr):
         bounds = self.get_allocation()
 
-        cr = self.window.cairo_create()
-
         # Background picture.
         x = (bounds.width - self.backgroundpixbuf.get_width())/2
-        cr.set_source_pixbuf(self.backgroundpixbuf, 0, 0)
+
+        Gdk.cairo_set_source_pixbuf(cr, self.backgroundpixbuf, 0, 0)
         cr.rectangle(x, 0, self.backgroundpixbuf.get_width(),
                      self.backgroundpixbuf.get_height())
         cr.paint()
 
-        cr = pangocairo.CairoContext(cr)
         cr.set_source_rgb(0, 0, 0)
-        self.pango_layout = cr.create_layout()
+        self.pango_layout = PangoCairo.create_layout(cr)
         self.pango_layout.set_font_description(
-            pango.FontDescription(TitleScene.TITLE_FONT))
-        self.pango_layout.set_text(unicode(self.title_original))
+            Pango.FontDescription(TitleScene.TITLE_FONT))
+        self.pango_layout.set_text(unicode(self.title_original),
+                                   len(self.title_original))
 
         original_size = self.pango_layout.get_size()
-        self.x_text = (bounds.width - original_size[0] / pango.SCALE) - \
+        self.x_text = (bounds.width - original_size[0] / Pango.SCALE) - \
             TitleScene.TITLE_OFFSET[0]
         self.y_text = TitleScene.TITLE_OFFSET[1]
 
-        gobject.timeout_add(50, self.timer_cb)
+        GObject.timeout_add(50, self.timer_cb)
 
     def draw_text(self):
         # Animated Typing Turtle title.
-        cr = self.window.cairo_create()
+        window = self.get_window()
+        if window is None:
+            return
+        cr = window.cairo_create()
 
         cr.move_to(self.x_text, self.y_text)
-        self.pango_layout.set_text(unicode(self.title_text))
-        cr.show_layout(self.pango_layout)
-        cr.stroke()
+        self.pango_layout.set_text(unicode(self.title_text),
+                                   len(self.title_text))
+        PangoCairo.update_layout(cr, self.pango_layout)
+        PangoCairo.show_layout(cr, self.pango_layout)
 
     def timer_cb(self):
         if len(self.title_src) > 0:
diff --git a/typingturtle.py b/typingturtle.py
index ad6c6cb..78d2fe6 100755
--- a/typingturtle.py
+++ b/typingturtle.py
@@ -25,25 +25,21 @@ from port import json
 #dbgp.client.brkOnExcept(host='192.168.1.104', port=12900)
 
 # there is need to set up localization.
-# since sugar.activity.main already seted up gettext envronment
+# since sugar3.activity.main already seted up gettext envronment
 #locale.setlocale(locale.LC_ALL, '')
 
-# Import PyGTK.
-import gobject, pygtk, gtk, pango
+
+from gi.repository import Gtk
 
 # Import Sugar UI modules.
-import sugar.activity.activity
-from sugar.graphics import *
-from sugar.graphics import toolbutton
-from sugar import profile
-
-OLD_TOOLBAR = False
-try:
-    from sugar.graphics.toolbarbox import ToolbarBox
-    from sugar.activity.widgets import StopButton
-    from sugar.activity.widgets import ActivityToolbarButton
-except ImportError:
-    OLD_TOOLBAR = True
+import sugar3.activity.activity
+from sugar3.graphics import *
+from sugar3.graphics import toolbutton
+from sugar3 import profile
+
+from sugar3.graphics.toolbarbox import ToolbarBox
+from sugar3.activity.widgets import StopButton
+from sugar3.activity.widgets import ActivityToolbarButton
 
 # Initialize logging.
 log = logging.getLogger('Typing Turtle')
@@ -51,9 +47,28 @@ log.setLevel(logging.DEBUG)
 logging.basicConfig()
 
 # Change to bundle directory.
-bundle_path = sugar.activity.activity.get_bundle_path() 
+bundle_path = sugar3.activity.activity.get_bundle_path() 
 os.chdir(bundle_path)
 
+# Set correct DPI for Rsvg and Screen
+from gi.repository import PangoCairo
+
+def _get_screen_dpi():
+    xft_dpi = Gtk.Settings.get_default().get_property('gtk-xft-dpi')
+    dpi = float(xft_dpi / 1024)
+    logging.debug('Setting dpi to: %f', dpi)
+    # HACK: if the DPI detected is 200.0 it seems we are on an XO, so
+    # we return 133 because the XO manage its resolution in a complex
+    # way. More information here:
+    #     http://wiki.laptop.org/go/Display
+    if 200 == int(dpi):
+        return 133
+    return dpi
+
+dpi = _get_screen_dpi()
+font_map_default = PangoCairo.font_map_get_default()
+font_map_default.set_resolution(dpi)
+
 # Import activity modules.
 import mainscreen, editlessonlistscreen
 
@@ -61,16 +76,16 @@ import mainscreen, editlessonlistscreen
 # 
 # It owns the main application window, and all the various toolbars and options.
 # Activity Screens are stored in a stack, with the currently active screen on top.
-class TypingTurtle(sugar.activity.activity.Activity):
+class TypingTurtle(sugar3.activity.activity.Activity):
     def __init__ (self, handle):
-        sugar.activity.activity.Activity.__init__(self, handle)
+        sugar3.activity.activity.Activity.__init__(self, handle)
         self.set_title(_("Typing Turtle"))
 	self.max_participants = 1
         
         self.build_toolbox()
         
         self.screens = []
-        self.screenbox = gtk.VBox()
+        self.screenbox = Gtk.VBox()
         
         self.nick = profile.get_nick_name()
         
@@ -92,45 +107,31 @@ class TypingTurtle(sugar.activity.activity.Activity):
         
         self.show_all()
         
-        self.editorbtn = sugar.graphics.toolbutton.ToolButton('view-source')
+        self.editorbtn = sugar3.graphics.toolbutton.ToolButton('view-source')
         self.editorbtn.set_tooltip(_("Edit Lessons"))
         self.editorbtn.connect('clicked', self.editor_clicked_cb)
 
-        if OLD_TOOLBAR:
-            # Hide the sharing button from the activity toolbar since
-            # we don't support sharing.
-            activity_toolbar = self.tbox.get_activity_toolbar()
-            activity_toolbar.share.props.visible = False
-
-            share_idx = activity_toolbar.get_item_index(activity_toolbar.share)
-            activity_toolbar.insert(self.editorbtn, share_idx)
-        else:
-            activity_toolbar = self.toolbar_box.toolbar
-            activity_toolbar.insert(self.editorbtn, 1)
+        activity_toolbar = self.toolbar_box.toolbar
+        activity_toolbar.insert(self.editorbtn, 1)
 
         self.editorbtn.show_all()
 
     def build_toolbox(self):
-        if OLD_TOOLBAR:
-            self.tbox = sugar.activity.activity.ActivityToolbox(self)
-            self.tbox.show_all()
-            self.set_toolbox(self.tbox)
-        else:
-            self.toolbar_box = ToolbarBox()
+        self.toolbar_box = ToolbarBox()
 
-            activity_button = ActivityToolbarButton(self)
-            self.toolbar_box.toolbar.insert(activity_button, 0)
-            activity_button.show()
+        activity_button = ActivityToolbarButton(self)
+        self.toolbar_box.toolbar.insert(activity_button, 0)
+        activity_button.show()
 
-            separator = gtk.SeparatorToolItem()
-            separator.props.draw = False
-            separator.set_expand(True)
-            self.toolbar_box.toolbar.insert(separator, -1)
+        separator = Gtk.SeparatorToolItem()
+        separator.props.draw = False
+        separator.set_expand(True)
+        self.toolbar_box.toolbar.insert(separator, -1)
 
-            self.toolbar_box.toolbar.insert(StopButton(self), -1)
+        self.toolbar_box.toolbar.insert(StopButton(self), -1)
 
-            self.set_toolbar_box(self.toolbar_box)
-            self.toolbar_box.show_all()
+        self.set_toolbar_box(self.toolbar_box)
+        self.toolbar_box.show_all()
 
     def editor_clicked_cb(self, btn):
         self.push_screen(editlessonlistscreen.EditLessonListScreen(self, self.mainscreen.lessons))
@@ -146,7 +147,7 @@ class TypingTurtle(sugar.activity.activity.Activity):
             
             self.screenbox.remove(oldscreen)
         
-        self.screenbox.pack_start(screen, True, True)
+        self.screenbox.pack_start(screen, True, True, 0)
         self.screens.append(screen)
         
         try:
@@ -172,7 +173,7 @@ class TypingTurtle(sugar.activity.activity.Activity):
             except:
                 pass
             
-            self.screenbox.pack_start(screen)
+            self.screenbox.pack_start(screen, True, True, 0)
             
     def add_history(self, entry):
         self.data['history'].append(entry)
-- 
1.7.11.2



More information about the Sugar-devel mailing list