[postr] Ported to GTK+3



commit b8d043bdd4de109f83fa15f8eeaffc7e2bbe8305
Author: GermÃn Poo-CaamaÃo <gpoo gnome org>
Date:   Wed Oct 3 14:30:29 2012 -0700

    Ported to GTK+3
    
    Added catalog for Glade.  To use it:
     $ export GLADE_CATALOG_SEARCH_PATH=.
     $ glade postr.glade
    
    Signed-off-by: GermÃn Poo-CaamaÃo <gpoo gnome org>

 nautilus/postrExtension.py  |   32 +-
 postr                       |    4 +-
 src/AboutDialog.py          |   18 +-
 src/AuthenticationDialog.py |   33 +-
 src/ContentTypeCombo.py     |   20 +-
 src/ErrorDialog.py          |   24 +-
 src/GroupSelector.py        |   59 ++--
 src/ImageList.py            |   44 ++-
 src/ImageStore.py           |   32 +-
 src/LicenseCombo.py         |   25 +-
 src/PrivacyCombo.py         |   22 +-
 src/ProgressDialog.py       |   45 ++-
 src/PyUnique.py             |   36 +-
 src/SafetyCombo.py          |   20 +-
 src/SetCombo.py             |   56 ++--
 src/StatusBar.py            |   12 +-
 src/TagsEntry.py            |   19 +-
 src/catalog_poster.xml      |   45 +++
 src/flickrest.py            |    8 +-
 src/postr.glade             |  864 +++++++++++++++++++++++--------------------
 src/postr.py                |  420 ++++++++++-----------
 src/proxyclient.py          |    2 +-
 src/util.py                 |   28 +-
 23 files changed, 1002 insertions(+), 866 deletions(-)
---
diff --git a/nautilus/postrExtension.py b/nautilus/postrExtension.py
index 750031b..a17b79e 100644
--- a/nautilus/postrExtension.py
+++ b/nautilus/postrExtension.py
@@ -18,19 +18,19 @@
 import gettext
 gettext.install('postr')
 
-import gobject, nautilus
+from gi.repository import Nautilus, GObject
 import os, os.path
 from urllib import unquote
 
 PROGRAM_NAME = 'postr'
 
-class PostrExtension(nautilus.MenuProvider):
+class PostrExtension(GObject.GObject, Nautilus.MenuProvider):
     def __init__(self):
         # The constructor must be exists, even if there is nothing
         # to initialize (See Bug #374958)
         #self.program = None
         pass
-    
+
     def locate_program(self, program_name):
         path_list = os.environ['PATH']
         for d in path_list.split(os.path.pathsep):
@@ -51,12 +51,12 @@ class PostrExtension(nautilus.MenuProvider):
         if len(files) == 0:
             return
 
-        names = [ unquote(file.get_uri()[7:]) for file in files ]
+        names = [ file.get_uri() for file in files ]
 
         argv = [ PROGRAM_NAME ] + names
 
         # TODO: use startup notification
-        gobject.spawn_async(argv, flags=gobject.SPAWN_SEARCH_PATH)
+        GObject.spawn_async(argv, flags=GObject.SPAWN_SEARCH_PATH)
 
     def get_file_items(self, window, files):
         # Show the menu iif:
@@ -67,21 +67,27 @@ class PostrExtension(nautilus.MenuProvider):
         # - Postr is installed (is in PATH)
         if len(files) == 0:
             return
-        
-        for file in files:
-            if file.is_directory() or file.get_uri_scheme() != 'file':
+
+        for fd in files:
+            if fd.is_directory() or fd.get_uri_scheme() != 'file':
                 return
-            if not file.is_mime_type("image/*"):
+            if not fd.is_mime_type("image/*"):
                 return
 
         #self.program = self.locate_program(PROGRAM_NAME)
         #if not self.program:
         #    return
 
-        item = nautilus.MenuItem('PostrExtension::upload_files',
-                                 _('Upload to Flickr...'),
-                                 _('Upload the selected files into Flickr'),
-                                 "postr")
+        item = Nautilus.MenuItem(name='PostrExtension::upload_files',
+                                 label=_('Upload to Flickr...'),
+                                 tip=_('Upload the selected files into Flickr'),
+                                 icon="postr")
         item.connect('activate', self.upload_files, files)
 
         return item,
+
+    def get_background_items(self, window, files):
+        # If nothing is selected, Nautils still can show a contextual
+        # menu item.
+        # This method must exist even if we have nothing to offer here.
+        return
diff --git a/postr b/postr
index 1c14caa..248db5e 100755
--- a/postr
+++ b/postr
@@ -21,8 +21,8 @@ import gettext
 gettext.install('postr')
 
 import sys
-from twisted.internet import gtk2reactor
-reactor = gtk2reactor.install()
+from twisted.internet import gtk3reactor
+reactor = gtk3reactor.install()
 
 # Import from src first so that we can run directly from the source tree for
 # development.
diff --git a/src/AboutDialog.py b/src/AboutDialog.py
index c28e829..ee71ec2 100644
--- a/src/AboutDialog.py
+++ b/src/AboutDialog.py
@@ -1,6 +1,8 @@
 # Postr, a Flickr Uploader
+# -*- coding: utf-8 -*-
 #
 # Copyright (C) 2006-2008 Ross Burton <ross burtonini com>
+# Copyright (C) 2012 GermÃn Poo-CaamaÃo <gpoo gnome org>
 #
 # This program is free software; you can redistribute it and/or modify it under
 # the terms of the GNU General Public License as published by the Free Software
@@ -15,16 +17,18 @@
 # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 # St, Fifth Floor, Boston, MA 02110-1301 USA
 
-import gtk
+from gi.repository import Gtk, GObject
 from version import __version__
 
-class AboutDialog(gtk.AboutDialog):
+class AboutDialog(Gtk.AboutDialog):
     def __init__(self, parent=None):
-        gtk.AboutDialog.__init__(self)
+        Gtk.AboutDialog.__init__(self)
         self.set_transient_for(parent)
         self.set_name(_('Flickr Uploader'))
-        self.set_copyright(u'Copyright \u00A9 2006-2008 Ross Burton')
-        self.set_authors(('Ross Burton <ross burtonini com>',))
+        self.set_copyright(u'Copyright \u00A9 2006-2008 Ross Burton\n'
+                           u'Copyright \u00A9 2009-2012 GermÃn Poo-CaamaÃo')
+        self.set_authors(('Ross Burton <ross burtonini com>',
+                          'GermÃn Poo-CaamaÃo <gpoo gnome org>'))
         self.set_website('http://projects.gnome.org/postr/')
         self.set_logo_icon_name('postr')
         self.set_version (__version__)
@@ -32,6 +36,6 @@ class AboutDialog(gtk.AboutDialog):
 
 if __name__ == "__main__":
     import gettext; gettext.install('postr')
-    
+
     AboutDialog().show()
-    gtk.main()
+    Gtk.main()
diff --git a/src/AuthenticationDialog.py b/src/AuthenticationDialog.py
index e2fd53c..e4a0706 100644
--- a/src/AuthenticationDialog.py
+++ b/src/AuthenticationDialog.py
@@ -15,13 +15,14 @@
 # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 # St, Fifth Floor, Boston, MA 02110-1301 USA
 
-import os, gtk, gconf
+import os
+from gi.repository import Gtk, GConf, GObject
 
 def on_url_clicked(button, url):
     """Global LinkButton handler that starts the default GNOME HTTP handler, or
     firefox."""
     # Get the HTTP URL handler
-    client = gconf.client_get_default()
+    client = GConf.Client.get_default()
     browser = client.get_string("/desktop/gnome/url-handlers/http/command") or "firefox"
 
     # Because the world sucks and everyone hates me, just use the first word and
@@ -33,30 +34,30 @@ def on_url_clicked(button, url):
     os.spawnlp(os.P_NOWAIT, browser, browser, url)
     # TODO: if that didn't work fallback on x-www-browser or something
 
-class AuthenticationDialog(gtk.Dialog):
+class AuthenticationDialog(Gtk.Dialog):
     def __init__(self, parent, url):
-        gtk.Dialog.__init__(self,
+        Gtk.Dialog.__init__(self,
                             title=_("Flickr Uploader"), parent=parent,
-                            flags=gtk.DIALOG_NO_SEPARATOR,
-                            buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
-                                     _("Continue"), gtk.RESPONSE_ACCEPT))
-        vbox = gtk.VBox(spacing=8)
+                            buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT,
+                                     _("Continue"), Gtk.ResponseType.ACCEPT))
+        vbox = Gtk.VBox(spacing=8)
+
         vbox.set_border_width(8)
-        
-        label = gtk.Label(_("Postr needs to login to Flickr to upload your photos. "
+
+        label = Gtk.Label(_("Postr needs to login to Flickr to upload your photos. "
                           "Please click on the link below to login to Flickr."))
         label.set_line_wrap(True)
         vbox.add(label)
 
-        # gtk.LinkButton is only in 2.10, so use a normal button if it isn't
+        # Gtk.LinkButton is only in 2.10, so use a normal button if it isn't
         # available.
-        if hasattr(gtk, "LinkButton"):
-            gtk.link_button_set_uri_hook(on_url_clicked)
-            button = gtk.LinkButton(url, _("Login to Flickr"))
+        if hasattr(Gtk, "LinkButton"):
+            Gtk.link_button_set_uri_hook(on_url_clicked)
+            button = Gtk.LinkButton(url, _("Login to Flickr"))
         else:
-            button = gtk.Button(_("Login to Flickr"))
+            button = Gtk.Button(_("Login to Flickr"))
             button.connect("clicked", on_url_clicked, url)
         vbox.add(button)
-        
+
         self.vbox.add(vbox)
         self.show_all()
diff --git a/src/ContentTypeCombo.py b/src/ContentTypeCombo.py
index 3064b6d..50cb54e 100644
--- a/src/ContentTypeCombo.py
+++ b/src/ContentTypeCombo.py
@@ -15,22 +15,24 @@
 # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 # St, Fifth Floor, Boston, MA 02110-1301 USA
 
-import gobject, gtk
+from gi.repository import GObject, Gtk
+
+class ContentTypeCombo(Gtk.ComboBox):
+    __gtype_name__ = 'ContentTypeCombo'
 
-class ContentTypeCombo(gtk.ComboBox):
     def __init__(self):
-        gtk.ComboBox.__init__(self)
+        Gtk.ComboBox.__init__(self)
         # Name, content_type
-        model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_INT)
-        model.set(model.append(), 0, "Photo", 1, 1)
-        model.set(model.append(), 0, "Screenshot", 1, 2)
-        model.set(model.append(), 0, "Other", 1, 3)
+        model = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_INT)
+        model.append(['Photo', 1])
+        model.append(['Screenshot', 2])
+        model.append(['Other', 3])
         self.model = model
         self.set_model(model)
         self.set_active(0)
 
-        cell = gtk.CellRendererText()
-        self.pack_start(cell)
+        cell = Gtk.CellRendererText()
+        self.pack_start(cell, True)
         self.add_attribute(cell, "text", 0)
 
     def get_content_type_for_iter(self, it):
diff --git a/src/ErrorDialog.py b/src/ErrorDialog.py
index 32891f5..f6024d3 100644
--- a/src/ErrorDialog.py
+++ b/src/ErrorDialog.py
@@ -15,15 +15,17 @@
 # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 # St, Fifth Floor, Boston, MA 02110-1301 USA
 
-import gtk
+from gi.repository import Gtk, GObject
 
-class ErrorDialog(gtk.MessageDialog):
+class ErrorDialog(Gtk.MessageDialog):
     def __init__(self, parent=None):
-        gtk.MessageDialog.__init__(self, flags=gtk.DIALOG_DESTROY_WITH_PARENT,
-                                   type=gtk.MESSAGE_ERROR,
-                                   buttons=gtk.BUTTONS_OK,
+        Gtk.MessageDialog.__init__(self,
+                                   flags=Gtk.DialogFlags.DESTROY_WITH_PARENT,
+                                   type=Gtk.MessageType.ERROR,
+                                   buttons=Gtk.ButtonsType.OK,
                                    parent=parent,
                                    message_format=_("An error occurred"))
+        self.set_destroy_with_parent(True)
         self.connect("response", lambda dialog, response: dialog.destroy())
         self.expander = None
 
@@ -44,19 +46,19 @@ class ErrorDialog(gtk.MessageDialog):
     def add_details(self, message):
         # TODO: format nicer
         if not self.expander:
-            self.expander = gtk.Expander(_('Details'))
-            self.view = gtk.TextView();
+            self.expander = Gtk.Expander(_('Details'))
+            self.view = Gtk.TextView();
             self.buffer = self.view.get_buffer()
 
-            sw = gtk.ScrolledWindow()
-            sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
-            sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+            sw = Gtk.ScrolledWindow()
+            sw.set_shadow_type(Gtk.Shadow.ETCHED_IN)
+            sw.set_policy(Gtk.Policy.AUTOMATIC, Gtk.Policy.AUTOMATIC)
 
             sw.add(self.view)
 
             self.expander.add(sw)
             self.expander.show_all()
-            self.vbox.pack_start(self.expander)
+            self.vbox.pack_start(self.expander, True, True, 0)
 
 
         iter = self.buffer.get_end_iter()
diff --git a/src/GroupSelector.py b/src/GroupSelector.py
index bcfc97e..bf29365 100644
--- a/src/GroupSelector.py
+++ b/src/GroupSelector.py
@@ -15,7 +15,7 @@
 # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 # St, Fifth Floor, Boston, MA 02110-1301 USA
 
-import gobject, gtk, pango
+from gi.repository import Gtk, GObject, Pango, GdkPixbuf
 from ErrorDialog import ErrorDialog
 import util
 
@@ -24,65 +24,66 @@ import util
  COL_NAME,
  COL_ICON) = range(0, 4)
 
-class GroupSelector(gtk.TreeView):
-
+class GroupSelector(Gtk.TreeView):
+    __gtype_name__ = 'GroupSelector'
     __gsignals__ = {
-        'changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ())
+        'changed' : (GObject.SignalFlags.RUN_LAST, None, ())
         }
-    
-    def __init__(self, flickr):
-        self.flickr = flickr
-        self.model = gtk.ListStore(gobject.TYPE_BOOLEAN,
-                                   gobject.TYPE_STRING,
-                                   gobject.TYPE_STRING,
-                                   gtk.gdk.Pixbuf)
+
+    def __init__(self):
+        self.flickr = None
+        self.model = Gtk.ListStore(GObject.TYPE_BOOLEAN,
+                                   GObject.TYPE_STRING,
+                                   GObject.TYPE_STRING,
+                                   GdkPixbuf.Pixbuf)
         self.model.connect("row-changed", lambda model, path, iter: self.emit("changed"))
-        
-        gtk.TreeView.__init__(self, self.model)
-        
+
+        Gtk.TreeView.__init__(self, self.model)
+
         # Calculate the size of thumbnails based on the size of the text
         # renderer, but provide a default in case style-set isn't called.
         self.connect("style-set", self.style_set);
         self.thumb_size = 24
 
-        column = gtk.TreeViewColumn('Selected')
+        column = Gtk.TreeViewColumn('Selected')
         self.append_column(column)
-        
-        renderer =  gtk.CellRendererToggle()
+
+        renderer = Gtk.CellRendererToggle()
         def toggled(r, path):
             self.model[path][COL_SELECTED] = not r.get_active()
         renderer.connect("toggled", toggled)
         column.pack_start(renderer, False)
         column.add_attribute(renderer, "active", COL_SELECTED)
-        
-        column = gtk.TreeViewColumn('Group')
+
+        column = Gtk.TreeViewColumn('Group')
         self.append_column(column)
 
-        renderer =  gtk.CellRendererPixbuf()
+        renderer = Gtk.CellRendererPixbuf()
         column.pack_start(renderer, False)
         column.add_attribute(renderer, "pixbuf", COL_ICON)
-        
-        self.text_renderer =  gtk.CellRendererText()
+
+        self.text_renderer = Gtk.CellRendererText()
         column.pack_start(self.text_renderer, True)
         column.add_attribute(self.text_renderer, "text", COL_NAME)
-        
-        self.set_size_request(-1, 24 * 3 + self.style_get_property("vertical-separator") * 6)
+
+        # FIXME: Port to GTK3
+        # self.set_size_request(-1, 24 * 3 + self.style_get_property("vertical-separator") * 6)
         self.set_headers_visible(False)
         self.set_search_column(COL_NAME)
-        def search_func(model, column, key, iter):
+        def search_func(model, column, key, iter, user_data):
             s = model.get_value(iter, column)
             # This API is braindead, false=matches
             return key.lower() not in s.lower()
-        self.set_search_equal_func(search_func)
+        self.set_search_equal_func(search_func, None)
         # TODO: enable case insensitive substring searching
-    
+
     def style_set(self, widget, old_style):
         self.thumb_size = self.text_renderer.get_size(self, None)[3]
 
     def update(self):
         # TODO: block changed signals
         self.flickr.groups_pools_getGroups().addCallbacks(self.got_groups, self.twisted_error)
-    
+
     def got_groups(self, rsp):
         for group in rsp.findall("groups/group"):
             it = self.model.append()
@@ -92,7 +93,7 @@ class GroupSelector(gtk.TreeView):
             def got_thumb(thumb, it):
                 self.model.set (it, COL_ICON, thumb)
             util.get_buddyicon(self.flickr, group, self.thumb_size).addCallback(got_thumb, it)
-    
+
     def twisted_error(self, failure):
         dialog = ErrorDialog()
         dialog.set_from_failure(failure)
diff --git a/src/ImageList.py b/src/ImageList.py
index c1706c0..8d96a56 100644
--- a/src/ImageList.py
+++ b/src/ImageList.py
@@ -1,6 +1,8 @@
 # Postr, a Flickr Uploader
+# -*- coding: utf-8 -*-
 #
 # Copyright (C) 2006-2008 Ross Burton <ross burtonini com>
+# Copyright (C) 2012 GermÃn Poo-CaamaÃo <gpoo gnome org>
 #
 # This program is free software; you can redistribute it and/or modify it under
 # the terms of the GNU General Public License as published by the Free Software
@@ -15,8 +17,7 @@
 # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 # St, Fifth Floor, Boston, MA 02110-1301 USA
 
-import gtk
-import pango 
+from gi.repository import Gtk, Pango, GObject, Gdk
 
 import ImageStore
 
@@ -24,20 +25,22 @@ import ImageStore
 (DRAG_URI,
  DRAG_IMAGE) = range (0, 2)
 
-class ImageList(gtk.TreeView):
+class ImageList(Gtk.TreeView):
+    __gtype_name__ = 'ImageList'
+
     def __init__(self):
-        gtk.TreeView.__init__(self)
+        Gtk.TreeView.__init__(self)
 
-        column = gtk.TreeViewColumn('Preview', 
-                                     gtk.CellRendererPixbuf(),
+        column = Gtk.TreeViewColumn('Preview',
+                                    Gtk.CellRendererPixbuf(),
                                     pixbuf=ImageStore.COL_THUMBNAIL)
 
         self.append_column(column)
 
-        renderer =  gtk.CellRendererText()
-        renderer.set_property('ellipsize', pango.ELLIPSIZE_END) 
+        renderer = Gtk.CellRendererText()
+        renderer.set_property('ellipsize', Pango.EllipsizeMode.END)
 
-        column = gtk.TreeViewColumn('Info', renderer)
+        column = Gtk.TreeViewColumn('Info', renderer)
         column.set_cell_data_func(renderer, self.data_func)
         self.append_column(column)
 
@@ -45,27 +48,31 @@ class ImageList(gtk.TreeView):
         self.set_enable_search(False)
 
         selection = self.get_selection()
-        selection.set_mode(gtk.SELECTION_MULTIPLE)
+        selection.set_mode(Gtk.SelectionMode.MULTIPLE)
 
         # Setup the drag and drop
         self.targets = self.drag_dest_get_target_list()
-        self.targets = gtk.target_list_add_image_targets (self.targets, DRAG_IMAGE, False)
-        self.targets = gtk.target_list_add_uri_targets (self.targets, DRAG_URI)
-        self.drag_dest_set (gtk.DEST_DEFAULT_ALL, self.targets, gtk.gdk.ACTION_COPY)
+        if not self.targets:
+            self.targets = Gtk.TargetList.new([])
+        self.targets.add_image_targets (DRAG_IMAGE, True)
+        self.targets.add_uri_targets (DRAG_URI)
+        self.drag_dest_set (Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
+        self.drag_dest_set_target_list(self.targets)
 
     def enable_targets(self):
         """Enable the drag and drop destination. """
-        self.drag_dest_set(gtk.DEST_DEFAULT_ALL, self.targets, gtk.gdk.ACTION_COPY)
+        self.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
+        self.drag_dest_set_target_list(self.targets)
 
     def unable_targets(self):
         """Unable the drag and drop destination. """
         self.drag_dest_unset()
 
-    def data_func(self, column, cell, model, it):
+    def data_func(self, column, cell, model, it, data):
         from xml.sax.saxutils import escape
 
         (title, description, tags) = model.get(it, ImageStore.COL_TITLE, ImageStore.COL_DESCRIPTION, ImageStore.COL_TAGS)
-        
+
         if title:
             info_title = title
         else:
@@ -80,8 +87,7 @@ class ImageList(gtk.TreeView):
 
         s = "<b><big>%s</big></b>\n%s\n" % (escape (info_title), escape (info_desc))
         if tags:
-            colour = self.style.text[gtk.STATE_INSENSITIVE].pixel
-            s = s + "<span color='#%X'>%s</span>" % (colour, escape (tags))
-        
+            s = s + '%s' % (escape (tags))
+
         cell.set_property("markup", s)
 
diff --git a/src/ImageStore.py b/src/ImageStore.py
index 523c064..6b52bc1 100644
--- a/src/ImageStore.py
+++ b/src/ImageStore.py
@@ -15,7 +15,7 @@
 # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 # St, Fifth Floor, Boston, MA 02110-1301 USA
 
-import gobject, gtk
+from gi.repository import GObject, Gtk, GdkPixbuf
 
 # Column indexes
 (COL_URI, # The filename of an image (can be None)
@@ -35,23 +35,23 @@ import gobject, gtk
  COL_LICENSE # Iterator containing license
  ) = range (0, 15)
 
-class ImageStore (gtk.ListStore):
+class ImageStore (Gtk.ListStore):
     def __init__(self):
-        gtk.ListStore.__init__(self, gobject.TYPE_STRING, # COL_URI
-                               gobject.TYPE_INT, # COL_SIZE
-                               gtk.gdk.Pixbuf, # COL_IMAGE
-                               gtk.gdk.Pixbuf, # COL_PREVIEW
-                               gtk.gdk.Pixbuf,  #COL_THUMBNAIL
-                               gobject.TYPE_STRING, # COL_TITLE
-                               gobject.TYPE_STRING, # COL_DESCRIPTION
-                               gobject.TYPE_STRING, # COL_TAGS
-                               gtk.TreeIter, # COL_SET
+        Gtk.ListStore.__init__(self, GObject.TYPE_STRING, # COL_URI
+                               GObject.TYPE_LONG, # COL_SIZE
+                               GdkPixbuf.Pixbuf, # COL_IMAGE
+                               GdkPixbuf.Pixbuf, # COL_PREVIEW
+                               GdkPixbuf.Pixbuf,  #COL_THUMBNAIL
+                               GObject.TYPE_STRING, # COL_TITLE
+                               GObject.TYPE_STRING, # COL_DESCRIPTION
+                               GObject.TYPE_STRING, # COL_TAGS
+                               Gtk.TreeIter, # COL_SET
                                object, # COL_GROUPS
-                               gtk.TreeIter, # COL_PRIVACY
-                               gtk.TreeIter, # COL_SAFETY
-                               gobject.TYPE_BOOLEAN, # COL_VISIBLE
-                               gtk.TreeIter, # COL_CONTENT_TYPE
-                               gtk.TreeIter) # COL_LICENSE
+                               Gtk.TreeIter, # COL_PRIVACY
+                               Gtk.TreeIter, # COL_SAFETY
+                               GObject.TYPE_BOOLEAN, # COL_VISIBLE
+                               Gtk.TreeIter, # COL_CONTENT_TYPE
+                               Gtk.TreeIter) # COL_LICENSE
         self._dirty = False
         self.connect("row-changed", self._on_row_changed)
 
diff --git a/src/LicenseCombo.py b/src/LicenseCombo.py
index ae606d6..91aa7c9 100644
--- a/src/LicenseCombo.py
+++ b/src/LicenseCombo.py
@@ -15,20 +15,22 @@
 # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 # St, Fifth Floor, Boston, MA 02110-1301 USA
 
-import gobject, gtk
+from gi.repository import GObject, Gtk
 
-class LicenseCombo(gtk.ComboBox):
-    def __init__(self, flickr):
-        gtk.ComboBox.__init__(self)
-        self.flickr = flickr
+class LicenseCombo(Gtk.ComboBox):
+    __gtype_name__ = 'LicenseCombo'
+
+    def __init__(self):
+        Gtk.ComboBox.__init__(self)
+        self.flickr = None
         
-        self.model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_INT)
-        self.model.set(self.model.append(), 0, _("Default"), 1, -1)
+        self.model = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_INT)
+        self.model.append([_("Default"), -1])
         self.set_model(self.model)
         self.set_active(-1)
 
-        cell = gtk.CellRendererText()
-        self.pack_start(cell)
+        cell = Gtk.CellRendererText()
+        self.pack_start(cell, True)
         self.add_attribute(cell, "text", 0)
 
     def twisted_error(self, failure):
@@ -42,9 +44,8 @@ class LicenseCombo(gtk.ComboBox):
         for license in rsp.findall("licenses/license"):
             license_id = int(license.get("id"))
             it = self.model.append()
-            self.model.set(it,
-                           0, license.get("name"),
-                           1, license_id)
+            self.model.append([license.get("name"), license_id])
+
             # Set default license to All Rights Reserved.
             # I haven't found a way to get the default license
             # from flickr by the API.
diff --git a/src/PrivacyCombo.py b/src/PrivacyCombo.py
index 79c79da..44051c5 100644
--- a/src/PrivacyCombo.py
+++ b/src/PrivacyCombo.py
@@ -15,23 +15,25 @@
 # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 # St, Fifth Floor, Boston, MA 02110-1301 USA
 
-import gobject, gtk
+from gi.repository import Gtk, GObject
+
+class PrivacyCombo(Gtk.ComboBox):
+    __gtype_name__ = 'PrivacyCombo'
 
-class PrivacyCombo(gtk.ComboBox):
     def __init__(self):
-        gtk.ComboBox.__init__(self)
+        Gtk.ComboBox.__init__(self)
         # Name, is_public, is_family, is_friend
-        model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_BOOLEAN, gobject.TYPE_BOOLEAN, gobject.TYPE_BOOLEAN)
-        model.set(model.append(), 0, "Public", 1, True, 2, False, 3, False)
-        model.set(model.append(), 0, "Family Only", 1, False, 2, True, 3, False)
-        model.set(model.append(), 0, "Friends and Family Only", 1, False, 2, True, 3, True)
-        model.set(model.append(), 0, "Private", 1, False, 2, False, 3, False)
+        model = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_BOOLEAN, GObject.TYPE_BOOLEAN, GObject.TYPE_BOOLEAN)
+        model.append(["Public", True, False, False])
+        model.append(["Family Only", False, True, False])
+        model.append(["Friends and Family Only", False, True, True])
+        model.append(["Private", False, False, False])
         self.model = model
         self.set_model(model)
         self.set_active(0)
 
-        cell = gtk.CellRendererText()
-        self.pack_start(cell)
+        cell = Gtk.CellRendererText()
+        self.pack_start(cell, True)
         self.add_attribute(cell, "text", 0)
 
     # (is_public, is_family, is_friend)
diff --git a/src/ProgressDialog.py b/src/ProgressDialog.py
index 7fab482..5de412a 100644
--- a/src/ProgressDialog.py
+++ b/src/ProgressDialog.py
@@ -1,6 +1,8 @@
 # Postr, a Flickr Uploader
+# -*- coding: utf-8 -*-
 #
 # Copyright (C) 2006-2008 Ross Burton <ross burtonini com>
+# Copyright (C) 2012 GermÃn Poo-CaamaÃo <gpoo gnome org>
 #
 # This program is free software; you can redistribute it and/or modify it under
 # the terms of the GNU General Public License as published by the Free Software
@@ -15,48 +17,49 @@
 # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 # St, Fifth Floor, Boston, MA 02110-1301 USA
 
-import gtk
+from gi.repository import Gtk, GObject
 
-class ProgressDialog(gtk.Dialog):
+class ProgressDialog(Gtk.Dialog):
     def __init__(self, cancel_cb):
-        gtk.Dialog.__init__(self, title="", flags=gtk.DIALOG_NO_SEPARATOR)
+        Gtk.Dialog.__init__(self, title="")
         self.cancel_cb = cancel_cb
-        
+
         self.set_resizable(False)
-        self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
+        self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
         self.connect("response", self.on_response)
-        
-        vbox = gtk.VBox(False, 8)
+
+        vbox = Gtk.VBox(False, 8)
         vbox.set_border_width(8)
-        self.vbox.add(vbox)
-        
-        hbox = gtk.HBox(False, 8)
+        self.get_children()[0].add(vbox)
+
+        hbox = Gtk.HBox(False, 8)
         vbox.add (hbox)
 
-        self.thumbnail = gtk.Image()
+        self.thumbnail = Gtk.Image()
         hbox.pack_start (self.thumbnail, False, False, 0)
 
-        self.label = gtk.Label()
+        self.label = Gtk.Label()
         self.label.set_alignment (0.0, 0.0)
         hbox.pack_start (self.label, True, True, 0)
-        
-        self.image_progress = gtk.ProgressBar()
+
+        self.image_progress = Gtk.ProgressBar()
         vbox.add(self.image_progress)
 
         vbox.show_all()
 
     def on_response(self, dialog, response):
-        if response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+        if response == Gtk.ResponseType.CANCEL or response == Gtk.ResponseType.DELETE_EVENT:
             self.cancel_cb()
-    
+
 if __name__ == "__main__":
-    import gobject
-    d = ProgressDialog()
-    d.thumbnail.set_from_icon_name ("stock_internet", gtk.ICON_SIZE_DIALOG)
+    import gettext; gettext.install('postr')
+
+    d = ProgressDialog(Gtk.main_quit)
+    d.thumbnail.set_from_icon_name ("stock_internet", Gtk.IconSize.DIALOG)
     d.label.set_text(_("Uploading"))
     def pulse():
         d.image_progress.pulse()
         return True
-    gobject.timeout_add(200, pulse)
+    GObject.timeout_add(200, pulse)
     d.show()
-    gtk.main()
+    Gtk.main()
diff --git a/src/PyUnique.py b/src/PyUnique.py
index ad9d981..907957e 100644
--- a/src/PyUnique.py
+++ b/src/PyUnique.py
@@ -20,11 +20,11 @@
 #
 #
 
-import gobject
+from gi.repository import GObject
 import dbus
 import dbus.service
 from dbus.mainloop.glib import DBusGMainLoop
-from gtk import gdk
+from gi.repository import Gdk
 import time
 
 # Set the glib main loop as the default main loop for dbus
@@ -64,29 +64,29 @@ class UniqueDBusObject(dbus.service.Object):
         self.app.emit('message-received', command, data)
         return "OK"
     
-class UniqueApp(gobject.GObject):
+class UniqueApp(GObject.GObject):
     """ Base class for every single instance application."""
 
     __gproperties__ = {
 
-        'is-running': (gobject.TYPE_BOOLEAN, 'is-running', 'is-running',
+        'is-running': (GObject.TYPE_BOOLEAN, 'is-running', 'is-running',
                        False,
-                       gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT),
-        'name': (gobject.TYPE_STRING, 'program name', 'program name',
-                 None, gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT),
-        'screen': (gobject.TYPE_OBJECT, 'screen of app', 'screen of app',
-                   gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT),
-        'startup-id': (gobject.TYPE_STRING, 'startup notification id',
+                       GObject.PARAM_READWRITE | GObject.PARAM_CONSTRUCT),
+        'name': (GObject.TYPE_STRING, 'program name', 'program name',
+                 None, GObject.PARAM_READWRITE | GObject.PARAM_CONSTRUCT),
+        'screen': (GObject.TYPE_OBJECT, 'screen of app', 'screen of app',
+                   GObject.PARAM_READWRITE | GObject.PARAM_CONSTRUCT),
+        'startup-id': (GObject.TYPE_STRING, 'startup notification id',
                        'startup notification id',
-                       None, gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT),
+                       None, GObject.PARAM_READWRITE | GObject.PARAM_CONSTRUCT),
         }
 
     __gsignals__ = {
-        'message-received': (gobject.SIGNAL_RUN_LAST |
-                             gobject.SIGNAL_NO_RECURSE,
-                             gobject.TYPE_INT,        # out: integer
-                             (gobject.TYPE_INT,       # in:  command id
-                              gobject.TYPE_STRING)),  # in:  command data
+        'message-received': (GObject.SignalFlags.RUN_LAST |
+                             GObject.SignalFlags.NO_RECURSE,
+                             GObject.TYPE_INT,        # out: integer
+                             (GObject.TYPE_INT,       # in:  command id
+                              GObject.TYPE_STRING)),  # in:  command data
         }
     
     # Default commands available to UniqueApp instances. More commands
@@ -98,11 +98,11 @@ class UniqueApp(gobject.GObject):
                 'CLOSE':    -4}
     
     def __init__(self, name, startup_id=None):
-        gobject.GObject.__init__(self)
+        GObject.GObject.__init__(self)
         
         self._is_running = False
         self._name = name
-        self._screen = gdk.screen_get_default()
+        self._screen = Gdk.Screen.get_default()
 
         # TODO: Find out what the startup_id is meant to be.
         self._startup_id = startup_id
diff --git a/src/SafetyCombo.py b/src/SafetyCombo.py
index 3191137..23f0c79 100644
--- a/src/SafetyCombo.py
+++ b/src/SafetyCombo.py
@@ -15,22 +15,24 @@
 # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 # St, Fifth Floor, Boston, MA 02110-1301 USA
 
-import gobject, gtk
+from gi.repository import GObject, Gtk
+
+class SafetyCombo(Gtk.ComboBox):
+    __gtype_name__ = 'SafetyCombo'
 
-class SafetyCombo(gtk.ComboBox):
     def __init__(self):
-        gtk.ComboBox.__init__(self)
+        Gtk.ComboBox.__init__(self)
         # Name, is_public, is_family, is_friend
-        model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_INT)
-        model.set(model.append(), 0, "Safe", 1, 1)
-        model.set(model.append(), 0, "Moderate", 1, 2)
-        model.set(model.append(), 0, "Restricted", 1, 3)
+        model = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_INT)
+        model.append(["Safe", 1])
+        model.append(["Moderate", 2])
+        model.append(["Restricted", 3])
         self.model = model
         self.set_model(model)
         self.set_active(0)
 
-        cell = gtk.CellRendererText()
-        self.pack_start(cell)
+        cell = Gtk.CellRendererText()
+        self.pack_start(cell, True)
         self.add_attribute(cell, "text", 0)
 
     def get_safety_for_iter(self, it):
diff --git a/src/SetCombo.py b/src/SetCombo.py
index b67fbe2..3b5cc1e 100644
--- a/src/SetCombo.py
+++ b/src/SetCombo.py
@@ -1,6 +1,8 @@
 # Postr, a Flickr Uploader
+# -*- coding: utf-8 -*-
 #
 # Copyright (C) 2006-2008 Ross Burton <ross burtonini com>
+# Copyright (C) 2012 GermÃn Poo-CaamaÃo <gpoo gnome org>
 #
 # This program is free software; you can redistribute it and/or modify it under
 # the terms of the GNU General Public License as published by the Free Software
@@ -16,7 +18,7 @@
 # St, Fifth Floor, Boston, MA 02110-1301 USA
 
 import datetime
-import gobject, gtk
+from gi.repository import GObject, Gtk, GdkPixbuf
 from twisted.web.client import getPage
 
 _NO_PHOTOSET_ID = "-1"
@@ -26,41 +28,43 @@ _DEFAULT_NEW_PHOTOSET_NAME = datetime.datetime.strftime(datetime.datetime.today(
                                                         _("new photoset (%m-%d-%y)"))
 
 # Column Indexes
-( COL_SETID,
+(COL_SETID,
   COL_SETLABEL,
-  COL_THUMBNAIL ) = range(0, 3)
+  COL_THUMBNAIL) = range(0, 3)
+
+class SetCombo(Gtk.ComboBox):
+    __gtype_name__ = 'SetCombo'
+
+    def __init__(self):
+        Gtk.ComboBox.__init__(self)
+        self.flickr = None
 
-class SetCombo(gtk.ComboBox):
-    def __init__(self, flickr):
-        gtk.ComboBox.__init__(self)
-        self.flickr = flickr
-        
         # Calculate the size of thumbnails based on the size of the text
         # renderer, but provide a default in case style-set isn't called.
+        self.text_renderer = Gtk.CellRendererText()
         self.connect("style-set", self.style_set)
         self.thumb_size = 24
 
         # ID, name, thumbnail
-        self.model =  gtk.ListStore (gobject.TYPE_STRING, gobject.TYPE_STRING, gtk.gdk.Pixbuf)
+        self.model = Gtk.ListStore (GObject.TYPE_STRING, GObject.TYPE_STRING, GdkPixbuf.Pixbuf)
         self.model.set (self.model.append(),
-                        COL_SETID, None,
+                        COL_SETID, _NO_PHOTOSET_ID,
                         COL_SETLABEL, _NO_PHOTOSET_LABEL)
         self._create_new_photoset_iter()
 
         self.set_model(self.model)
         self.set_active (-1)
 
-        renderer = gtk.CellRendererPixbuf()
+        renderer = Gtk.CellRendererPixbuf()
         self.pack_start (renderer, expand=False)
-        self.set_attributes(renderer, pixbuf=COL_THUMBNAIL)
-        
-        self.text_renderer = gtk.CellRendererText()
+        self.add_attribute(renderer, 'pixbuf', COL_THUMBNAIL)
+
         self.pack_start (self.text_renderer, expand=False)
-        self.set_attributes(self.text_renderer, text=COL_SETLABEL)
+        self.add_attribute(self.text_renderer, 'text', COL_SETLABEL)
 
     def style_set(self, widget, old_style):
         self.thumb_size = self.text_renderer.get_size(self, None)[3]
-    
+
     def twisted_error(self, failure):
         from ErrorDialog import ErrorDialog
         dialog = ErrorDialog()
@@ -68,12 +72,12 @@ class SetCombo(gtk.ComboBox):
         dialog.show_all()
 
     def __got_set_thumb(self, page, it):
-        loader = gtk.gdk.PixbufLoader()
+        loader = GdkPixbuf.PixbufLoader()
         loader.set_size (self.thumb_size, self.thumb_size)
         loader.write(page)
         loader.close()
         self.model.set (it, COL_THUMBNAIL, loader.get_pixbuf())
-    
+
     def __got_photosets(self, rsp):
         """Callback for the photosets.getList call"""
         for photoset in rsp.findall("photosets/photoset"):
@@ -123,24 +127,24 @@ class SetCombo(gtk.ComboBox):
     def _response_to_dialog(self, entry, dialog, response):
         dialog.response(response)
 
-    def name_new_photoset(self):
-        dialog = gtk.MessageDialog(None,
-                                   gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
-                                   gtk.MESSAGE_QUESTION,
-                                   gtk.BUTTONS_OK_CANCEL,
+    def name_new_photoset(self, window=None):
+        dialog = Gtk.MessageDialog(window,
+                                   Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
+                                   Gtk.MessageType.QUESTION,
+                                   Gtk.ButtonsType.OK_CANCEL,
                                    None)
         dialog.set_markup(_("Name for the new photoset:"))
-        entry = gtk.Entry()
+        entry = Gtk.Entry()
         entry.set_text(self.new_photoset_name)
         # so that you can press 'enter' to close dialog
-        entry.connect("activate", self._response_to_dialog, dialog, gtk.RESPONSE_OK)
+        entry.connect("activate", self._response_to_dialog, dialog, Gtk.ResponseType.OK)
         dialog.vbox.pack_end(entry, True, True, 0)
         dialog.show_all()
 
         response = dialog.run()
         text = entry.get_text()
         dialog.destroy()
-        if response == gtk.RESPONSE_OK:
+        if response == Gtk.ResponseType.OK:
             self.update_new_photoset(text.strip())
         return self.new_photoset_name
 
diff --git a/src/StatusBar.py b/src/StatusBar.py
index ee37a38..d0f956a 100644
--- a/src/StatusBar.py
+++ b/src/StatusBar.py
@@ -15,16 +15,18 @@
 # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 # St, Fifth Floor, Boston, MA 02110-1301 USA
 
-import gtk
+from gi.repository import Gtk, GObject
 from ErrorDialog import ErrorDialog
 from util import greek
 from xml.sax.saxutils import escape
 
-class StatusBar(gtk.Label):
-    def __init__(self, flickr):
-        gtk.Label.__init__(self)
+class StatusBar(Gtk.Label):
+    __gtype_name__ = 'StatusBar'
+
+    def __init__(self):
+        Gtk.Label.__init__(self)
+        self.flickr = None
         self.set_alignment(0.0, 0.5)
-        self.flickr = flickr
         self.quota = None
         self.to_upload = None
         # In case we are offline or we can not get the max file size to
diff --git a/src/TagsEntry.py b/src/TagsEntry.py
index 9fa4fd0..abf6341 100644
--- a/src/TagsEntry.py
+++ b/src/TagsEntry.py
@@ -15,20 +15,21 @@
 # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 # St, Fifth Floor, Boston, MA 02110-1301 USA
 
-import gtk
+from gi.repository import Gtk, GObject
 
 _USER_POPULAR_TAGS = 200
 _HOTS_TAGS = 20
 _COL_TAG_NAME = 0
 
-class TagsEntry(gtk.Entry):
-    def __init__(self, flickr):
-        gtk.Entry.__init__(self)
+class TagsEntry(Gtk.Entry):
+    __gtype_name__ = 'TagsEntry'
 
-        self.flickr = flickr
+    def __init__(self):
+        Gtk.Entry.__init__(self)
+        self.flickr = None
 
         # Create the completion object
-        self.completion = gtk.EntryCompletion()
+        self.completion = Gtk.EntryCompletion()
         self.completion.set_match_func(self.__match_func, None)
         self.completion.connect('match-selected', self.on_completion_match)
 
@@ -41,7 +42,7 @@ class TagsEntry(gtk.Entry):
         self.completion.set_minimum_key_length(1)
 
 
-        self.completion_model = gtk.ListStore(str)
+        self.completion_model = Gtk.ListStore(str)
 
         self.show_all()
 
@@ -98,9 +99,7 @@ class TagsEntry(gtk.Entry):
         '''
 
         for tag in rsp.getiterator('tag'):
-            self.completion_model.set(self.completion_model.append(),
-                                    _COL_TAG_NAME,
-                                    tag.text)
+            self.completion_model.append([tag.text])
 
         self.completion.set_model(self.completion_model)
 
diff --git a/src/catalog_poster.xml b/src/catalog_poster.xml
new file mode 100644
index 0000000..43b3207
--- /dev/null
+++ b/src/catalog_poster.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<glade-catalog name="postr" depends="gtk+" version="1.0">
+  <glade-widget-classes>
+    <glade-widget-class title="ContentTypeCombo" name="ContentTypeCombo"
+                        generic-name="ContentTypeCombo" parent="GtkComboBox"
+                        icon-name="widget-gtk-combobox" />
+    <glade-widget-class title="GroupSelector" name="GroupSelector"
+                        generic-name="GroupSelector" parent="GtkTreeView"
+                        icon-name="widget-gtk-treeview" />
+    <glade-widget-class title="ImageList" name="ImageList"
+                        generic-name="ImageList" parent="GtkTreeView"
+                        icon-name="widget-gtk-treeview" />
+    <glade-widget-class title="LicenseCombo" name="LicenseCombo"
+                        generic-name="LicenseCombo" parent="GtkComboBox"
+                        icon-name="widget-gtk-combobox" />
+    <glade-widget-class title="PrivacyCombo" name="PrivacyCombo"
+                        generic-name="PrivacyCombo" parent="GtkComboBox"
+                        icon-name="widget-gtk-combobox" />
+    <glade-widget-class title="SafetyCombo" name="SafetyCombo"
+                        generic-name="SafetyCombo" parent="GtkComboBox"
+                        icon-name="widget-gtk-combobox" />
+    <glade-widget-class title="SetCombo" name="SetCombo"
+                        generic-name="SetCombo" parent="GtkComboBox"
+                        icon-name="widget-gtk-combobox" />
+    <glade-widget-class title="StatusBar" name="StatusBar"
+                        generic-name="StatusBar" parent="GtkLabel"
+                        icon-name="widget-gtk-label" />
+    <glade-widget-class title="TagsEntry" name="TagsEntry"
+                        generic-name="TagsEntry" parent="GtkEntry"
+                        icon-name="widget-gtk-entry" />
+  </glade-widget-classes>
+
+  <glade-widget-group name="postr-widgets" title="Postr Custom Widgets">
+    <glade-widget-class-ref name="ContentTypeCombo"/>
+    <glade-widget-class-ref name="GroupSelector"/>
+    <glade-widget-class-ref name="ImageList"/>
+    <glade-widget-class-ref name="LicenseCombo"/>
+    <glade-widget-class-ref name="PrivacyCombo"/>
+    <glade-widget-class-ref name="SafetyCombo"/>
+    <glade-widget-class-ref name="StatusBar"/>
+    <glade-widget-class-ref name="SetCombo"/>
+    <glade-widget-class-ref name="TagsEntry"/>
+  </glade-widget-group>
+
+</glade-catalog>
diff --git a/src/flickrest.py b/src/flickrest.py
index abf256a..9980dfd 100644
--- a/src/flickrest.py
+++ b/src/flickrest.py
@@ -16,7 +16,7 @@
 # St, Fifth Floor, Boston, MA 02110-1301 USA
 
 import logging, os, mimetools, urllib
-import gio
+from gi.repository import Gio
 from twisted.internet import defer
 from twisted.python.failure import Failure
 import proxyclient as client
@@ -145,13 +145,13 @@ class Flickr:
         for key, val in inputs.items():
             lines.append("--" + boundary.encode("utf-8"))
             header = 'Content-Disposition: form-data; name="%s";' % key
-            if isinstance(val, gio.File):
+            if isinstance(val, Gio.File):
                 header += 'filename="%s";' % val.get_basename()
                 lines.append(header)
                 header = "Content-Type: application/octet-stream"
             lines.append(header)
             lines.append("")
-            if isinstance(val, gio.File):
+            if isinstance(val, Gio.File):
                 contents, length, etags = val.load_contents()
                 lines.append(contents)
             # Otherwise just hope it is string-like and encode it to
@@ -198,7 +198,7 @@ class Flickr:
         if imageData:
             kwargs['photo'] = imageData
         else:
-            kwargs['photo'] = gio.File(uri)
+            kwargs['photo'] = Gio.File.new_for_uri(uri)
 
         (boundary, form) = self.__encodeForm(kwargs)
         headers= {
diff --git a/src/postr.glade b/src/postr.glade
index f1c1053..b8bf270 100644
--- a/src/postr.glade
+++ b/src/postr.glade
@@ -1,198 +1,243 @@
-<?xml version="1.0"?>
-<glade-interface>
-  <!-- interface-requires gtk+ 2.10 -->
-  <!-- interface-naming-policy toplevel-contextual -->
-  <widget class="GtkWindow" id="window">
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <!-- interface-requires postr 1.0 -->
+  <object class="GtkAccelGroup" id="accelgroup1"/>
+  <object class="GtkImage" id="image1">
     <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="stock">gtk-open</property>
+  </object>
+  <object class="GtkImage" id="image3">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="yalign">0.49000000953674316</property>
+    <property name="stock">gtk-remove</property>
+  </object>
+  <object class="GtkImage" id="image4">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="stock">gtk-save</property>
+  </object>
+  <object class="GtkWindow" id="window">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
     <property name="title" translatable="yes">Flickr Uploader</property>
     <property name="default_width">640</property>
     <property name="default_height">350</property>
-    <signal name="delete_event" handler="on_quit_activate"/>
+    <accel-groups>
+      <group name="accelgroup1"/>
+    </accel-groups>
+    <signal name="delete-event" handler="on_quit_activate" swapped="no"/>
     <child>
-      <widget class="GtkVBox" id="vbox1">
+      <object class="GtkVBox" id="vbox1">
         <property name="visible">True</property>
+        <property name="can_focus">False</property>
         <child>
-          <widget class="GtkMenuBar" id="menubar1">
+          <object class="GtkMenuBar" id="menubar1">
             <property name="visible">True</property>
+            <property name="can_focus">False</property>
             <child>
-              <widget class="GtkMenuItem" id="menuitem1">
+              <object class="GtkMenuItem" id="menuitem1">
+                <property name="use_action_appearance">False</property>
                 <property name="visible">True</property>
+                <property name="can_focus">False</property>
                 <property name="label" translatable="yes">_File</property>
                 <property name="use_underline">True</property>
-                <child>
-                  <widget class="GtkMenu" id="menuitem1_menu">
+                <child type="submenu">
+                  <object class="GtkMenu" id="menuitem1_menu">
+                    <property name="can_focus">False</property>
                     <child>
-                      <widget class="GtkImageMenuItem" id="add_photos">
+                      <object class="GtkImageMenuItem" id="add_photos">
                         <property name="label" translatable="yes">_Add Photos...</property>
+                        <property name="use_action_appearance">False</property>
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="use_underline">True</property>
+                        <property name="image">image1</property>
                         <property name="use_stock">False</property>
-                        <signal name="activate" handler="on_add_photos_activate"/>
                         <accelerator key="O" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-                        <child internal-child="image">
-                          <widget class="GtkImage" id="image1">
-                            <property name="visible">True</property>
-                            <property name="stock">gtk-open</property>
-                          </widget>
-                        </child>
-                      </widget>
+                        <signal name="activate" handler="on_add_photos_activate" swapped="no"/>
+                      </object>
                     </child>
                     <child>
-                      <widget class="GtkImageMenuItem" id="remove_menu">
+                      <object class="GtkImageMenuItem" id="remove_menu">
                         <property name="label" translatable="yes">_Remove Photos</property>
+                        <property name="use_action_appearance">False</property>
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="use_underline">True</property>
+                        <property name="image">image3</property>
                         <property name="use_stock">False</property>
-                        <signal name="activate" handler="on_remove_activate"/>
                         <accelerator key="D" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-                        <child internal-child="image">
-                          <widget class="GtkImage" id="image3">
-                            <property name="visible">True</property>
-                            <property name="yalign">0.49000000953674316</property>
-                            <property name="stock">gtk-remove</property>
-                          </widget>
-                        </child>
-                      </widget>
+                        <signal name="activate" handler="on_remove_activate" swapped="no"/>
+                      </object>
                     </child>
                     <child>
-                      <widget class="GtkSeparatorMenuItem" id="separator2">
+                      <object class="GtkSeparatorMenuItem" id="separator2">
                         <property name="visible">True</property>
-                      </widget>
+                        <property name="can_focus">False</property>
+                      </object>
                     </child>
                     <child>
-                      <widget class="GtkImageMenuItem" id="save_session_menu">
+                      <object class="GtkImageMenuItem" id="save_session_menu">
                         <property name="label" translatable="yes">_Save session</property>
+                        <property name="use_action_appearance">False</property>
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="use_underline">True</property>
+                        <property name="image">image4</property>
                         <property name="use_stock">False</property>
-                        <signal name="activate" handler="on_save_session_activate"/>
                         <accelerator key="S" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-                        <child internal-child="image">
-                          <widget class="GtkImage" id="image4">
-                            <property name="visible">True</property>
-                            <property name="stock">gtk-save</property>
-                          </widget>
-                        </child>
-                      </widget>
+                        <signal name="activate" handler="on_save_session_activate" swapped="no"/>
+                      </object>
                     </child>
                     <child>
-                      <widget class="GtkMenuItem" id="load_session_menu">
+                      <object class="GtkMenuItem" id="load_session_menu">
+                        <property name="use_action_appearance">False</property>
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="label" translatable="yes">_Load session</property>
                         <property name="use_underline">True</property>
-                        <signal name="activate" handler="on_load_session_activate"/>
                         <accelerator key="L" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-                      </widget>
+                        <signal name="activate" handler="on_load_session_activate" swapped="no"/>
+                      </object>
                     </child>
                     <child>
-                      <widget class="GtkSeparatorMenuItem" id="separator3">
+                      <object class="GtkSeparatorMenuItem" id="separator3">
                         <property name="visible">True</property>
-                      </widget>
+                        <property name="can_focus">False</property>
+                      </object>
                     </child>
                     <child>
-                      <widget class="GtkMenuItem" id="switch_menu">
+                      <object class="GtkMenuItem" id="switch_menu">
+                        <property name="use_action_appearance">False</property>
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="label" translatable="yes">_Switch user...</property>
                         <property name="use_underline">True</property>
-                        <signal name="activate" handler="on_switch_activate"/>
-                      </widget>
+                        <signal name="activate" handler="on_switch_activate" swapped="no"/>
+                      </object>
                     </child>
                     <child>
-                      <widget class="GtkMenuItem" id="upload_menu">
+                      <object class="GtkMenuItem" id="upload_menu">
+                        <property name="use_action_appearance">False</property>
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="label" translatable="yes">_Upload</property>
                         <property name="use_underline">True</property>
-                        <signal name="activate" handler="on_upload_activate"/>
-                      </widget>
+                        <signal name="activate" handler="on_upload_activate" swapped="no"/>
+                      </object>
                     </child>
                     <child>
-                      <widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
+                      <object class="GtkSeparatorMenuItem" id="separatormenuitem1">
                         <property name="visible">True</property>
-                      </widget>
+                        <property name="can_focus">False</property>
+                      </object>
                     </child>
                     <child>
-                      <widget class="GtkImageMenuItem" id="quit">
+                      <object class="GtkImageMenuItem" id="quit">
                         <property name="label">gtk-quit</property>
+                        <property name="use_action_appearance">False</property>
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="use_underline">True</property>
                         <property name="use_stock">True</property>
-                        <signal name="activate" handler="on_quit_activate"/>
-                      </widget>
+                        <property name="accel_group">accelgroup1</property>
+                        <signal name="activate" handler="on_quit_activate" swapped="no"/>
+                      </object>
                     </child>
-                  </widget>
+                  </object>
                 </child>
-              </widget>
+              </object>
             </child>
             <child>
-              <widget class="GtkMenuItem" id="select2">
+              <object class="GtkMenuItem" id="select2">
+                <property name="use_action_appearance">False</property>
                 <property name="visible">True</property>
+                <property name="can_focus">False</property>
                 <property name="label" translatable="yes">Select</property>
                 <property name="use_underline">True</property>
-                <signal name="activate" handler="on_select2_activate"/>
-                <child>
-                  <widget class="GtkMenu" id="select2_menu">
+                <child type="submenu">
+                  <object class="GtkMenu" id="select2_menu">
+                    <property name="can_focus">False</property>
                     <child>
-                      <widget class="GtkImageMenuItem" id="select_all">
+                      <object class="GtkImageMenuItem" id="select_all">
                         <property name="label">gtk-select-all</property>
+                        <property name="use_action_appearance">False</property>
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="use_underline">True</property>
                         <property name="use_stock">True</property>
-                        <signal name="activate" handler="on_select_all_activate"/>
+                        <property name="accel_group">accelgroup1</property>
                         <accelerator key="E" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-                      </widget>
+                        <signal name="activate" handler="on_select_all_activate" swapped="no"/>
+                      </object>
                     </child>
                     <child>
-                      <widget class="GtkMenuItem" id="deselect_all">
+                      <object class="GtkMenuItem" id="deselect_all">
+                        <property name="use_action_appearance">False</property>
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="label" translatable="yes">Dese_lect All</property>
                         <property name="use_underline">True</property>
-                        <signal name="activate" handler="on_deselect_all_activate"/>
                         <accelerator key="E" signal="activate" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/>
-                      </widget>
+                        <signal name="activate" handler="on_deselect_all_activate" swapped="no"/>
+                      </object>
                     </child>
                     <child>
-                      <widget class="GtkMenuItem" id="invert_selection">
+                      <object class="GtkMenuItem" id="invert_selection">
+                        <property name="use_action_appearance">False</property>
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="label" translatable="yes">_Invert Selection</property>
                         <property name="use_underline">True</property>
-                        <signal name="activate" handler="on_invert_selection_activate"/>
                         <accelerator key="I" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-                      </widget>
+                        <signal name="activate" handler="on_invert_selection_activate" swapped="no"/>
+                      </object>
                     </child>
-                  </widget>
+                  </object>
                 </child>
-              </widget>
+              </object>
             </child>
             <child>
-              <widget class="GtkMenuItem" id="menuitem4">
+              <object class="GtkMenuItem" id="menuitem4">
+                <property name="use_action_appearance">False</property>
                 <property name="visible">True</property>
+                <property name="can_focus">False</property>
                 <property name="label" translatable="yes">_Help</property>
                 <property name="use_underline">True</property>
-                <child>
-                  <widget class="GtkMenu" id="menuitem4_menu">
+                <child type="submenu">
+                  <object class="GtkMenu" id="menuitem4_menu">
+                    <property name="can_focus">False</property>
                     <child>
-                      <widget class="GtkImageMenuItem" id="help">
-                        <property name="stock_id">gtk-help</property>
-                        <property name="label" translatable="True">_Contents</property>
+                      <object class="GtkImageMenuItem" id="help">
+                        <property name="label" translatable="yes">_Contents</property>
+                        <property name="use_action_appearance">False</property>
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="use_underline">True</property>
-                        <signal name="activate" handler="on_help_activate"/>
-                      </widget>
+                        <property name="use_stock">False</property>
+                        <signal name="activate" handler="on_help_activate" swapped="no"/>
+                      </object>
                     </child>
                     <child>
-                      <widget class="GtkImageMenuItem" id="about">
+                      <object class="GtkImageMenuItem" id="about">
                         <property name="label">gtk-about</property>
+                        <property name="use_action_appearance">False</property>
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="use_underline">True</property>
                         <property name="use_stock">True</property>
-                        <signal name="activate" handler="on_about_activate"/>
-                      </widget>
+                        <property name="accel_group">accelgroup1</property>
+                        <signal name="activate" handler="on_about_activate" swapped="no"/>
+                      </object>
                     </child>
-                  </widget>
+                  </object>
                 </child>
-              </widget>
+              </object>
             </child>
-          </widget>
+          </object>
           <packing>
             <property name="expand">False</property>
             <property name="fill">False</property>
@@ -200,24 +245,27 @@
           </packing>
         </child>
         <child>
-          <widget class="GtkEventBox" id="statusbar_box">
+          <object class="GtkEventBox" id="statusbar_box">
             <property name="visible">True</property>
             <property name="app_paintable">True</property>
+            <property name="can_focus">False</property>
             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-            <signal name="expose_event" handler="on_statusbar_box_expose"/>
+            <signal name="draw" handler="on_statusbar_box_draw" swapped="no"/>
             <child>
-              <widget class="GtkHBox" id="hbox">
+              <object class="GtkHBox" id="hbox">
                 <property name="visible">True</property>
+                <property name="can_focus">False</property>
                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                 <property name="border_width">4</property>
                 <property name="spacing">4</property>
                 <child>
-                  <widget class="GtkImage" id="avatar_image">
+                  <object class="GtkImage" id="avatar_image">
                     <property name="visible">True</property>
+                    <property name="can_focus">False</property>
                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                     <property name="stock">gtk-missing-image</property>
                     <property name="icon-size">5</property>
-                  </widget>
+                  </object>
                   <packing>
                     <property name="expand">False</property>
                     <property name="fill">False</property>
@@ -225,58 +273,69 @@
                   </packing>
                 </child>
                 <child>
-                  <widget class="Custom" id="statusbar">
+                  <object class="StatusBar" id="statusbar">
                     <property name="visible">True</property>
+                    <property name="can_focus">False</property>
                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="creation_function">status_bar_new</property>
-                  </widget>
+                  </object>
                   <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
                     <property name="position">1</property>
                   </packing>
                 </child>
                 <child>
-                  <widget class="GtkVButtonBox" id="vbuttonbox1">
+                  <object class="GtkVButtonBox" id="vbuttonbox1">
                     <property name="visible">True</property>
+                    <property name="can_focus">False</property>
                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                     <child>
-                      <widget class="GtkButton" id="upload_button">
+                      <object class="GtkButton" id="upload_button">
+                        <property name="use_action_appearance">False</property>
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
                         <property name="receives_default">True</property>
                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <signal name="clicked" handler="on_upload_activate"/>
+                        <property name="use_action_appearance">False</property>
+                        <signal name="clicked" handler="on_upload_activate" swapped="no"/>
                         <child>
-                          <widget class="GtkHBox" id="hbox2">
+                          <object class="GtkHBox" id="hbox2">
                             <property name="visible">True</property>
+                            <property name="can_focus">False</property>
                             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                             <property name="border_width">2</property>
                             <property name="spacing">6</property>
                             <child>
-                              <widget class="GtkImage" id="image2">
+                              <object class="GtkImage" id="image2">
                                 <property name="visible">True</property>
+                                <property name="can_focus">False</property>
                                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                                 <property name="stock">gtk-connect</property>
-                              </widget>
+                              </object>
                               <packing>
                                 <property name="expand">False</property>
+                                <property name="fill">True</property>
                                 <property name="position">0</property>
                               </packing>
                             </child>
                             <child>
-                              <widget class="GtkLabel" id="label2">
+                              <object class="GtkLabel" id="label2">
                                 <property name="visible">True</property>
+                                <property name="can_focus">False</property>
                                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                                 <property name="label" translatable="yes">_Upload</property>
                                 <property name="use_underline">True</property>
                                 <property name="mnemonic_widget">upload_button</property>
-                              </widget>
+                              </object>
                               <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
                                 <property name="position">1</property>
                               </packing>
                             </child>
-                          </widget>
+                          </object>
                         </child>
-                      </widget>
+                      </object>
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">False</property>
@@ -284,16 +343,16 @@
                         <property name="position">0</property>
                       </packing>
                     </child>
-                  </widget>
+                  </object>
                   <packing>
                     <property name="expand">False</property>
                     <property name="fill">False</property>
                     <property name="position">2</property>
                   </packing>
                 </child>
-              </widget>
+              </object>
             </child>
-          </widget>
+          </object>
           <packing>
             <property name="expand">False</property>
             <property name="fill">False</property>
@@ -301,464 +360,481 @@
           </packing>
         </child>
         <child>
-          <widget class="GtkHPaned" id="hpaned1">
+          <object class="GtkHPaned" id="hpaned1">
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <property name="position">200</property>
             <child>
-              <widget class="GtkVBox" id="vbox2">
+              <object class="GtkVBox" id="vbox2">
                 <property name="visible">True</property>
+                <property name="can_focus">False</property>
                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                 <child>
-                  <widget class="GtkScrolledWindow" id="scrolledwindow1">
+                  <object class="GtkScrolledWindow" id="scrolledwindow1">
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
-                    <property name="hscrollbar_policy">automatic</property>
-                    <property name="vscrollbar_policy">automatic</property>
                     <property name="shadow_type">in</property>
                     <child>
-                      <widget class="Custom" id="thumbview">
+                      <object class="ImageList" id="thumbview">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
                         <property name="has_focus">True</property>
-                        <property name="creation_function">ImageList.ImageList()</property>
-                      </widget>
+                        <child internal-child="selection">
+                          <object class="GtkTreeSelection" id="ImageList-selection1"/>
+                        </child>
+                      </object>
                     </child>
-                  </widget>
+                  </object>
                   <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
                     <property name="position">0</property>
                   </packing>
                 </child>
                 <child>
-                  <widget class="GtkHBox" id="hbox1">
+                  <object class="GtkHBox" id="hbox1">
                     <property name="visible">True</property>
+                    <property name="can_focus">False</property>
                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                     <child>
-                      <widget class="GtkButton" id="add_button">
+                      <object class="GtkButton" id="add_button">
                         <property name="label" translatable="yes">Add Photos...</property>
+                        <property name="use_action_appearance">False</property>
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
                         <property name="receives_default">True</property>
                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <signal name="clicked" handler="on_add_photos_activate"/>
-                      </widget>
+                        <property name="use_action_appearance">False</property>
+                        <signal name="clicked" handler="on_add_photos_activate" swapped="no"/>
+                      </object>
                       <packing>
                         <property name="expand">False</property>
+                        <property name="fill">True</property>
                         <property name="position">0</property>
                       </packing>
                     </child>
                     <child>
-                      <widget class="GtkButton" id="remove_button">
+                      <object class="GtkButton" id="remove_button">
                         <property name="label" translatable="yes">Remove Photos</property>
+                        <property name="use_action_appearance">False</property>
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
                         <property name="receives_default">True</property>
                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <signal name="clicked" handler="on_remove_activate"/>
-                      </widget>
+                        <property name="use_action_appearance">False</property>
+                        <signal name="clicked" handler="on_remove_activate" swapped="no"/>
+                      </object>
                       <packing>
                         <property name="expand">False</property>
+                        <property name="fill">True</property>
                         <property name="position">1</property>
                       </packing>
                     </child>
                     <child>
                       <placeholder/>
                     </child>
-                  </widget>
+                  </object>
                   <packing>
                     <property name="expand">False</property>
+                    <property name="fill">True</property>
                     <property name="position">1</property>
                   </packing>
                 </child>
-              </widget>
+              </object>
               <packing>
                 <property name="resize">False</property>
                 <property name="shrink">False</property>
               </packing>
             </child>
             <child>
-              <widget class="GtkTable" id="info_table">
+              <object class="GtkGrid" id="info_table">
                 <property name="visible">True</property>
+                <property name="can_focus">False</property>
                 <property name="border_width">6</property>
-                <property name="n_rows">7</property>
-                <property name="n_columns">3</property>
-                <property name="column_spacing">4</property>
                 <property name="row_spacing">6</property>
+                <property name="column_spacing">4</property>
+                <child>
+                  <object class="SetCombo" id="set_combo">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="hexpand">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">4</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="TagsEntry" id="tags_entry">
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">3</property>
+                    <property name="width">2</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
                 <child>
-                  <widget class="Custom" id="set_combo">
+                  <object class="GtkEntry" id="title_entry">
                     <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="primary_icon_activatable">False</property>
+                    <property name="secondary_icon_activatable">False</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">1</property>
+                    <property name="width">2</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="rename_button">
+                    <property name="label" translatable="yes">Rename</property>
+                    <property name="use_action_appearance">False</property>
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="use_action_appearance">False</property>
+                    <signal name="clicked" handler="on_rename_activate" swapped="no"/>
+                  </object>
+                  <packing>
+                    <property name="left_attach">2</property>
+                    <property name="top_attach">4</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkScrolledWindow" id="scrolledwindow2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="creation_function">set_combo_new</property>
-                  </widget>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <object class="GtkTextView" id="desc_view">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="wrap_mode">word</property>
+                        <property name="accepts_tab">False</property>
+                      </object>
+                    </child>
+                  </object>
                   <packing>
                     <property name="left_attach">1</property>
-                    <property name="right_attach">3</property>
+                    <property name="top_attach">2</property>
+                    <property name="width">2</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkImage" id="thumbnail_image">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="hexpand">True</property>
+                    <property name="vexpand">True</property>
+                    <property name="yalign">0</property>
+                    <property name="stock">gtk-missing-image</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">0</property>
+                    <property name="width">3</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="title_label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">_Title:</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">title_entry</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">1</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="desc_label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="yalign">0</property>
+                    <property name="label" translatable="yes">_Description:</property>
+                    <property name="use_underline">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">2</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="tags_label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">Ta_gs:</property>
+                    <property name="use_underline">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">3</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="set_label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">Add to _Set:</property>
+                    <property name="use_underline">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
                     <property name="top_attach">4</property>
-                    <property name="bottom_attach">5</property>
-                    <property name="x_options">GTK_FILL</property>
-                    <property name="y_options"></property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
                   </packing>
                 </child>
                 <child>
-                  <widget class="GtkExpander" id="expander2">
+                  <object class="GtkExpander" id="expander2">
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                     <child>
-                      <widget class="GtkScrolledWindow" id="scrolledwindow3">
+                      <object class="GtkScrolledWindow" id="scrolledwindow3">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                         <property name="hscrollbar_policy">never</property>
-                        <property name="vscrollbar_policy">automatic</property>
                         <property name="shadow_type">in</property>
                         <child>
-                          <widget class="Custom" id="group_selector">
+                          <object class="GroupSelector" id="group_selector">
                             <property name="visible">True</property>
+                            <property name="can_focus">True</property>
                             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                            <property name="creation_function">group_selector_new</property>
-                          </widget>
+                            <child internal-child="selection">
+                              <object class="GtkTreeSelection" id="GroupSelector-selection"/>
+                            </child>
+                          </object>
                         </child>
-                      </widget>
+                      </object>
                     </child>
-                    <child>
-                      <widget class="GtkLabel" id="label1">
+                    <child type="label">
+                      <object class="GtkLabel" id="label1">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                         <property name="label" translatable="yes">Send to Groups</property>
-                      </widget>
-                      <packing>
-                        <property name="type">label_item</property>
-                      </packing>
+                      </object>
                     </child>
-                  </widget>
+                  </object>
                   <packing>
-                    <property name="right_attach">3</property>
+                    <property name="left_attach">0</property>
                     <property name="top_attach">5</property>
-                    <property name="bottom_attach">6</property>
-                    <property name="x_options">GTK_FILL</property>
-                    <property name="y_options">GTK_FILL</property>
+                    <property name="width">3</property>
+                    <property name="height">1</property>
                   </packing>
                 </child>
                 <child>
-                  <widget class="GtkExpander" id="expander1">
+                  <object class="GtkExpander" id="expander1">
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                     <child>
-                      <widget class="GtkTable" id="table2">
+                      <object class="GtkGrid" id="table2">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="n_rows">5</property>
-                        <property name="n_columns">2</property>
-                        <property name="column_spacing">4</property>
                         <property name="row_spacing">6</property>
+                        <property name="column_spacing">4</property>
                         <child>
-                          <widget class="GtkLabel" id="content_type_label">
+                          <object class="PrivacyCombo" id="privacy_combo">
                             <property name="visible">True</property>
-                            <property name="xalign">0</property>
-                            <property name="label" translatable="yes">_Content type:</property>
-                            <property name="use_underline">True</property>
-                            <property name="mnemonic_widget">tags_entry</property>
-                          </widget>
+                            <property name="can_focus">False</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                          </object>
                           <packing>
-                            <property name="top_attach">2</property>
-                            <property name="bottom_attach">3</property>
-                            <property name="x_options">GTK_FILL</property>
-                            <property name="y_options">GTK_FILL</property>
+                            <property name="left_attach">1</property>
+                            <property name="top_attach">0</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
                           </packing>
                         </child>
                         <child>
-                          <widget class="Custom" id="privacy_combo">
+                          <object class="SafetyCombo" id="safety_combo">
                             <property name="visible">True</property>
+                            <property name="can_focus">False</property>
                             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                            <property name="creation_function">PrivacyCombo.PrivacyCombo()</property>
-                          </widget>
+                          </object>
                           <packing>
                             <property name="left_attach">1</property>
-                            <property name="right_attach">2</property>
+                            <property name="top_attach">1</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
                           </packing>
                         </child>
                         <child>
-                          <widget class="GtkLabel" id="privacy_label">
+                          <object class="GtkCheckButton" id="visible_check">
+                            <property name="label" translatable="yes">_Visible in search results</property>
+                            <property name="use_action_appearance">False</property>
                             <property name="visible">True</property>
-                            <property name="xalign">0</property>
-                            <property name="label" translatable="yes">_Privacy:</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="use_action_appearance">False</property>
                             <property name="use_underline">True</property>
-                            <property name="mnemonic_widget">tags_entry</property>
-                          </widget>
+                            <property name="xalign">0</property>
+                            <property name="active">True</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
                           <packing>
-                            <property name="x_options">GTK_FILL</property>
-                            <property name="y_options">GTK_FILL</property>
+                            <property name="left_attach">1</property>
+                            <property name="top_attach">4</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
                           </packing>
                         </child>
                         <child>
-                          <widget class="GtkLabel" id="safety_label">
+                          <object class="ContentTypeCombo" id="content_type_combo">
                             <property name="visible">True</property>
-                            <property name="xalign">0</property>
-                            <property name="label" translatable="yes">_Safety:</property>
-                            <property name="use_underline">True</property>
-                            <property name="mnemonic_widget">tags_entry</property>
-                          </widget>
+                            <property name="can_focus">False</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                          </object>
                           <packing>
-                            <property name="top_attach">1</property>
-                            <property name="bottom_attach">2</property>
-                            <property name="x_options">GTK_FILL</property>
-                            <property name="y_options">GTK_FILL</property>
+                            <property name="left_attach">1</property>
+                            <property name="top_attach">2</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
                           </packing>
                         </child>
                         <child>
-                          <widget class="Custom" id="safety_combo">
+                          <object class="LicenseCombo" id="license_combo">
                             <property name="visible">True</property>
+                            <property name="can_focus">False</property>
                             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                            <property name="creation_function">SafetyCombo.SafetyCombo()</property>
-                          </widget>
+                          </object>
                           <packing>
                             <property name="left_attach">1</property>
-                            <property name="right_attach">2</property>
-                            <property name="top_attach">1</property>
-                            <property name="bottom_attach">2</property>
+                            <property name="top_attach">3</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
                           </packing>
                         </child>
                         <child>
-                          <widget class="GtkCheckButton" id="visible_check">
-                            <property name="label" translatable="yes">_Visible in search results</property>
+                          <object class="GtkLabel" id="privacy_label">
                             <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">False</property>
-                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="can_focus">False</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">_Privacy:</property>
                             <property name="use_underline">True</property>
-                            <property name="active">True</property>
-                            <property name="draw_indicator">True</property>
-                          </widget>
+                          </object>
                           <packing>
-                            <property name="left_attach">1</property>
-                            <property name="right_attach">2</property>
-                            <property name="top_attach">4</property>
-                            <property name="bottom_attach">5</property>
+                            <property name="left_attach">0</property>
+                            <property name="top_attach">0</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
                           </packing>
                         </child>
                         <child>
-                          <widget class="Custom" id="content_type_combo">
+                          <object class="GtkLabel" id="safety_label">
                             <property name="visible">True</property>
-                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                            <property name="creation_function">ContentTypeCombo.ContentTypeCombo()</property>
-                          </widget>
+                            <property name="can_focus">False</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">_Safety:</property>
+                            <property name="use_underline">True</property>
+                          </object>
                           <packing>
-                            <property name="left_attach">1</property>
-                            <property name="right_attach">2</property>
-                            <property name="top_attach">2</property>
-                            <property name="bottom_attach">3</property>
+                            <property name="left_attach">0</property>
+                            <property name="top_attach">1</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
                           </packing>
                         </child>
                         <child>
-                          <widget class="GtkLabel" id="license_label">
+                          <object class="GtkLabel" id="content_type_label">
                             <property name="visible">True</property>
+                            <property name="can_focus">False</property>
                             <property name="xalign">0</property>
-                            <property name="label" translatable="yes">_License:</property>
+                            <property name="label" translatable="yes">_Content type:</property>
                             <property name="use_underline">True</property>
-                            <property name="mnemonic_widget">tags_entry</property>
-                          </widget>
+                          </object>
                           <packing>
-                            <property name="top_attach">3</property>
-                            <property name="bottom_attach">4</property>
-                            <property name="x_options">GTK_FILL</property>
-                            <property name="y_options">GTK_FILL</property>
+                            <property name="left_attach">0</property>
+                            <property name="top_attach">2</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
                           </packing>
                         </child>
                         <child>
-                          <widget class="Custom" id="license_combo">
+                          <object class="GtkLabel" id="license_label">
                             <property name="visible">True</property>
-                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                            <property name="creation_function">license_combo_new</property>
-                          </widget>
+                            <property name="can_focus">False</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">_License:</property>
+                            <property name="use_underline">True</property>
+                          </object>
                           <packing>
-                            <property name="left_attach">1</property>
-                            <property name="right_attach">2</property>
+                            <property name="left_attach">0</property>
                             <property name="top_attach">3</property>
-                            <property name="bottom_attach">4</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
                           </packing>
                         </child>
                         <child>
                           <placeholder/>
                         </child>
-                      </widget>
+                      </object>
                     </child>
-                    <child>
-                      <widget class="GtkLabel" id="label5">
+                    <child type="label">
+                      <object class="GtkLabel" id="label5">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                         <property name="label" translatable="yes">Privacy, Safety, Type and License</property>
-                      </widget>
-                      <packing>
-                        <property name="type">label_item</property>
-                      </packing>
+                      </object>
                     </child>
-                  </widget>
+                  </object>
                   <packing>
-                    <property name="right_attach">3</property>
+                    <property name="left_attach">0</property>
                     <property name="top_attach">6</property>
-                    <property name="bottom_attach">7</property>
-                    <property name="x_options">GTK_FILL</property>
-                    <property name="y_options">GTK_FILL</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="title_label">
-                    <property name="visible">True</property>
-                    <property name="xalign">0</property>
-                    <property name="label" translatable="yes">_Title:</property>
-                    <property name="use_underline">True</property>
-                    <property name="mnemonic_widget">title_entry</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">1</property>
-                    <property name="bottom_attach">2</property>
-                    <property name="x_options">GTK_FILL</property>
-                    <property name="y_options"></property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="desc_label">
-                    <property name="visible">True</property>
-                    <property name="xalign">0</property>
-                    <property name="yalign">0</property>
-                    <property name="label" translatable="yes">_Description:</property>
-                    <property name="use_underline">True</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">2</property>
-                    <property name="bottom_attach">3</property>
-                    <property name="x_options">GTK_FILL</property>
-                    <property name="y_options">GTK_FILL</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="tags_label">
-                    <property name="visible">True</property>
-                    <property name="xalign">0</property>
-                    <property name="label" translatable="yes">Ta_gs:</property>
-                    <property name="use_underline">True</property>
-                    <property name="mnemonic_widget">tags_entry</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">3</property>
-                    <property name="bottom_attach">4</property>
-                    <property name="x_options">GTK_FILL</property>
-                    <property name="y_options"></property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="Custom" id="tags_entry">
-                    <property name="visible">True</property>
-                    <property name="sensitive">False</property>
-                    <property name="can_focus">True</property>
-                    <property name="creation_function">tag_entry_new</property>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">3</property>
-                    <property name="top_attach">3</property>
-                    <property name="bottom_attach">4</property>
-                    <property name="y_options"></property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkEntry" id="title_entry">
-                    <property name="visible">True</property>
-                    <property name="sensitive">False</property>
-                    <property name="can_focus">True</property>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">3</property>
-                    <property name="top_attach">1</property>
-                    <property name="bottom_attach">2</property>
-                    <property name="y_options"></property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="set_label">
-                    <property name="visible">True</property>
-                    <property name="xalign">0</property>
-                    <property name="label" translatable="yes">Add to _Set:</property>
-                    <property name="use_underline">True</property>
-                    <property name="mnemonic_widget">set_combo</property>
-                  </widget>
-                  <packing>
-                    <property name="top_attach">4</property>
-                    <property name="bottom_attach">5</property>
-                    <property name="x_options">GTK_FILL</property>
-                    <property name="y_options"></property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkButton" id="rename_button">
-                    <property name="label" translatable="yes">Rename</property>
-                    <property name="visible">True</property>
-                    <property name="sensitive">False</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
-                    <signal name="clicked" handler="on_rename_activate"/>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">2</property>
-                    <property name="right_attach">3</property>
-                    <property name="top_attach">4</property>
-                    <property name="bottom_attach">5</property>
-                    <property name="x_options">GTK_FILL</property>
-                    <property name="y_options"></property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkImage" id="thumbnail_image">
-                    <property name="visible">True</property>
-                    <property name="yalign">0</property>
-                    <property name="stock">gtk-missing-image</property>
-                  </widget>
-                  <packing>
-                    <property name="right_attach">3</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkScrolledWindow" id="scrolledwindow2">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="hscrollbar_policy">automatic</property>
-                    <property name="vscrollbar_policy">automatic</property>
-                    <property name="shadow_type">in</property>
-                    <child>
-                      <widget class="GtkTextView" id="desc_view">
-                        <property name="visible">True</property>
-                        <property name="sensitive">False</property>
-                        <property name="can_focus">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="wrap_mode">word</property>
-                        <property name="accepts_tab">False</property>
-                      </widget>
-                    </child>
-                  </widget>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">3</property>
-                    <property name="top_attach">2</property>
-                    <property name="bottom_attach">3</property>
-                    <property name="y_options">GTK_FILL</property>
+                    <property name="width">3</property>
+                    <property name="height">1</property>
                   </packing>
                 </child>
-              </widget>
+              </object>
               <packing>
                 <property name="resize">True</property>
                 <property name="shrink">False</property>
               </packing>
             </child>
-          </widget>
+          </object>
           <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
             <property name="position">2</property>
           </packing>
         </child>
-      </widget>
+      </object>
     </child>
-  </widget>
-</glade-interface>
+  </object>
+</interface>
diff --git a/src/postr.py b/src/postr.py
index 1d8d640..822820e 100644
--- a/src/postr.py
+++ b/src/postr.py
@@ -1,6 +1,8 @@
 # Postr, a Flickr Uploader
+# -*- coding: utf-8 -*-
 #
 # Copyright (C) 2006-2008 Ross Burton <ross burtonini com>
+# Copyright (C) 2009-2012 GermÃn Poo-CaamaÃo <gpoo gnome org>
 #
 # This program is free software; you can redistribute it and/or modify it under
 # the terms of the GNU General Public License as published by the Free Software
@@ -19,10 +21,10 @@ import logging, os, urllib
 from urlparse import urlparse
 from os.path import basename
 
-import pygtk; pygtk.require ("2.0")
-import gobject, gtk, gtk.glade, gconf, gio
-import gnome.ui
+from gi.repository import GObject, Gtk, GConf, GdkPixbuf, Gio, Gdk
 
+#FIXME
+#import gnome.ui
 
 try:
     import gtkspell
@@ -34,7 +36,7 @@ from AboutDialog import AboutDialog
 from AuthenticationDialog import AuthenticationDialog
 from ProgressDialog import ProgressDialog
 from ErrorDialog import ErrorDialog
-import ImageStore, ImageList, StatusBar, PrivacyCombo, SafetyCombo, GroupSelector, ContentTypeCombo
+import ImageStore, ImageList, StatusBar, PrivacyCombo, SafetyCombo, GroupSelector, ContentTypeCombo, SetCombo, LicenseCombo, TagsEntry
 from proxyclient import EXTRA_STEP_SET_ID, EXTRA_STEP_GROUPS, EXTRA_STEP_LICENSE, EXTRA_STEP_NEW_SET, UploadProgressTracker
 
 from flickrest import Flickr
@@ -59,10 +61,11 @@ except ImportError:
  ROTATED_90_CCW
  ) = (1, 3, 6, 8)
 
-_FILE_ATTRIBUTES = ",".join([gio.FILE_ATTRIBUTE_STANDARD_TYPE,
-                             gio.FILE_ATTRIBUTE_STANDARD_NAME,
-                             gio.FILE_ATTRIBUTE_STANDARD_SIZE,
-                             gio.FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME])
+_FILE_ATTRIBUTES = ",".join([Gio.FILE_ATTRIBUTE_STANDARD_TYPE,
+                             Gio.FILE_ATTRIBUTE_STANDARD_NAME,
+                             Gio.FILE_ATTRIBUTE_STANDARD_SIZE,
+                             Gio.FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME])
+_SUPPORTED_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/bmp']
 
 class Postr(UniqueApp):
     def __init__(self):
@@ -73,17 +76,18 @@ class Postr(UniqueApp):
             pass
 
         self.is_connected = False
-        
+
         self.flickr = Flickr(api_key="c53cebd15ed936073134cec858036f1d",
                              secret="7db1b8ef68979779",
                              perms="write")
 
-        self.logo_icon_size = gtk.icon_size_register("logo", 128, 128)
-        
-        gtk.window_set_default_icon_name("postr")
-        gtk.glade.set_custom_handler(self.get_custom_handler)
-        glade = gtk.glade.XML(os.path.join(os.path.dirname(__file__), "postr.glade"))
-        glade.signal_autoconnect(self)
+        self.logo_icon_size = Gtk.icon_size_register("logo", 128, 128)
+
+        Gtk.Window.set_default_icon_name("postr")
+        glade = Gtk.Builder()
+        glade.add_from_file(os.path.join (os.path.dirname(__file__), "postr.glade"))
+        #Gtk.glade.set_custom_handler(self.get_custom_handler)
+        glade.connect_signals(self)
 
         get_glade_widgets(glade, self,
                            ("window",
@@ -109,25 +113,33 @@ class Postr(UniqueApp):
                             "license_combo",
                             "thumbview")
                            )
+
+        # Activate callbacks in custom widgets
+        self.group_selector.flickr = self.flickr
+        self.statusbar.flickr = self.flickr
+        self.tags_entry.flickr = self.flickr
+        self.license_combo.flickr = self.flickr
+        self.set_combo.flickr = self.flickr
+
         align_labels(glade, ("title_label", "desc_label",
                              "tags_label", "set_label",
                              "privacy_label", "safety_label"))
-        
+
         # Just for you, Daniel.
         try:
             if os.getlogin() == "daniels":
                 self.window.set_title("Respecognise")
         except Exception:
             pass
-        
+
         self.model = ImageStore.ImageStore()
         self.model.connect("row-inserted", self.on_model_changed)
         self.model.connect("row-deleted", self.on_model_changed)
-        
+
         self.thumbview.set_model(self.model)
 
         self.set_combo.connect("changed", self.on_set_combo_changed)
-        
+
         selection = self.thumbview.get_selection()
         selection.connect("changed", self.on_selection_changed)
 
@@ -159,7 +171,7 @@ class Postr(UniqueApp):
 
         self.thumbnail_image.clear()
         self.thumbnail_image.set_size_request(128, 128)
-        
+
         self.change_signals = [] # List of (widget, signal ID) tuples
         self.change_signals.append((self.title_entry, self.title_entry.connect('changed', self.on_field_changed, ImageStore.COL_TITLE)))
         self.change_signals.append((self.desc_view.get_buffer(), self.desc_view.get_buffer().connect('changed', self.on_field_changed, ImageStore.COL_DESCRIPTION)))
@@ -170,12 +182,12 @@ class Postr(UniqueApp):
         self.change_signals.append((self.visible_check, self.visible_check.connect('toggled', self.on_field_changed, ImageStore.COL_VISIBLE)))
         self.change_signals.append((self.content_type_combo, self.content_type_combo.connect('changed', self.on_field_changed, ImageStore.COL_CONTENT_TYPE)))
         self.change_signals.append((self.license_combo, self.license_combo.connect('changed', self.on_field_changed, ImageStore.COL_LICENSE)))
-        
+
         self.thumbnail_image.connect('size-allocate', self.update_thumbnail)
         self.old_thumb_allocation = None
 
         self.on_selection_changed(selection)
-        
+
         # The upload progress dialog
         self.uploading = False
         self.current_upload_it = None
@@ -193,11 +205,11 @@ class Postr(UniqueApp):
         self.update_remove()
 
         # Update the proxy configuration
-        client = gconf.client_get_default()
-        client.add_dir("/system/http_proxy", gconf.CLIENT_PRELOAD_RECURSIVE)
-        client.notify_add("/system/http_proxy", self.proxy_changed)
+        client = GConf.Client.get_default()
+        client.add_dir("/system/http_proxy", GConf.ClientPreloadType.PRELOAD_RECURSIVE)
+        client.notify_add("/system/http_proxy", self.proxy_changed, None)
         self.proxy_changed(client, 0, None, None)
-        
+
         # Connect to flickr, go go go
         self.flickr.authenticate_1().addCallbacks(self.auth_open_url, self.twisted_error)
 
@@ -206,7 +218,7 @@ class Postr(UniqueApp):
 
     def twisted_error(self, failure):
         self.update_upload()
-        
+
         dialog = ErrorDialog(self.window)
         dialog.set_from_failure(failure)
         dialog.show_all()
@@ -218,7 +230,7 @@ class Postr(UniqueApp):
             if host is None or host == "" or port == 0:
                 self.flickr.set_proxy(None)
                 return
-            
+
             if client.get_bool("/system/http_proxy/use_authentication"):
                 user = client.get_string("/system/http_proxy/authentication_user")
                 password = client.get_string("/system/http_proxy/authentication_password")
@@ -232,48 +244,6 @@ class Postr(UniqueApp):
             self.flickr.set_proxy(url)
         else:
             self.flickr.set_proxy(None)
-    
-    def get_custom_handler(self, glade, function_name, widget_name, str1, str2, int1, int2):
-        """libglade callback to create custom widgets."""
-        handler = getattr(self, function_name, None)
-        if handler:
-            return handler(str1, str2, int1, int2)
-        else:
-            widget = eval(function_name)
-            widget.show()
-            return widget
-
-    def group_selector_new(self, *args):
-        w = GroupSelector.GroupSelector(self.flickr)
-        w.show()
-        return w
-
-    def set_combo_new(self, *args):
-        import SetCombo
-        w = SetCombo.SetCombo(self.flickr)
-        w.show()
-        return w
-
-    def license_combo_new(self, *args):
-        import LicenseCombo
-        w = LicenseCombo.LicenseCombo(self.flickr)
-        w.show()
-        return w
-    
-    def image_list_new(self, *args):
-        """Custom widget creation function to make the image list."""
-        view = ImageList.ImageList()
-        view.show()
-        return view
-
-    def status_bar_new(self, *args):
-        bar = StatusBar.StatusBar(self.flickr)
-        bar.show()
-        return bar
-    def tag_entry_new(self, *args):
-        import TagsEntry
-        entry = TagsEntry.TagsEntry(self.flickr)
-        return entry
 
     def on_message_pyunique(self, instance, command, data):
         """ PyUnique callback for receiving a message """
@@ -289,7 +259,7 @@ class Postr(UniqueApp):
         # the model was changed, not what was changed.
         self.update_upload()
         self.update_remove()
-    
+
     def auth_open_url(self, state):
         """Callback from midway through Flickr authentication.  At this point we
         either have cached tokens so can carry on, or need to open a web browser
@@ -298,10 +268,10 @@ class Postr(UniqueApp):
             self.connected(True)
         else:
             dialog = AuthenticationDialog(self.window, state['url'])
-            if dialog.run() == gtk.RESPONSE_ACCEPT:
+            if dialog.run() == Gtk.ResponseType.ACCEPT:
                 self.flickr.authenticate_2(state).addCallbacks(self.connected, self.twisted_error)
             dialog.destroy()
-    
+
     def connected(self, connected):
         """Callback when the Flickr authentication completes."""
         self.is_connected = connected
@@ -314,13 +284,14 @@ class Postr(UniqueApp):
             self.update_avatar()
             self.update_tag_list()
 
-    def on_statusbar_box_expose(self, widget, event):
+    def on_statusbar_box_draw(self, widget, cr):
         """
         Expose callback for the event box containing the status bar, to paint it
         in a different colour.
         """
-        widget.window.draw_rectangle(widget.style.dark_gc[gtk.STATE_NORMAL], True, *event.area)
-        
+        #FIXME: get the dark theme color instead
+        widget.override_background_color(Gtk.StateType.NORMAL, Gdk.RGBA(0.5, 0.5, 0.5, 0.6))
+
     def update_upload(self):
         connected = self.is_connected and self.model.iter_n_children(None) > 0
         self.upload_menu.set_sensitive(connected)
@@ -338,7 +309,7 @@ class Postr(UniqueApp):
         for row in self.model:
             size += row[ImageStore.COL_SIZE]
         self.statusbar.set_upload(size)
-    
+
     def update_avatar(self):
         """
         Update the avatar displayed at the top of the window.  Called when
@@ -356,14 +327,14 @@ class Postr(UniqueApp):
             get_buddyicon(self.flickr, data).addCallbacks(get_buddyicon_cb, self.twisted_error)
         # Need to call people.getInfo to get the iconserver/iconfarm
         self.flickr.people_getInfo(user_id=self.flickr.get_nsid()).addCallbacks(getinfo_cb, self.twisted_error)
-    
+
     def on_field_changed(self, widget, column):
         """Callback when the entry fields are changed."""
-        if isinstance(widget, gtk.Entry) or isinstance(widget, gtk.TextBuffer):
+        if isinstance(widget, Gtk.Entry) or isinstance(widget, Gtk.TextBuffer):
             value = widget.get_property("text")
-        elif isinstance(widget, gtk.ToggleButton):
+        elif isinstance(widget, Gtk.ToggleButton):
             value = widget.get_active()
-        elif isinstance(widget, gtk.ComboBox):
+        elif isinstance(widget, Gtk.ComboBox):
             value = widget.get_active_iter()
         elif isinstance(widget, GroupSelector.GroupSelector):
             value = widget.get_selected_groups()
@@ -383,7 +354,7 @@ class Postr(UniqueApp):
         """Callback when the set combo is changed."""
         set_it = self.set_combo.get_active_iter()
 
-        (id, ) = self.set_combo.get_id_for_iter(set_it) if set_it else (None, )
+        (id,) = self.set_combo.get_id_for_iter(set_it) if set_it else (None,)
         self._update_rename_button(id)
 
         selection = self.thumbview.get_selection()
@@ -394,43 +365,38 @@ class Postr(UniqueApp):
 
     def _update_rename_button(self, id):
         if id == '-1':
-            self.info_table.child_set(self.set_combo,
-                                      "right-attach",
-                                      2)
             self.rename_button.set_sensitive(True)
         else:
-            self.info_table.child_set(self.set_combo,
-                                      "right-attach",
-                                      3)
             self.rename_button.set_sensitive(False)
 
     def on_rename_activate(self, button):
-        self.set_combo.name_new_photoset()
+        self.set_combo.name_new_photoset(self.window)
 
     def on_add_photos_activate(self, widget):
         """Callback from the File->Add Photos menu item or Add button."""
-        dialog = gtk.FileChooserDialog(title=_("Add Photos"), parent=self.window,
-                                       action=gtk.FILE_CHOOSER_ACTION_OPEN,
-                                       buttons=(gtk.STOCK_CANCEL,
-                                                gtk.RESPONSE_CANCEL,
-                                                gtk.STOCK_OPEN,
-                                                gtk.RESPONSE_OK))
+        dialog = Gtk.FileChooserDialog(title=_("Add Photos"), parent=self.window,
+                                       action=Gtk.FileChooserAction.OPEN,
+                                       buttons=(Gtk.STOCK_CANCEL,
+                                                Gtk.ResponseType.CANCEL,
+                                                Gtk.STOCK_OPEN,
+                                                Gtk.ResponseType.OK))
         dialog.set_select_multiple(True)
         if self.last_folder:
             dialog.set_current_folder_uri(self.last_folder)
 
         # Add filters for all reasonable image types
-        filters = gtk.FileFilter()
+        filters = Gtk.FileFilter()
         filters.set_name(_("Images"))
-        filters.add_mime_type("image/*")
+        for mime_type in _SUPPORTED_MIME_TYPES:
+            filters.add_mime_type(mime_type)
         dialog.add_filter(filters)
-        filters = gtk.FileFilter()
+        filters = Gtk.FileFilter()
         filters.set_name(_("All Files"))
         filters.add_pattern("*")
         dialog.add_filter(filters)
 
         # Add a preview widget
-        preview = gtk.Image()
+        preview = Gtk.Image()
         dialog.set_preview_widget(preview)
 
         def get_thumbnail(uri):
@@ -438,16 +404,21 @@ class Postr(UniqueApp):
             # None in case is not possible to get it or
             # generate it.
 
-            gfile = gio.File(uri)
-            ginfo = gfile.query_info('time::modified,standard::content-type')
+            gfile = Gio.File.new_for_uri(uri)
+            attributes = ','.join([Gio.FILE_ATTRIBUTE_TIME_MODIFIED,
+                                   Gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE])
+            ginfo = gfile.query_info(attributes,
+                                     Gio.FileQueryInfoFlags.NONE, None)
             mtime = ginfo.get_modification_time()
             mime = ginfo.get_content_type()
 
+            # FIXME: Port to GTK3
+            '''
             factory = gnome.ui.ThumbnailFactory(gnome.ui.THUMBNAIL_SIZE_NORMAL)
             thumb_path = factory.lookup(uri, int(mtime))
 
             if thumb_path:
-                return gtk.gdk.pixbuf_new_from_file(thumb_path)
+                return GdkPixbuf.Pixbuf.new_from_file(thumb_path)
 
             # There is no thumbmail, we will try to generate one
             # or return None if not possible
@@ -458,9 +429,10 @@ class Postr(UniqueApp):
                 return thumbnail
             else:
                 return None
+            '''
+            return None
 
         def update_preview_cb(file_chooser, preview):
-            filename = file_chooser.get_preview_filename()
             uri = file_chooser.get_preview_uri()
 
             if uri:
@@ -475,48 +447,48 @@ class Postr(UniqueApp):
             file_chooser.set_preview_widget_active(have_preview)
 
         dialog.connect("update-preview", update_preview_cb, preview)
-        
-        if dialog.run() == gtk.RESPONSE_OK:
+
+        if dialog.run() == Gtk.ResponseType.OK:
             dialog.hide()
             self.last_folder = dialog.get_current_folder_uri()
             for uri in dialog.get_uris():
                 self.add_image_uri(uri)
         dialog.destroy()
-            
+
     def on_quit_activate(self, widget, *args):
         """Callback from File->Quit."""
         if self.uploading:
-            dialog = gtk.MessageDialog(type=gtk.MESSAGE_WARNING, parent=self.window)
-            dialog.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
-                               gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT,
-                               gtk.STOCK_QUIT, gtk.RESPONSE_OK)
+            dialog = Gtk.MessageDialog(type=Gtk.MessageType.WARNING, parent=self.window)
+            dialog.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
+                               Gtk.STOCK_SAVE, Gtk.ResponseType.ACCEPT,
+                               Gtk.STOCK_QUIT, Gtk.ResponseType.OK)
             dialog.set_markup(_('<b>Currently Uploading</b>'))
             dialog.format_secondary_text(_('Photos are still being uploaded. '
                                            'Are you sure you want to quit? '
                                            'You can also save your pending upload set for later.'))
-            dialog.set_default_response(gtk.RESPONSE_OK)
+            dialog.set_default_response(Gtk.ResponseType.OK)
             response = dialog.run()
             dialog.destroy()
-            if response == gtk.RESPONSE_CANCEL:
+            if response == Gtk.ResponseType.CANCEL:
                 return True
-            elif response == gtk.RESPONSE_ACCEPT:
+            elif response == Gtk.ResponseType.ACCEPT:
                 self.save_upload_set()
         elif self.is_connected and self.model.iter_n_children(None) > 0 and self.model.dirty():
-            dialog = gtk.MessageDialog(type=gtk.MESSAGE_WARNING, parent=self.window)
-            dialog.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
-                               gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT,
-                               gtk.STOCK_QUIT, gtk.RESPONSE_OK)
+            dialog = Gtk.MessageDialog(type=Gtk.MessageType.WARNING, parent=self.window)
+            dialog.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
+                               Gtk.STOCK_SAVE, Gtk.ResponseType.ACCEPT,
+                               Gtk.STOCK_QUIT, Gtk.ResponseType.OK)
             dialog.set_markup(_('<b>Photos to be uploaded</b>'))
             dialog.format_secondary_text(_('There are photos pending to '
                                            'be uploaded. '
                                            'Are you sure you want to quit? '
                                            'You can also save your pending upload set for later.'))
-            dialog.set_default_response(gtk.RESPONSE_OK)
+            dialog.set_default_response(Gtk.ResponseType.OK)
             response = dialog.run()
             dialog.destroy()
-            if response == gtk.RESPONSE_CANCEL:
+            if response == Gtk.ResponseType.CANCEL:
                 return True
-            elif response == gtk.RESPONSE_ACCEPT:
+            elif response == Gtk.ResponseType.ACCEPT:
                 self.save_upload_set()
 
         import twisted.internet.reactor
@@ -531,7 +503,7 @@ class Postr(UniqueApp):
 
     def on_remove_activate(self, widget):
         """Callback from File->Remove or Remove button."""
-        
+
         def get_selected_iter(model, path, iter, selectList):
             selectIter = model.get_iter(path)
             selectList.append(selectIter)
@@ -555,7 +527,6 @@ class Postr(UniqueApp):
         elif len(model) > 0:
             self.thumbview.set_cursor(model[-1].path)
 
-
     def on_select_all_activate(self, menuitem):
         """Callback from Edit->Select All."""
         selection = self.thumbview.get_selection()
@@ -580,13 +551,13 @@ class Postr(UniqueApp):
         """Callback from File->Switch User."""
         self.flickr.clear_cached()
         self.flickr.authenticate_1().addCallbacks(self.auth_open_url, self.twisted_error)
-    
+
     def on_upload_activate(self, menuitem):
         """Callback from File->Upload."""
         if self.uploading:
             print "Upload should be disabled, currently uploading"
             return
-        
+
         it = self.model.get_iter_first()
         if it is None:
             print "Upload should be disabled, no photos"
@@ -605,10 +576,10 @@ class Postr(UniqueApp):
         self.upload_index = 0
         self.list_failed_it = []
         self.upload()
-       
+
     def on_help_activate(self, menuitem):
         """Callback from Help->Contents."""
-        gtk.show_uri(None,"ghelp:postr",gtk.gdk.CURRENT_TIME);
+        Gtk.show_uri(None, "ghelp:postr", Gdk.CURRENT_TIME);
 
     def on_about_activate(self, menuitem):
         """Callback from Help->About."""
@@ -616,7 +587,7 @@ class Postr(UniqueApp):
         dialog.run()
         dialog.destroy()
 
-    def update_thumbnail(self, widget, allocation = None):
+    def update_thumbnail(self, widget, allocation=None):
         """Update the preview, as the selected image was changed."""
         if self.current_it:
             if not allocation:
@@ -636,7 +607,7 @@ class Postr(UniqueApp):
             self.old_thumb_allocation = allocation
 
             (simage,) = self.model.get(self.current_it, ImageStore.COL_PREVIEW)
-            
+
             tw = allocation.width
             th = allocation.height
             # Clamp the size to 512
@@ -646,23 +617,23 @@ class Postr(UniqueApp):
                                            simage.get_height(),
                                            tw, th)
 
-            thumb = simage.scale_simple(tw, th, gtk.gdk.INTERP_BILINEAR)
+            thumb = simage.scale_simple(tw, th, GdkPixbuf.InterpType.BILINEAR)
             widget.set_from_pixbuf(thumb)
 
     def on_selection_changed(self, selection):
         """Callback when the selection was changed, to update the entries and
         preview."""
-        [obj.handler_block(i) for obj,i in self.change_signals]
-        
+        [obj.handler_block(i) for obj, i in self.change_signals]
+
         def enable_field(field, value):
             field.set_sensitive(True)
-            if isinstance(field, gtk.Entry):
+            if isinstance(field, Gtk.Entry):
                 field.set_text(value)
-            elif isinstance(field, gtk.TextView):
+            elif isinstance(field, Gtk.TextView):
                 field.get_buffer().set_text(value)
-            elif isinstance(field, gtk.ToggleButton):
+            elif isinstance(field, Gtk.ToggleButton):
                 field.set_active(value)
-            elif isinstance(field, gtk.ComboBox):
+            elif isinstance(field, Gtk.ComboBox):
                 if value:
                     field.set_active_iter(value)
                 else:
@@ -674,13 +645,13 @@ class Postr(UniqueApp):
                 raise "Unhandled widget type %s" % field
         def disable_field(field):
             field.set_sensitive(False)
-            if isinstance(field, gtk.Entry):
+            if isinstance(field, Gtk.Entry):
                 field.set_text("")
-            elif isinstance(field, gtk.TextView):
+            elif isinstance(field, Gtk.TextView):
                 field.get_buffer().set_text("")
-            elif isinstance(field, gtk.ToggleButton):
+            elif isinstance(field, Gtk.ToggleButton):
                 field.set_active(True)
-            elif isinstance(field, gtk.ComboBox):
+            elif isinstance(field, Gtk.ComboBox):
                 field.set_active(-1)
             elif isinstance(field, GroupSelector.GroupSelector):
                 field.set_selected_groups(())
@@ -732,22 +703,22 @@ class Postr(UniqueApp):
             disable_field(self.license_combo)
 
             self.thumbnail_image.set_from_icon_name("postr", self.logo_icon_size)
-        [obj.handler_unblock(i) for obj,i in self.change_signals]
+        [obj.handler_unblock(i) for obj, i in self.change_signals]
 
     def add_image_dir_file(self, gfile):
-        children = gfile.enumerate_children(_FILE_ATTRIBUTES, flags=gio.FILE_QUERY_INFO_NONE)
-        child_info = children.next_file()
+        children = gfile.enumerate_children(_FILE_ATTRIBUTES, Gio.FileQueryInfoFlags.NONE, None)
+        child_info = children.next_file(None)
         while child_info:
             file_type = child_info.get_file_type()
-            if file_type == gio.FILE_TYPE_REGULAR:
+            if file_type == Gio.FileType.REGULAR:
                 self.add_image_fileinfo(gfile, child_info)
-            elif file_type == gio.FILE_TYPE_DIRECTORY:
+            elif file_type == Gio.FileType.DIRECTORY:
                 dirname = os.path.join(gfile.get_uri(), child_info.get_name())
-                self.add_image_dir_file(gio.File(dirname))
+                self.add_image_dir_file(Gio.File.new_for_uri(dirname))
             else:
                 print "Unhandled file %s" % gfile.get_uri()
-            child_info = children.next_file()
-        children.close()
+            child_info = children.next_file(None)
+        children.close(None)
 
     def add_image_uri(self, uri):
         """Add a file to the image list.  Called by the File->Add Photo and drag
@@ -755,14 +726,23 @@ class Postr(UniqueApp):
         return self.add_image_filename(uri)
 
     def add_image_filename(self, filename):
-        gfile = gio.File(filename)
-        fileinfo = gfile.query_info(_FILE_ATTRIBUTES, flags=gio.FILE_QUERY_INFO_NONE)
+        gfile = Gio.File.new_for_commandline_arg(filename)
+        fileinfo = gfile.query_info(_FILE_ATTRIBUTES,
+                                    Gio.FileQueryInfoFlags.NONE,
+                                    None)
         self.add_image_file(gfile, fileinfo)
 
     def add_image_fileinfo(self, parent, fileinfo):
         filename = os.path.join(parent.get_uri(), fileinfo.get_name())
-        gfile = gio.File(filename)
-        self.add_image_file(gfile, fileinfo)
+        gfile = Gio.File.new_for_uri(filename)
+        ginfo = gfile.query_info(Gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+                                 Gio.FileQueryInfoFlags.NONE, None)
+        mime = ginfo.get_content_type()
+
+        if mime in _SUPPORTED_MIME_TYPES:
+            self.add_image_file(gfile, fileinfo)
+        else:
+            print 'Unsupported format (%s): %s' % (mime, filename)
 
     def _on_preview_size_prepared(self, loader, width, height):
         """Appropriately scale the image preview to fit inside 512x512"""
@@ -781,20 +761,20 @@ class Postr(UniqueApp):
             d.set_from_string(_("Image %s is too large, images must be no larger than %dMB in size.") % (gfile.get_path(), self.statusbar.maxfile))
             d.show_all()
             return
-        
+
         # TODO: we open the file three times now, which is madness, especially
         # if gnome-vfs is used to read remote files.  Need to find/write EXIF
         # and IPTC parsers that are incremental.
 
         # only opening the file_stream
-        file_stream = gfile.read()
+        file_stream = gfile.read(None)
 
         # First we load the image scaled to 512x512 for the preview.
         try:
             if gfile.is_native():
-                preview = gtk.gdk.pixbuf_new_from_file_at_size(gfile.get_path(), 512, 512)
+                preview = GdkPixbuf.Pixbuf.new_from_file_at_size(gfile.get_path(), 512, 512)
             else:
-                loader = gtk.gdk.PixbufLoader()
+                loader = GdkPixbuf.PixbufLoader()
                 loader.connect("size-prepared", self._on_preview_size_prepared)
                 loader.write(file_stream.read())
                 loader.close()
@@ -804,9 +784,9 @@ class Postr(UniqueApp):
             d.set_from_exception(e)
             d.show_all()
             return
-        
+
         # type 1 is beginning of file
-        if not file_stream.can_seek() or not file_stream.seek(0, type=1):
+        if not file_stream.can_seek() or not file_stream.seek(0, type=1, cancellable=None):
             file_stream = gfile.read()
 
         # On a file that doesn't contain EXIF, like a PNG, this just returns an
@@ -817,28 +797,28 @@ class Postr(UniqueApp):
             exif = {}
 
         # type 1 is beginning of file
-        if not file_stream.can_seek() or not file_stream.seek(0, type=1):
-            file_stream = gfile.read()
+        if not file_stream.can_seek() or not file_stream.seek(0, type=1, cancellable=None):
+            file_stream = gfile.read(None)
 
         try:
             iptc = IPTCInfo(file_stream).data
         except:
             iptc = {}
-        
+
         # Rotate the preview if required.  We don't need to manipulate the
         # original data as Flickr will do that for us.
         if "Image Orientation" in exif:
             rotation = exif["Image Orientation"].values[0]
             if rotation == ROTATED_180:
-                preview = preview.rotate_simple(gtk.gdk.PIXBUF_ROTATE_UPSIDEDOWN)
+                preview = preview.rotate_simple(Gdk.PIXBUF_ROTATE_UPSIDEDOWN)
             elif rotation == ROTATED_90_CW:
-                preview = preview.rotate_simple(gtk.gdk.PIXBUF_ROTATE_CLOCKWISE)
+                preview = preview.rotate_simple(Gdk.PIXBUF_ROTATE_CLOCKWISE)
             elif rotation == ROTATED_90_CCW:
-                preview = preview.rotate_simple(gtk.gdk.PIXBUF_ROTATE_COUNTERCLOCKWISE)
-        
+                preview = preview.rotate_simple(Gdk.PIXBUF_ROTATE_COUNTERCLOCKWISE)
+
         # Now scale the preview to a thumbnail
         sizes = get_thumb_size(preview.get_width(), preview.get_height(), 64, 64)
-        thumb = preview.scale_simple(sizes[0], sizes[1], gtk.gdk.INTERP_BILINEAR)
+        thumb = preview.scale_simple(sizes[0], sizes[1], GdkPixbuf.InterpType.BILINEAR)
 
         # Slurp data from the EXIF and IPTC tags
         title_tags = (
@@ -863,15 +843,14 @@ class Postr(UniqueApp):
                     if value:
                         return value
             return default
-        
+
         title = slurp(title_tags, os.path.splitext(fileinfo.get_display_name())[0])
         desc = slurp(desc_tags)
         tags = slurp(tag_tags)
-        
+
         self.model.set(self.model.append(),
                        ImageStore.COL_URI, gfile.get_uri(),
                        ImageStore.COL_SIZE, filesize,
-                       ImageStore.COL_IMAGE, None,
                        ImageStore.COL_PREVIEW, preview,
                        ImageStore.COL_THUMBNAIL, thumb,
                        ImageStore.COL_TITLE, title,
@@ -881,25 +860,25 @@ class Postr(UniqueApp):
 
         self.update_statusbar()
         self.update_upload()
-    
+
     def on_drag_data_received(self, widget, context, x, y, selection, targetType, timestamp):
         """Drag and drop callback when data is received."""
         if targetType == ImageList.DRAG_IMAGE:
             pixbuf = selection.get_pixbuf()
 
             # TODO: don't scale up if the image is smaller than 512/512
-            
+
             # Scale the pixbuf to a preview
             sizes = get_thumb_size(pixbuf.get_width(), pixbuf.get_height(), 512, 512)
-            preview = pixbuf.scale_simple(sizes[0], sizes[1], gtk.gdk.INTERP_BILINEAR)
+            preview = pixbuf.scale_simple(sizes[0], sizes[1], GdkPixbuf.InterpType.BILINEAR)
             # Now scale to a thumbnail
             sizes = get_thumb_size(pixbuf.get_width(), pixbuf.get_height(), 64, 64)
-            thumb = pixbuf.scale_simple(sizes[0], sizes[1], gtk.gdk.INTERP_BILINEAR)
+            thumb = pixbuf.scale_simple(sizes[0], sizes[1], GdkPixbuf.InterpType.BILINEAR)
 
             # TODO: This is wrong, and should generate a PNG here and use the
             # size of the PNG
             size = pixbuf.get_width() * pixbuf.get_height() * pixbuf.get_n_channels()
-            
+
             self.model.set(self.model.append(),
                            ImageStore.COL_IMAGE, pixbuf,
                            ImageStore.COL_SIZE, size,
@@ -911,15 +890,16 @@ class Postr(UniqueApp):
                            ImageStore.COL_TAGS, "",
                            ImageStore.COL_VISIBLE, True)
 
-        
+
         elif targetType == ImageList.DRAG_URI:
             for uri in selection.get_uris():
-                gfile = gio.File(uri)
-                fileinfo = gfile.query_info(_FILE_ATTRIBUTES)
+                gfile = Gio.File.new_for_uri(uri)
+                fileinfo = gfile.query_info(_FILE_ATTRIBUTES,
+                                            Gio.FileQueryInfoFlags.NONE, None)
                 file_type = fileinfo.get_file_type()
-                if file_type == gio.FILE_TYPE_REGULAR:
+                if file_type == Gio.FileType.REGULAR:
                     self.add_image_file(gfile, fileinfo)
-                elif file_type == gio.FILE_TYPE_DIRECTORY:
+                elif file_type == Gio.FileType.DIRECTORY:
                     self.add_image_dir_file(gfile)
                 else:
                     print "Unhandled file %s" % gfile.get_uri()
@@ -943,7 +923,7 @@ class Postr(UniqueApp):
 
         # Use named args for i18n
         data = {
-            "index": self.upload_index+1,
+            "index": self.upload_index + 1,
             "count": self.upload_count
             }
         progress_label = _('Uploading %(index)d of %(count)d') % data
@@ -953,14 +933,14 @@ class Postr(UniqueApp):
 
     def add_to_set(self, rsp, set):
         """Callback from the upload method to add the picture to a set."""
-        photo_id=rsp.find("photoid").text
+        photo_id = rsp.find("photoid").text
         self.flickr.photosets_addPhoto(photo_id=photo_id, photoset_id=set).addErrback(self.twisted_error)
         self.upload_progress_tracker.complete_extra_step(EXTRA_STEP_SET_ID)
         return rsp
 
     def add_to_groups(self, rsp, groups):
         """Callback from the upload method to add the picture to a groups."""
-        photo_id=rsp.find("photoid").text
+        photo_id = rsp.find("photoid").text
         for group in groups:
             def error(failure):
                 # Code 6 means "moderated", which isn't an error
@@ -972,7 +952,7 @@ class Postr(UniqueApp):
 
     def set_license(self, rsp, license):
         """Callback from the upload method to set license for the picture."""
-        photo_id=rsp.find("photoid").text
+        photo_id = rsp.find("photoid").text
         self.flickr.photos_licenses_setLicense(photo_id=photo_id,
                                                license_id=license).addErrback(self.twisted_error)
         self.upload_progress_tracker.complete_extra_step(EXTRA_STEP_LICENSE)
@@ -1100,7 +1080,7 @@ class Postr(UniqueApp):
                                        progress_tracker=self.upload_progress_tracker)
             else:
                 print "No filename or pixbuf stored"
-        except gio.Error, (error):
+        except Gio.Error, (error):
             # save the iterator and continue uploading process
             self.list_failed_it.append(it)
             self.current_upload_it = None
@@ -1128,7 +1108,7 @@ class Postr(UniqueApp):
             self.upload_progress_tracker.complete_extra_step(EXTRA_STEP_NEW_SET)
 
     def create_photoset_then_continue(self, rsp, photoset_name):
-        photo_id=rsp.find("photoid").text
+        photo_id = rsp.find("photoid").text
         create_photoset = self.flickr.photosets_create(primary_photo_id=photo_id, title=photoset_name)
         create_photoset.addCallback(self._process_photoset_creation, photoset_name)
         create_photoset.addErrback(self.upload_error)
@@ -1147,7 +1127,7 @@ class Postr(UniqueApp):
 
         thumbnail = self.model.get_value(iter, ImageStore.COL_THUMBNAIL)
         #Use a pixmap to create a new image
-        drawable = gtk.gdk.Pixmap(self.window.window, # gtk.gdk.Drawable
+        drawable = Gdk.Pixmap(self.window.window, # Gdk.Drawable
                                     thumbnail.get_width(),
                                     thumbnail.get_height())
 
@@ -1158,24 +1138,24 @@ class Postr(UniqueApp):
                                 0, 0) #Destination X, Y coordinate
 
         error_icon = self.window.render_icon(
-                                stock_id=gtk.STOCK_DIALOG_ERROR,
-                                size=gtk.ICON_SIZE_DIALOG)
+                                stock_id=Gtk.STOCK_DIALOG_ERROR,
+                                size=Gtk.IconSize.DIALOG)
 
         # It chose a size for the error icon proportional to the thumbnail image
         size = min(int(thumbnail.get_width() * HALF_SIZE),
                     int(thumbnail.get_height() * HALF_SIZE))
 
         error_icon = error_icon.scale_simple(size, size,
-                                    gtk.gdk.INTERP_BILINEAR)
+                                    GdkPixbuf.InterpType.BILINEAR)
 
         # The error icon is drawed in the bottom right edge of the image
         drawable.draw_pixbuf(self.window.get_style().white_gc, #graphics context
                             error_icon, #the pixbuf
                             0, 0, #Source X,Y coordinate
-                            thumbnail.get_width()-size, #Destination X coordinate
-                            thumbnail.get_height()-size) #Destination Y coordinate
+                            thumbnail.get_width() - size, #Destination X coordinate
+                            thumbnail.get_height() - size) #Destination Y coordinate
 
-        new_thumbnail = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, #color mode
+        new_thumbnail = GdkPixbuf.Pixbuf(GdkPixbuf.Colorspace.RGB, #color mode
                                 True, #has alpha
                                 8, #bits
                                 thumbnail.get_width(), #width
@@ -1185,7 +1165,7 @@ class Postr(UniqueApp):
                                         drawable.get_colormap(),
                                         0, 0, #Source X, Y coordinate
                                         0, 0, #Destination X, Y coordinate
-                                        -1, -1) #The full width, height
+                                        - 1, -1) #The full width, height
 
         self.model.set_value(iter, ImageStore.COL_THUMBNAIL, new_thumbnail)
 
@@ -1203,7 +1183,7 @@ class Postr(UniqueApp):
         self.thumbview.set_reorderable(False)
 
         self.thumbview.enable_targets()
-        [obj.handler_unblock(i) for obj,i in self.drag_signals]
+        [obj.handler_unblock(i) for obj, i in self.drag_signals]
 
     def on_button_press_cb(self, thumbview, event, data=None):
         if self.drop_disabled:
@@ -1211,45 +1191,43 @@ class Postr(UniqueApp):
         self.thumbview.unable_targets()
 
         self.drop_disabled = True
-        [obj.handler_block(i) for obj,i in self.drag_signals]
+        [obj.handler_block(i) for obj, i in self.drag_signals]
         thumbview.set_reorderable(True)
         return
 
     def on_button_release_cb(self, thumbview, event, data=None):
-
         if self.drop_disabled and (not self.drag_started):
             self.drop_disabled = False
             thumbview.set_reorderable(False)
             self.thumbview.enable_targets()
-            [obj.handler_unblock(i) for obj,i in self.drag_signals]
+            [obj.handler_unblock(i) for obj, i in self.drag_signals]
         return False
 
-
     def save_upload_set(self):
-        dialog = gtk.FileChooserDialog(title=None,
-                                       action=gtk.FILE_CHOOSER_ACTION_SAVE,
-                                       buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
-                                                gtk.STOCK_SAVE, gtk.RESPONSE_OK))
+        dialog = Gtk.FileChooserDialog(title=None, parent=self.window,
+                                       action=Gtk.FileChooserAction.SAVE,
+                                       buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
+                                                Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
 
-        dialog.set_default_response(gtk.RESPONSE_OK)
+        dialog.set_default_response(Gtk.ResponseType.OK)
 
         default_filename = datetime.strftime(datetime.today(), "upload_saved_on_%m-%d-%y.postr")
         dialog.set_current_name(default_filename)
 
         dialog.set_do_overwrite_confirmation(True)
 
-        filter = gtk.FileFilter()
+        filter = Gtk.FileFilter()
         filter.set_name("postr upload sets")
         filter.add_pattern("*.postr")
         dialog.add_filter(filter)
 
-        filter = gtk.FileFilter()
+        filter = Gtk.FileFilter()
         filter.set_name("All Files")
         filter.add_pattern("*")
         dialog.add_filter(filter)
 
         response = dialog.run()
-        if response == gtk.RESPONSE_OK:
+        if response == Gtk.ResponseType.OK:
             filename = dialog.get_filename()
             dest = shelve.open(filename, 'n')
 
@@ -1310,7 +1288,7 @@ class Postr(UniqueApp):
         else:
             safety_path = None
 
-        args = ( path,
+        args = (path,
                  uri,
                  title,
                  desc,
@@ -1319,29 +1297,29 @@ class Postr(UniqueApp):
                  groups,
                  privacy_path,
                  safety_path,
-                 visible )
+                 visible)
         return args
 
     def load_upload_set(self):
-        dialog = gtk.FileChooserDialog(title=None,
-                                       action=gtk.FILE_CHOOSER_ACTION_OPEN,
-                                       buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
-                                                gtk.STOCK_OPEN, gtk.RESPONSE_OK))
+        dialog = Gtk.FileChooserDialog(title=None, parent=self.window,
+                                       action=Gtk.FileChooserAction.OPEN,
+                                       buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
+                                                Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
 
-        dialog.set_default_response(gtk.RESPONSE_OK)
+        dialog.set_default_response(Gtk.ResponseType.OK)
 
-        filter = gtk.FileFilter()
+        filter = Gtk.FileFilter()
         filter.set_name("postr upload sets")
         filter.add_pattern("*.postr")
         dialog.add_filter(filter)
 
-        filter = gtk.FileFilter()
+        filter = Gtk.FileFilter()
         filter.set_name("All Files")
         filter.add_pattern("*")
         dialog.add_filter(filter)
 
         response = dialog.run()
-        if response == gtk.RESPONSE_OK:
+        if response == Gtk.ResponseType.OK:
             filename = dialog.get_filename()
             source = shelve.open(filename, 'r')
             if source:
@@ -1354,14 +1332,14 @@ class Postr(UniqueApp):
                         if self.flickr.get_nsid() != nsid:
                             markup_args = (self.flickr.get_username(), username) if self.flickr.get_username() and username else (self.flickr.get_nsid(), nsid)
                             markup_pattern = _("You are logged in as %s but loading\nan upload set for %s")
-                            confirm_dialog = gtk.MessageDialog(buttons=gtk.BUTTONS_YES_NO)
-                            confirm_dialog.set_default_response(gtk.RESPONSE_YES)
+                            confirm_dialog = Gtk.MessageDialog(buttons=Gtk.ButtonsType.YES_NO)
+                            confirm_dialog.set_default_response(Gtk.ResponseType.YES)
                             confirm_dialog.set_markup(markup_pattern % markup_args)
                             confirm_dialog.format_secondary_text(_("Do you want to continue "
                                                                    "with the load?  You will "
                                                                    "not import photoset information."))
                             response = confirm_dialog.run()
-                            if response == gtk.RESPONSE_NO:
+                            if response == Gtk.ResponseType.NO:
                                 dialog.destroy()
                                 return
                             else:
@@ -1371,14 +1349,14 @@ class Postr(UniqueApp):
                     if source.has_key("nsid"):
                         source_user = source.get("username", source["nsid"])
                         markup_pattern = _("You are not logged in but loading\nan upload set for %s")
-                        confirm_dialog = gtk.MessageDialog(buttons=gtk.BUTTONS_YES_NO)
-                        confirm_dialog.set_default_response(gtk.RESPONSE_YES)
+                        confirm_dialog = Gtk.MessageDialog(buttons=Gtk.ButtonsType.YES_NO)
+                        confirm_dialog.set_default_response(Gtk.ResponseType.YES)
                         confirm_dialog.set_markup(markup_pattern % source_user)
                         confirm_dialog.format_secondary_text(_("Do you want to continue "
                                                                "with the load?  You will "
                                                                "not import photoset information."))
                         response = confirm_dialog.run()
-                        if response == gtk.RESPONSE_NO:
+                        if response == Gtk.ResponseType.NO:
                             dialog.destroy()
                             return
                         else:
diff --git a/src/proxyclient.py b/src/proxyclient.py
index 9284c79..67b550f 100644
--- a/src/proxyclient.py
+++ b/src/proxyclient.py
@@ -426,7 +426,7 @@ EXTRA_STEP_FRACTION = 0.04
 
 class UploadProgressTracker(object):
     """
-    This object takes a gtk.ProgressBar object as a parameter
+    This object takes a Gtk.ProgressBar object as a parameter
     and appropriately calls progress.set_fraction() as more
     data gets written to the pipe.
     """
diff --git a/src/util.py b/src/util.py
index 5ad3410..bf58995 100644
--- a/src/util.py
+++ b/src/util.py
@@ -15,30 +15,31 @@
 # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 # St, Fifth Floor, Boston, MA 02110-1301 USA
 
-import gtk, os
+import os
+from gi.repository import Gtk, GdkPixbuf
 
 
 def greek(size):
     """Take a quantity (like 1873627) and display it in a human-readable rounded
     form (like 1.8M)"""
     _abbrevs = [
-        (1<<50L, 'P'),
-        (1<<40L, 'T'), 
-        (1<<30L, 'G'), 
-        (1<<20L, 'M'), 
-        (1<<10L, 'k'),
+        (1 << 50L, 'P'),
+        (1 << 40L, 'T'),
+        (1 << 30L, 'G'),
+        (1 << 20L, 'M'),
+        (1 << 10L, 'k'),
         (1, '')
         ]
     for factor, suffix in _abbrevs:
         if size > factor:
             break
-    return "%.1f%s" % (float(size)/factor, suffix)
+    return "%.1f%s" % (float(size) / factor, suffix)
 
 
 def get_widget_checked(glade, name):
     """Get widget name from glade, and if it doesn't exist raise an exception
     instead of returning None."""
-    widget = glade.get_widget(name)
+    widget = glade.get_object(name)
     if widget is None: raise "Cannot find widget %s" % name
     return widget
 
@@ -53,8 +54,8 @@ def get_glade_widgets (glade, object, widget_names):
 def get_thumb_size(srcw, srch, dstw, dsth):
     """Scale scrw x srch to an dimensions with the same ratio that fits as
     closely as possible to dstw x dsth."""
-    scalew = dstw/float(srcw)
-    scaleh = dsth/float(srch)
+    scalew = dstw / float(srcw)
+    scaleh = dsth / float(srch)
     scale = min(scalew, scaleh)
     return (int(srcw * scale), int(srch * scale))
 
@@ -62,7 +63,8 @@ def get_thumb_size(srcw, srch, dstw, dsth):
 def align_labels(glade, names):
     """Add the list of widgets identified by names in glade to a horizontal
     sizegroup."""
-    group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
+    group = Gtk.SizeGroup()
+    group.set_mode(Gtk.SizeGroupMode.HORIZONTAL)
     widget = [group.add_widget(get_widget_checked(glade, name)) for name in names]
 
 
@@ -87,7 +89,7 @@ def get_buddyicon(flickr, data, size=48):
             __buddy_cache = bsddb3.hashopen(path, "c")
 
     def load_thumb(page, size):
-        loader = gtk.gdk.PixbufLoader()
+        loader = GdkPixbuf.PixbufLoader()
         loader.set_size (size, size)
         loader.write(page)
         loader.close()
@@ -96,7 +98,7 @@ def get_buddyicon(flickr, data, size=48):
     def got_data(page, url, size):
         __buddy_cache[url] = page
         return load_thumb(page, size)
-    
+
     if int(data.get("iconfarm")) > 0:
         url = "http://farm%s.static.flickr.com/%s/buddyicons/%s.jpg"; % (data.get("iconfarm"), data.get("iconserver"), data.get("nsid"))
     else:



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]