Monday, May 23, 2011

Installing Gtk+3 And PyGobject Introspection


In an earlier post, I assumed the latest version of Gtk+3 and PyGI would be installed by default on Ubuntu 11.04. However, as I discovered some methods were missing (Gdk.atom_intern()), it became evident I did not have the latest versions of the above libraries.


Warning: Some of the packages of Gtk+3 or its dependencies may be experimental. After I installed Gtk+3  and PyGI, I had major issues with Gnome and had to reinstall Ubuntu altogether. I am not sure about the relation between installing Gtk+3, PyGI and the problem I had, but you are warned and should do that at your own risk.

Now Gtk+ offers an installation guide. The installation process is not only cumbersome, but the guide here above is not well written in my opinion. Also, the dependencies of Gtk+3 have their own dependencies and it's a never ending pain to get through it. Depending on your distribution though, the process may be easier on you. For instance if you are using Gentoo, you may simply have to
USE=introspection emerge gtk+.


I'm using Ubuntu 11.04 however and i'll be able to document just that. If you have any other information about other distributions, let me know and i'll update this post.


Step 1: Checking Dependencies
A number of libraries are necessary for Gtk+3 to function. These are the latest versions of:
  • Glib
  • Pango
  • Atk
  • GNU libiconv
  • GNU gettext
  • fontconfig
  • Cairo
  • GdkPixbuf
  • Gobject-Introspection
  • shared-mime-info
Some of those packages may already be installed on 11.04 (in this epic installation I've lost track of what was already installed by default). You can get some from your repositories easily and others you want to install the latest versions available on line.

Installing Glib
You can get the latest version of Glib from ftp and install it:

./configure
make
make install
NB: the configuration script will install the configuration file to /usr/lib/i386-linux-gnu/pkgconfig which may be a problem to other installations. If a further configuration script says it cannot find the latest Glib library, you ought to:

export PKG_CONFIG_PATH="/usr/lib/i386-linux-gnu/pkgconfig:$PKG_CONFIG_PATH"
before running the configuration script again.

Installing Pango
You can get the latest version of Pango from ftp too and perform the same configure, make, make install operation. You can alternatively install the library from repositories:

sudo apt-get install libpango1.0*


Installing Atk
I had a hard time installing this one. First the ftp was not available and second the packages I found failed to install. Luckily Atk is available from repositories:

sudo apt-get install libatk1.0*


Installing GNU Libiconv And Gettext
I couldn't find those in repositories, correct me if i'm wrong. Get the latests vertions of Libiconv and Gettext from ftp. Repeat the configure-make-install process and it should work.

Installing Fontconfig
Fontconfig is available from respositories:

sudo apt-get install fontconfig


Installing Cairo
Get the latest release from ftp, config-make-install takes some time, but it worked smoothly for me.

Installing Gdk-Pixbuf
I believe this is one of those I didn't have to install. You can always check:

sudo apt-get install libgdk-pixbuf2.0*


Installing Gobject Introspection
This is what will allow PyGobject Introspection to do its job. Simply:

sudo apt-get install gobject-introspection


Installing Share Mime Info
I secretly skipped this one, but you can get it here, and it wouldn't surprise me if it was in the repository as well.

Step 2: Installing Gtk+3
With all the above dependencies we should be set. Download Gtk+3's latest version, as of this post it's 3.10 already. Before run the configuration, you want to do:

export PKG_CONFIG_PATH="/usr/lib/i386-linux-gnu/pkgconfig:$PKG_CONFIG_PATH"
Otherwise it won't find the latest GLIB version you just installed. Then go for:

./configure
make
make install
It went fine that way for me and I hope it went well for you.

Step 3: Installing PyGobject Instrospection
The documentation will tell you about the latest version of PyGobject, as of this post it is the 2.28. Configure, make, make install, if necessary set the PKG_CONFIG_PATH again before configuration.
Once you did that you still need to update your Gobject Introspection Repository. There are plenty of packages which you can find with:

apt-cache search gir1.2-
You may not need to install everything, definitely:

sudo apt-get install gir1.2-gtk-3.0 gir1.2-gdk-3.0 gir1.2-gdkpixbuf-2.0

Now you should be all set for making some Gtk+3 GUI with Python  :)

Sunday, May 22, 2011

GtkWindow Basics

Most GUI are built as windows (actually, I can't think of a GUI that isn't a window even if that window is transparent, like a desklet, it is a window nonetheless). So we should start from there. The GtkWindow widget is a subclass of GtkWidget which in turn is a subclass of Gobject, this is why we'll find our GtkWindow class in the Gtk Module of the Gobject Introspection repository. Code-wise, it looks like so:

from gi.repository import Gtk
w = Gtk.Window()

A window needs few other things to appear onto the screen, here is a minimal example:

#!/usr/lib/python
from gi.repository import Gtk
class WindowApp:
        def __init__(self):
                self.window = Gtk.Window().new(Gtk.WindowType.TOPLEVEL)
                self.window.connect('destroy', lambda x: Gtk.main_quit())
                self.window.set_title('Window')
                self.window.show_all()
               

if __name__ == '__main__':
        app = WindowApp()
        Gtk.main()

That should provide you with a cute Gtk+3 window:

The title bar decoration depends on your window manager, so it may vary. The actual window widget is the area below that title bar. Not on this picture, but you may see it on your screen: there is a resize-grip on the bottom right of the window, we'll see about that later.

Let's look a bit closer at the code:

from gi.repository import Gtk
It should be clear by now that we are importing Gtk from our Gobject Introspection module.

class WindowApp:
We defined a new object class called WindowApp. This object represents our main application, which we instantiate later in the code:

app = WindowApp()


As we define our application in def __init__(self):, we need to reference our main window as self.window which is an instance of our Gtk.Window(), initiated with:
self.window = Gtk.Window().new(Gtk.WindowType.TOPLEVEL)
The new() method specifies our window is a TOPLEVEL window, as opposed to a 'pop up'; the former will be managed by the Window Manager whilst the latter won't. The default is 'top level', hence Gtk.Window() would have been enough indeed.

self.window.connect('destroy', lambda x: Gtk.main_quit())
The above line tells us to stop the Gtk main loop (see below) when the window is destroyed (i.e. when you click on the [x] button on your window decoration / title bar). The Gtk.Window.connect() method is an event-handler method, this means it will be triggered when a signal is emitted--in this instance the 'destroy' signal emitted on closing the window. The second argument in connect() is the method or function we want to call when the signal is received. In this case we used a lambda, but we could have called a method defined as eg. def quitApp(self): ect. More on event-handling later.

self.window.set_title('Window')
With this line we set a title of our title bar.

self.window.show_all()
This method is important: it draws the window (it does not appear until the main loop is launched though). We'll have to be careful later, because some window properties and methods will have to be called before and other after that method. Alternatively we could have used self.window.show(), but show_all() specifies showing the top level window and all its children (i.e. all the other widgets we'll attached to it).

app = WindowApp()
That instantiates our application.

Gtk.main()
This starts the Gtk main loop, without which the interface does not appear and which is a loop allowing to listen for signals emitted by widgets whenever those emit one (typically when clicking on them or when their value changes).
We'll look at more details on the GtkWindow next time.

Saturday, May 21, 2011

Introspecting Into GtkWindow

GtkWindow is a basic widget class, commonly used in GUI's, so it's a good place to start with. You can always find more information on any GtkWidget subclass on the Gnome Developer's Documentation. But as I mentioned earlier, the documentation is for C programming and there is hardly any material for PyGI.
Also if you take a look at the documentation on GtkWindow, you will guess that not all methods are provided by the documentation. For instance the gtk_show_all() function is not included, because it is inherited from GtkWidget. As a beginner, it would be quite unfortunate to miss out on this function because it allows the GtkWindow object and all its children widgets (all the controls it includes) to be drawn onto the screen.
So another way to find out what other secrets the GtkWindow object holds, is to introspect the object with the dir() function. Because the GtkWindow object has a lot of attributes and methods, we get quite a big list in return. Let's try out and see:

In a Python Console, first import Gtk and then run dir() as follow:

>>> from gi.repository import Gtk
>>> for item in dir(Gtk.Window):
...     print item
 
As I promised, there are quite a few attributes and methods, so I won't list them here lest we'd waste space. But for the sake of introspection, we could add:

>>> for item in dir(Gtk.Window):
...     if 'show' in item:
...         print item
...
do_show()
do_show_all()
do_show_help()
get_no_show_all()
reshow_with_initial_size()
set_no_show_all()
show()
show_all()
show_now()
Now we observe gladly that the show_all() method is listed. Notice that, because it is a Python binding, it has not the same syntax as the C function:  gtk_window_show_all corresponds to Gtk.Window.show_all(). You could always look into the Gnome Developer's Documentation for more details. In theory, we could get help() or __doc__ to assist us further, but unfortunately we won't rub our hands in excitement with the little doc available:
>>> help(Gtk.Window.show_all)
Help on method show_all:
show_all(*args) unbound gi.repository.Gtk.Window method

>>> print Gtk.Window.show_all.__doc__
None

Update (25/05/11): the __gdoc__ property offers information:
>>> print Gtk.Window.__gdoc__
''' Object GtkWindow

Signals from GtkWindow:
  set-focus (GtkWidget)
  activate-focus ()
  activate-default ()
  keys-changed ()

Properties from GtkWindow:
  type -> GtkWindowType: Window Type
    The type of the window
  title -> gchararray: Window Title
    The title of the window
  role -> gchararray: Window Role
    Unique identifier for the window to be used when restoring a session
  resizable -> gboolean: Resizable
    If TRUE, users can resize the window
  modal -> gboolean: Modal
    If TRUE, the window is modal (other windows are not usable while this one is up)
...
... '''

Gtk3 Is Here

On February the 10th of 2011, Gtk+3 was released and, using this fresh Gtk+3 library, Gnome released Gnome 3.
Gtk+3 should be a "big clean up effort", our source quotes, and noteworthy features are:
  • cairo drawing throughout,
  • modern input device handling,
  • a new theming API ,
  • more flexible geometry management,
  • multiple backend support for Gdk,
  • easy application support,
  • and new widgets.
If you're someone that likes programming using Python, you may already be familiar with PyGtk. PyGtk however will no longer be developed to follow Gtk further than Gtk+2, and "users wishing to develop Python applications using Gtk+ are recommended to use the GObject-Introspection features available in PyGObject."
PyGobject is a Python dynamic module that enables developers to use the power of GObject which is part of the Gnome platform. The new Gtk+3 bindings will be found in this module.
I am using Ubuntu 11.04 as of this post, and I can't recall installing PyGobject, so if you are using the same distribution, you probably already have the module at your disposition. You can check that in your Python console by importing the PyGobject Introspection module (aka PyGI):

from gi.repository import Gtk
If no exception returns, you should be ready to code, but make sure you have the Gtk+3 repository:
import gi
gi.require_version("Gtk", "3.0")
gi.require_version("Gdk", "3.0")

For those who are used to work with PyGtk, it may be wise to port your applications to PyGobject. More information on how to port PyGtk to PyGobject is available on line.
If you're an advanced programmer, the transition won't be hard on you, there are not so many changes. If, however, you are a novice in programming or new to GUI programming, you may find yourself in a bit more difficulties since there is little documentation as of yet on Python bindings. There are few demo's available (not all worked for me) and the Gtk+ documentation is written for C.
So you just may find yourself in the same situation as I am, left with your brain and fingers, and the wish to learn GUI programming with Python. You could just as well try other GUI libraries, like Qt4 or Wx. Because I like using Ubuntu, and because Gtk+ is at home on that OS, Gtk+ seemed like the proper choice to make for me.
Hence I have initiated this blog, open to any one who wants to join and share information on PyGI usage. I'm personally really interested in making styled (aka skinned or themed) applications, so I'll try to always add extra info on how to achieve this. In the worse of cases it will be a good way to keep notes and document what I am learning, in the best of cases it could become a platform for knowledge exchange and learning. Let's see how far we go :)