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.

Bloggarkiv