The three classes in GtkImageView

The whole API for GtkImageView is not completed yet, but it is slowly getting there. Much of the design is borrowed (or almost stolen) from gThumb. Here is a birds eye view of the three main classes along with their counterparts in gThumb:

GtkImageView (gtkimageview.c, gtkimageview.h)

This is the main class of the package. It provides a draggable and zoomable pane on which images can be displayed. The user of the class can customize how images are displayed and whether high or low quality scaling should be used. It also implements a number of useful keybindings for manipulating the image view.

Much code and ideas was borrowed from the ImageViewer widget in gThumb in the files /libgthumb/image-viewer.{c,h}.

GtkImageScrollWin (gtkimagescrollwin.c, gtkimagescrollwin.h)

This class implements a kind of GtkScrolledWindow which is more suitable to use in conjuction with GtkImageView. A GtkImageView embedded inside a GtkImageScrollWin will have auto-hiding horizontal and vertical scrollbars. Additionally, in the bottom right corner it has a button which brings up a GtkImageNavigor for the image.

This class corresponds to the GthNavWindow class in /libgthumb/gth-nav-window.{c,h}.

GtkImageNavigator (gtkimagenavigator.c, gtkimagenavigator.h)

The GtkImageNavigator provides a small popup window showing a preview of the GdkPixbuf it references. It contains a rectangle which the user can drag which causes the GtkImageNavigator to emit a certain signal, signalling to possibly a GtkImageView that it should change its scroll.

It is fairly similar to the NavWindow class in /libgthumb/nav-window.{c,h}.

And here follows a small example showing how the library is supposed to be used:

#include <gtkimageview/gtkimageview.h> ... GtkWidget *image_view; GtkWidget *scroll_win; GdkPixbuf *pixbuf; image_view = gtk_image_view_new (); scroll_win = gtk_image_scroll_win_new (GTK_IMAGE_VIEW (image_view)); gtk_box_pack_start (GTK_BOX (box), scroll_win, TRUE, TRUE, 0); ... pixbuf = gdk_pixbuf_new_from_file ("animage.png", NULL); gtk_image_view_set_pixbuf (image_view, pixbuf);

Phone sex

Phone sex can be a decent enough substitute if you are in a long distance relationship. Although those awkward silences can be really awkward.

Others mistakes

Seems like I am not the only one who has had problems with Python's evalution of default arguments :

class Namespace(object): def __init__(self, __ns={}, **kwargs): if kwargs: __ns.update(kwargs) self.__dict__ = __ns

This particular example was found in comp.lang.python .

GtkImageView is now online

The code for GtkImageView is now publicly released. You can check it out using Subversion:

svn co http://publicsvn.bjourne.webfactional.com/gtkimageview gtkimageview

You can also browse to the project site at trac.bjourne.webfactional.com where you can view the code online. It is still very basic.

The GtkImageView widget

The project I have been working on lately is to create a general purpose image viewer widget for GTK . For my personal project, which will be a commercial product to be sold, I needed such a widget.

After searching around a bit, I concluded that there was no such widget [ 1 ] .

So, what I have created is such a general purpouse widget named GtkImageView. I think that there is a great use for such a widget in GNOME and that it will be just as useful as the GtkSourceView widget has been.

There are quite a few programs in GNOME that display an image inside a pane which you can zoom and drag around. Atleast both gThumb , Eye of GNOME and GIMP has such widgets. But the image display widget in these three programs is implemented independently and are incompatible to each other. Each behave slightly differently from the other. Different keybindings, different zoom factor levels and different graphic adornments.

This is where GtkImageView comes into the picture. It is an attempt to unify these three different widget implementations into one that they all can use. The gains are obvious:

less code duplication
Less code for each project to maintain means less bugs.
Uniform UI
The same set of keybindings in all programs means that a user does not have to relearn each program.
Usable by third parties
If you today want to create an application that has a widget that can pane and zoom on an image you have to create it from scratch. You would probably look at, for example, gThumb's source and then cut and paste that. Then you would have to spend some time integrating their widget in your own programs. Time that would be better spent doing something else.

Right now, GtkImageView is almost fully coded. What remains is to upload it to bjourne.webfactional.com and make it world-readable. The following tasks are not yet done:

  • API documentation needs to be written.
  • There needs to be example programs.
  • Patches must be written for EOG and gThumb.
  • Must announce intention to the GNOME community and get buy-in from EOG and gThumb's maintainers.
  • Need to upload code and publish documentation online.
[ 1 ] Which was wrong, as I found out later.

Evaluation times in Python

One of Python's greatest strengths is its tendancy to reduce many of the common mistakes you do in other languages. But the language is not perfect, and it introduces its own bug sources. For example, try finding the bug in the following snippet:

class Vector: def __init__(self, x, y, z): self.x = x self.y = y self.z = z class Ray: def __init__(self, direction, origin = Vector(0, 0, 0)): self.direction = direction self.origin = origin ray1 = Ray(Vector(0, 0, -1)) ray2 = Ray(Vector(0, 0, 1)) ray3 = Ray(Vector(-1, 0, 0), Vector(2, 3, 4))

Does it look correct to you too?

It kind of does to me, but on closer inspection one finds that there is an "obvious" bug in there. The line:

def __init__(self, direction, origin = Vector(0, 0, 0)):

is wrong. Default arguments, such as the origin parameter is evaluated only when the module is loaded. Therefore, all Ray objects, whose origin Vector is created from the default argument, will share the same Vector instance.

>>> r1 = Ray(Vector(1, 2, 3)) >>> r2 = Ray(Vector(3, 2, 1)) >>> r1.origin.x = 33 >>> print r2.origin.x 33

That is certainly not what the programmer desired. Ray's __init__ must be fixed so that a new origin Vector is created every time the constructor is called with a default argument:

class Ray: def __init__(self, direction, origin = None): if origin is None: origin = Vector(0, 0, 0) self.origin = origin self.direction = direction

This is a fair bit uglier than the previous example. For me, these types of bugs are caused because I really, really do not like the if blaha is None: idiom. But I know it is time for me to just accept that you must never use mutable default arguments.

The behaviour is one of Python's warts which bites all newcomes to the language. Coming from languages where the norm is that function definitions are compiled, it is hard to grasp that Python actually executes them. The gotcha is documented in numerous sources:

So someone got the pretty logical idea that changing how default arguments is evaluated should be changed. It would both help newbies, reduce many lines of code and help developers write more correct code.

The idea was brought up on the Python-3000 mailing list. But was quickly rejected by the BFDL since it was a too big change and breaks orthogonality with class variables. And that was that. Well, there was also a few who even defended the current behaviour and thought that changing it would not help anyone. It must have been a long time since these people read introductionary material to Python and encountered the "do not use mutable default argument values!" warning. :)

But the proposed semantical change definitely was to big and it would break orthogonality with other language features. I just hope that someone else will invent a new and better way to solve the problem. Python's incapability of handling mutable default values nicely is a big wart that someone hopefully can find a solution for.

Simple to_string function in C

Most languages have ways to serialize objects to strings. But ofcourse, C does not have any. The difficulty of creating one in C, is that the string representation of the object must be freed afterwards. Let us say you have a Rectangle type with the fields x, y, width and height. You might write its to_string function like this:
char * rect_to_string (Rectangle *rect) { char buf[256]; snprintf (buf, 256, "(%d, %d)-(%d, %d)", rect->x, rect->y, rect->width, rect->height); return strdup (buf); }
Note that memory is allocated. A client must therefore make sure to deallocate the string when it is done with it:
char *s = rect_to_string (my_rect); printf ("my_rect is %s\n", s); free (s);
If you forget to free the string bad things will of course happen. You must also not use it inline:
printf ("my_rect is %s\n", rect_to_string (my_rect));
Because that will leak memory. The memory allocated inside strdup continues to live on, but the reference to that memory is gone. What you can, and should do, is to use a static buffer.
char * rect_to_string (Rectangle *rect) { static char buf[256]; snprintf (buf, 256, "(%d, %d)-(%d, %d)", rect->x, rect->y, rect->width, rect->height); return buf; }
Since no memory is allocated, the inline approach works ok. However, if you want the string to survive for any longer periods of times you must still allocate it. The following code demonstrates the bug.
char *rect1_str = rect_to_str (rect1); char *rect2_str = rect_to_str (rect2); printf ("The rectangles are: %s %s\n", rect1_str, rect2_str);
Both variables will point to the same static buffer. And because rect_to_string overwrites the contents of that buffer, only the string representation of rect2 will survive. The solution to this problem is to explicitly allocate strings that must survive:
char *rect1_str = strdup (rect_to_str (rect1)); char *rect2_str = strdup (rect_to_str (rect2)); printf ("The rectangles are: %s %s\n", rect1_str, rect2_str); free (rect1_str); free (rect2_str);
Even with this quirk, I believe the last method is superior. It is very nice to be able to just print out the contents of a struct such as a Rectangle and not have worry about memory problems.

Clickable HTML design

So I am once again fiddling with my blog. I almost get the feeling that I am already to old for the blog generation. It is easy to create something that looks "roughly good" using Blogspot's tools. But if you want to tune some details, it is virtually impossible. Or maybe I am just to stupid. I would like to change the line spacing, but it does not seem possible. Oh well, atleast the page is decently readable anyway. I wonder if I ever will be able to post nicely syntax highlighted code.

Quick guide to PyGTK on Windows

I found this to be non-trivial. Here are the steps you need to go through to get PyGTK to work in Windows:
  1. Download the Python 2.5 MSI installer. Direct link

    Install it to C:\Python25 and do not forget to add C:\Python25\bin to your PATH.

  2. Download the PyGTK EXE installer. Direct Link
  3. Download the GTK EXE installer. Direct link

    Install it in C:\GTK. It should automatically add C:\GTK\bin to your PATH. If it does not, do it manually.

  4. Download the PyCairo EXE installer. Direct link.

  5. Download the pygobject EXE installer. Direct link.
Maybe it is not that complicated. :)

SL:s nya priser

Stockholm-Nynäshamn Tur och Retur: 150 kr Månadskort: 1000 kr Dags för revolution snart?

AVL Tree in Python

Here is an AVL tree implemented in Python! Note that it is supposed to be "beautiful" and easy to read and not efficient, that is why both balance() and height() are recursive. I learnt the algorithm from C++ an Introduction to Data Structures which is an excellent book that I recommend. I hope this snippet is useful to someone:
# -*- coding: utf-8 -*- class Node: def __init__(self, data): self.data = data self.set_childs(None, None) def set_childs(self, left, right): self.left = left self.right = right def balance(self): lheight = 0 if self.left: lheight = self.left.height() rheight = 0 if self.right: rheight = self.right.height() return lheight - rheight def height(self): lheight = 0 if self.left: lheight = self.left.height() rheight = 0 if self.right: rheight = self.right.height() return 1 + max(lheight, rheight) def rotate_left(self): self.data, self.right.data = self.right.data, self.data old_left = self.left self.set_childs(self.right, self.right.right) self.left.set_childs(old_left, self.left.left) def rotate_right(self): self.data, self.left.data = self.left.data, self.data old_right = self.right self.set_childs(self.left.left, self.left) self.right.set_childs(self.right.right, old_right) def rotate_left_right(self): self.left.rotate_left() self.rotate_right() def rotate_right_left(self): self.right.rotate_right() self.rotate_left() def do_balance(self): bal = self.balance() if bal > 1: if self.left.balance() > 0: self.rotate_right() else: self.rotate_left_right() elif bal < -1: if self.right.balance() < 0: self.rotate_left() else: self.rotate_right_left() def insert(self, data): if data <= self.data: if not self.left: self.left = Node(data) else: self.left.insert(data) else: if not self.right: self.right = Node(data) else: self.right.insert(data) self.do_balance() def print_tree(self, indent = 0): print " " * indent + str(self.data) if self.left: self.left.print_tree(indent + 2) if self.right: self.right.print_tree(indent + 2) if __name__ == "__main__": tree = Node(5) tree.insert(7) tree.insert(9) tree.print_tree()
I just had to update this so that it would use COLORS!

How to checkout Compiz

This is the command to check out Compiz: git-clone git://anongit.freedesktop.org/git/xorg/app/compiz

ACLs - or Where Windows Beat Linux

Windows have had them for years and just now are Linux distributions about to aquire them. Access Control Lists (ACLs) are necessary in situations where you demand more fine-grained access control than what the old Unix owner, group and world permission bits provide. If you need them, odds are you need them because you have a Samba file server. In this article, I will explain how you setup ACLs for Samba shares running on Gentoo. Also consult this howto for how to get the ACLs working. If you haven't done it already lately, start by syncing yourself: # emerge sync

The States Historical Roots

This is the second installement of my article series about Wikipedia's Ideological Bias. In this article I will deal with how Wikipedia represents the State of Israel's historical roots.

Bloggarkiv