Future of GNOME language bindings

First of all, let me show you a screenshot showing what have been hacking on in my spare time over the last two weeks or so:

.WebKitGtkPython.png

It’s showing a simple web browser written in python using WebKit, this is the code for that:

import bank
import Gtk, WebKit

win = Gtk.Window(Gtk.WindowType.TOPLEVEL)
p = WebKit.Page()
p.open(“http://www.google.com/”)
win.add(p)
win.show_all()

Gtk.main()

There are no specific bindings for WebKit, or even Gtk in this case. It’s all done using the introspection information available through gobject-introspection. I am not using the existing python bindings for GObject and GTK, I am instead using pybank, the python bindings for gobject-introspection.

The bank module, our interface to pybank differ from most (all?) GNOME language bindings written today by constructing the bindings in runtime. The bank module loads and interprets the metadata repository compiled using the g-idl-compiler tool. When you first access the Page class in WebKit it generates the Page class, and because it’s a GtkContainer subclass it imports the Gtk bindings and eventually the GObject ones as it’s also a subclass of GObject. When calling the constructors and methods it’s using libffi.

Before you’re all getting too excited, this is just a proof of concept, you won’t be able to build real applications based on pybank, you can’t even listen to signals yet. The only supported parameter types at the moment are int, str, enum and object. It’s mainly used a testcase for the introspection framework, to be able to make sure that the information available through introspection is going to work for this kind of language/binding.

The idea behind gobject-introspection is that each C library itself will generate and install the metadata at compile time. The metadata represents what you see in the C headers and a little bit extra which is already available through introspection in GObject such as properties, signals and class inheritence.

So what’s missing before we can start using this?

Jürg of Vala fame has written a header parser which will generate the metadata by scanning the headers. It’s in a pretty good state already, but not good enough to generate good enough metadata, it still needs to be tweaked a bit. The metadata in gobject-introspection needs a few additions such as typedefs, default values, a module/metdata mapping and a few other things.

In the screenshot attached below you can see that this is using about 6M of memory. Right, the bindings are not finished and the application is rather trivial, but I don’t expect this to go up significantly as I add more features for pybank, I expect it to go down as I can remove a couple of dependencies when gobject-introspection will be nearer to competition.

GObject-introspection goals:

  • Provide all information necessary to generate language bindings
  • Consolidate this information, to avoid duplication between all languages
  • Encourage upstream projects to include the metadata
Posted in Blogroll, General, GNOME, olpc, PyGTK, Python | 13 Comments

Life update

Mono

I’ve seem to have been the latest victim of this. That’s the sickness and not the software. I got the diagnosis last Friday, It’s likely that I’ll have a rough couple of months ahead of me.

Sweden

I’m back home in Sweden since a few weeks. I’ve not been able to enjoy it too much due to sickness.We will have to wait and see what the future holds for me. It’s great to see my family again, it’s been a while.

All seems so strange, like I’m gotten used to the South American way of doing things. I’m still amazed that I don’t need to lock doors when going out to the super market.

Vista

I haven’t been using windows more than a couple of minutes at a time since Win98/NT4. I bought a new laptop and it has Vista included. I don’t think it’s as bad as everyone says. There are a couple of very nice features. The volume mixer “applet” works surprisingly well. The main slider widget changes the volume on all channels/tracks instead of a predefine one (such as PCM/master/mumbo-yumboJ34). Why aren’t we doing something similar in GNOME, can’t be that hard..

Posted in General | 6 Comments

ObjectList tutorial

This blog post will give you an introduction to the ObjectList widget which is a part of the kiwi library.

* Rationale

Creating graphical user interfaces which displays a sequence of objects is a common task. In the GTK+ toolkit you will normally use a GtkTreeView for this. GtkTreeView is a very flexible and extensible widget, for instance it allows you to separate the data storage from the representation. However the disadvantage of using the GtkTreeView is that it’s a little bit too complicated to use, especially for beginners.

The ObjectList aims to provide a familiar API to create, manipulate and access sequences of objects. It builds on top of GtkTreeView, and allows you to access the “raw” objects (view, columns, model, cellrenderers, selection) in case you want to do something which is not directly supported by the ObjectList.

Kiwi and ObjectList are tied to the Python programming language and depends heavily on PyGTK (and thus CPython). However the concepts introduced in the widget are usually not specific to Python, it’s very possible to implement similar high level wrappers on top of GtkTreeView for C#, Java etc.

* Simple ObjectList example

Here is the source code and the output of a simple ObjectList example

Simple ObjectList example Simple example screenshot

Let’s walk through the example and explain what it does.

  • The class Fruit is defined with two attributes; name and price.
  • An ObjectList called fruits is created which has two columns, name and price
  • 5 objects are created and inserted into the list.

The example is concluded by creating a PyGTK window, adding the objectlist to it and running the main loop.
The data displayed in the ObjectList is stored in normal python instances, there is no need to create and set column types for a GtkTreeModel and extract the data from your python objects and insert it into the model. The model / view separation is kept while still keeping it easy to use.

Notice that the data is appended to the list by calling the append() method of the ObjectList, this is intentionally similar to the append method of the builtin list type of python. If you wanted you could use the extend() method to insert a list of object at one go.

The objects inserted into the list can be modified by using standard python list concepts:

  • iteration: for item in list
  • accessing an individual item: list[n]
  • removing an item: del list[n] or list.remove(item)
  • accessing parts of the item: list[n:m]

There are also methods beyond a normal python list routines which only makes sense in graphical interfaces:

  • selecting an item: list.select(item)
  • getting the selected item: list.get_selected()
  • changing the columns: list.set_columns(columns)
  • getting the columsn: list.get_columns()
  • etc…

* Columns

When you create a column you define how the data is going to be displayed. Column width, sorting, justification, markup and so on. Here is an incomplete list of the support column attributes:

  • title: the text will be used in the column header
  • justify: the justification, eg left or right aligned
  • format: printf style format string
  • width: width in pixels of the column
  • sorted: if we should sort the data after the content in this column
  • editable: is the column editable?
  • use_markup: should the content be interpreted as markup?
  • use_stock: treat the content as stock icon names and display icons

Here is a more complicated, real world example from Stoq, a Retail Management System written on top of Kiwi.

Accounts payable column definition

Accounts payable

The interface shows the accounts payable application which lists outgoing payments.

What we can see from the screenshot is:

  • The first column is sorted and it has the title “#”
  • The third column is the supplier name which is a bit too wide to fit and uses ellipsize
  • The fourth column is the date the purchase was sold and is formatted according to the current locale
  • The last column uses the special datatype currency which formats a number according to the monetary rules defined for the current locale, with thousand separators, decimal points and currency symbols set right.

This is all for now, for more information about Kiwi check out Howto, the API reference and the source code repository

Posted in Blogroll, General, GNOME, olpc, PyGTK, Python | 4 Comments

GIMPNet IRC Spamming

Spammers have recently hit GIMPnet, the IRC network which hosts many GNOME and Mono related projects. Only a few channels are affected: #gnome, #gimp, #gtk+, #pygtk and #mono. The spamming has forced us to set the invite only flag, which prevents the spam bots from entering the channels and thus avoiding the spam. The downside of this is that no new users can enter these channels.

However, there’s a workaround, if you want to enter any of these channels just ask our friendly bot dorito to invite you, which can be done by sending him a private message, in most clients you can do this by typing:

/msg dorito invite #channel

If everything goes well you’ll receive an invitation to the channel. This has to be done each time you login to the network.

A long term solution is being worked on, this is just a temporary workaround.

Posted in General | 2 Comments

Valgrind & Andvare

Yesterday I on a bus ride from São Paulo I had the opportunity to see some of the developments tools available on OSX. Shark and mallocdebug are quite interesting, bling-bling for the developer masses.

When I woke up this morning I realized that it shouldn’t be too difficult to do something similar on top of valgrind.

[…later in the evening and 500 lines typed down…]

andvare.png

It’s quite useful already, it groups all the leaks by the topmost function which is a bit easier to follow than the output valgrind usually gives us.

You can find a tarball here if you want to play around with it.

Update: I uploaded a bzr branch to launchpad:

bzr branch http://code.launchpad.net/~jdahlin/andvare/main/

Posted in Blogroll, General, GNOME, PyGTK, Python | 8 Comments

GtkBuilder has landed!

Today, after more than 2 years and 120 comments I could finally close #172535, adding support for loading interfaces created by UI designers in Gtk+.

GtkBuilder replaces libglade, it uses a similar XML format but also supports the following:

  • GtkTreeViews including columns and cell renderers
  • Menus and toolbars created using GtkUIManager, including actions & actiongroups.
  • TreeModels, it’s possible to define the data used by treemodels. It’s used by treeviews, iconviews, comboboxes, and entries.
  • SizeGroups, align all these widgets without using tables!

I’d like to especially thank Matthias Clasen for reviewing the beast, it was over 6500 lines in the end! Henrique Romano helped me to implement parts of it and Tristan Van Berkom, Tim Janik, Kalle Vahlman, Christian Perch, Dan Winship, Owen Taylor, Behdad Esfahbod and Havoc Pennington also helped out with suggestions and improvements to the patch.There are a couple of things that needs to be done to simplify the transition from libglade to gtkbuilder though:

  • Add support in UI designers. Gazpacho mostly supports it already, it’ll be easy to fix. glade-2 is out of the question and I expect glade-3 to at least partially support GtkBuilder before GNOME 2.20 is released
  • Improve migration from libglade files. There’s a script in bugzilla which converts old libglade files to files which gtkbuilder can load. It needs to be improved and tested, especially menus and toolbars
  • Some libglade features are not supported yet, such as loading only a part of a glade file and pixbuf properties. These will be fixed before the final Gtk+ 2.12 release

Now, time to party!

Posted in Blogroll, General, GNOME, olpc | 15 Comments

Converting a Subversion repository to Bazaar

I recently wanted to test drive Bazaar with a fairly large project.
The first problem is to convert the whole repository which happen to be stored in subversion to a bunch of Bazaar branches.
There’s a tool called svn2bzr written by Gustavo Niemeyer which allows you to easily import a bunch of subversion branches in bzr.

There’s nothing special about my subversion repository, it only contains a couple of modules in the same repository, similar to how KDE has it set up, but different to GNOME.

First you need a dump, that’s easily created using

$ svnadmin dump /path/to/url > stoq-projects.dump

Next step is to convert the four modules called kiwi, stoqlib, stoqdrivers and stoq, to do that, issue this command:

$ python ./svn2bzr.py --scheme=trunk \
--exclude=kiwi(|/tags|/branches)$ \
--exclude=stoq(|/tags|/branches)$ \ 
--exclude=stoqdrivers(|/tags|/branches)$ \ 
--exclude=stoqlib(|/tags|/branches)$ ../stoq-projects.svndump stoq-projects

It turned out that the revision timestamp conversion had a couple of bugs, so you’d really need the latest version, incidentally available as a bzr branch from here.

Posted in General | Comments Off

Getting somewhere….

I’m very pleased to see that no less than 8 posts on Gnome are about PyGTK or applications using PyGTK. And does not count OLPC, which is also using it.

Very few of the posts are explicitly mentioning Python or PyGTK, it’s such a well accepted platform that there’s really no need to.

This the result of many years of hard work. I’d like to acknowledge the following people who have made it possible:

Gnome hackers, keep on being productive, use high level languages, spread the word and don’t forget to let us know what you’!

Posted in GNOME, PyGTK, Python | 2 Comments

Simplified GObject properties

Today I spent most of the day to finish off an implementation of bug 338098, adding a property helper to the python gobject bindings.

The support for defining your own GObject properties in PyGObject/PyGTK has always been a nail in my eye:

  • You need to create a dictionary filled with crazy options
  • You need to implement get_property and set_property to store/retrieve the values for each property.
  • There’s very little help if you do a mistake, a cryptic error message will be displayed which gives you insufficient clues to figure out what you’ve done wrong.

A long time ago I solved this in kiwi. But I never quite got around to submit these helpers to pygobject where they belong.

With the new property helper it gets much simpler. Let’s say you want to create a new object called Color which has the three integer properties called red, green and blue:

  class Color(gobject.GObject):
    red = gobject.property(type=int)
    green = gobject.property(type=int)
    blue = gobject.property(type=int)

That’s it!
Easy to read and understand.

If you want to set a property, just modify the properties as if they were a normal python attribute:

  color = Color()
  color.red = 10
  color.green = 20
  color.blue = 300

Same goes for access:

  >>> color.green
  20

Now, suppose you want a read-only property, then you can use the “new” python 2.4 decorator syntax:

  @gobject.property
  def fnorb(self):
     return 'fnuffra'

Which will add a fnorb property which will always return the string ‘fnuffra’ and raise an exception if your try to modify it.

The patch has not yet landed in pygobject’s SVN repository, but it’ll probably go in shortly, assuming nobody have any objections.

Once this is done I intend to work on a similar solution for signals.

Posted in GNOME, PyGTK, Python | 4 Comments

Metaclasses & PyGObject

I recently ran into a long-standing bug in the Kiwi plugin for Gazpacho.

I have this class in Kiwi: (simplified for explanation purposes)

class KiwiEntry(gtk.Entry):
  gproperty('data_type', object)
  def __init__(self, data_type):
     gtk.Entry.__init__(self)
     self.set_property('data_type', data_type)

This worked absolutely fine when you construct the object by calling the constructor from your python code.
However, Gazpacho and also Glade-3 uses gobject.new() to construct objects, which uses an alternative construction path.

When using gobject.new() to construct the KiwiEntry, an exception would be raised that said that data_type was not a property of the object!

After a few hours of digging in Gazpacho and Kiwi I found out that the underlying bug was actually in PyGObject, the python bindings for GObject. It turned out that the GObject subclasses constructed using gobject.new was not properly created during the constructor phase.

Changing the code to set the property immediately after the constructor would magically solve the bug.

First I tried to solve the bug by using gobject.idle_add. It would actually work but it did not really satisfy me since it depends on the mainloop running. Not too much of a deal actually, since you need a mainloop to use the entry subclass anyway. However, I knew that this would cause hard to debug problems in the future.

The solution of course is to use a metaclass!
A metaclass is a class of a class, which allows you to modify how a class behaves. For instance, you can add a piece of code which is ran when the class is constructed if you like. Or in my case, add a hook which is called after the normal construct has been called.

class MyMeta(gobject.GObjectMeta):
    def __call__(self, *args, **kwargs):
        instance = super(MyMeta, self).__call__(*args, **kwargs)
        instance.__post_init__()
        return instance

This metaclass overrides the __call__ method which is the code being run when you put two parenthesis after the class:

  class()

To use this metaclass for an object, just define the __metaclass__ class attribute in the subclass(es) you wish to use it in:

class KiwiEntry(gtk.Entry):
  __metaclass__ = MyMeta

  def __init__(self, data_type=None):
     gtk.Entry.__init__(self)
     self._data_type = data_type

  def __post_init__(self):
     self.set_property('data-type', self._data_type)

A Metaclass is a very powerful concept, it should be used with caution. It’s very easy to abuse them and make code not only hard to understand, but almost impossible to debug.

For more information about metaclasses, refer to the Unifying types and classes in Python 2.2 which contains a quite technical explanation.

Posted in GNOME, PyGTK, Python | Comments Off