Snåla SAS

Ibland skickar jag in insändare till tidningar. De blir aldrig publicerade, men det är kul att försöka. Den här handlade om SAS strejken.

Alla som har flugit vet hur stressande det kan vara att sitta på ett kvalmigt fullpackat försenat charterplan. Det är inget mot att ha det som sin ständiga arbetsplats. Kabinpersonalen förtjänar pauser och lunchpauser och att SAS nekar dem detta är dåligt. SAS gick med över en miljard i vinst förra året så de har råd att ge sina anställda drägliga anställningsvillkor. Att de har ratat kabinpersonalens bud är inget annat än ren och skär snålhet.

Tools for GtkImageView

I have decided that I want to extend the GtkImageView widget to make it extensible. Right now, it handles showing images that you can zoom in on and drag around. It will be extended so that you can do the following things:

  • Drag a selection on the widget. Very similar to how gThumbs Image->Crop dialog works.
  • Various kinds of drawing operations.

I thought about implementing this as "tools":


+------------+
|            | 1     1 +-------------+
|GtkImageView| ------> |GtkIImageTool|
|            |         +-------------+
+------------+              |_____________________
                           /                      |
                 +-------------------+ +--------------------+
                 |GtkImageToolDragger| |GtkImageToolSelector|
                 +-------------------+ +--------------------+

In this diagram, GtkImageView has a reference to a GtkIImageTool which is an interface that abstracts out certain behaviour of GtkImageView. GtkImageToolDragger and GtkImageToolSelector are two concrete implementations of the GtkIImageTool interface. When GtkImageView references a GtkImageToolDragger, it behaves like normal. You have a hand cursor and can drag the image. When GtkImageView references a GtkImageToolSelector, it instead displays a selection cursor and you can make a rectangular selection on the image.

Using this arrangement, it is now possible to dynamically alter the behaviour of GtkImageView.

GtkImageView *view = GTK_IMAGE_VIEW (gtk_image_view_new ()); GtkImageToolSelector *selector = gtk_image_tool_selector_new (); gtk_image_view_set_tool (view, selector); /* The user can now make some selections on the image. We can query which area of the image that is selected. */ GdkRectangle rect; if (!gtk_image_tool_selector_get_selection (selector, &rect)) printf ("Nothing is selected!\n"); else printf ("You selected (%d, %d)-(%d, %d)\n", rect.x, rect.y, rect.width, rect.height);

It should be possible to achieve this, but the interface that GtkIImageTool will specify, might become to fat.

/* These are needed because the tool needs to be able to decide what happens when mouse events occur. */ gtk_iimage_tool_button_press () gtk_iimage_tool_button_release () gtk_iimage_tool_motion_notify () /* The tool needs to decide what the default cursor is. */ gtk_iimage_tool_get_default_cursor () /* The tool may need to do something when the pixbuf of the view is changed. */ gtk_iimage_tool_set_pixbuf () /* The tool will want to draw the image in a special way. */ gtk_iimage_tool_draw_pixbuf_data () /* The tool will want to tell GtkImageNav how the image data should be drawn as a thumbnail. */ gtk_iimage_tool_get_display_pixbuf ()

Tired of DocBook

Spent some time trying to find out how to write definition lists in DocBook. DocBook is the markup language used by gtk-doc and consequently the tool I am using for writing documentation for GtkImageView.

... And I am very, VERY sick of it. It turns out it was fairly simple (heh), all you have to do to create a list of directories and paragraphs is this:

<variablelist><title>Font Filename Extensions</title> <varlistentry><term><filename>TTF</filename></term> <listitem> <para> TrueType fonts. </para> </listitem> </varlistentry> <varlistentry><term><filename>PFA</filename></term> <term><filename>PFB</filename></term> <listitem> <para> PostScript fonts. <filename>PFA</filename> files are common on <acronym>UNIX</acronym> systems, <filename>PFB</filename> files are more common on Windows systems. </para> </listitem> </varlistentry> </variablelist>

The result is almost exactly what you could have accomplised using this HTML:

<dl> <lh>Font Filename Extension</lh> <dt><tt>TTF</tt></dt> <dd>TrueType fonts.</dd> <dt><tt>PFA, PFB</tt></dt> <dd>PostScript fonts. <tt>PFA</tt> files are common on UNIX systems, <tt>PFB</tt> files are more common on Windows systems.</dd> </dl>

And of course, even less markup is needed if you use reStructuredText.

My search for a decent documentation writing system continues.

It is official!

It is official! GtkImageView is now released!

Here is the whole release announcement reprinted in full, just for fun:

I'm pleased to finally announce GtkImageView 1.0.0:

Description

GtkImageView is a simple image viewer widget for GTK. Similar to the image viewer panes in gThumb or Eye of Gnome. It makes writing image viewing and editing applications easy. Among its features are:

  • Mouse and keyboard zooming.
  • Scrolling and dragging.
  • Adjustable interpolation.
  • Fullscreen mode.

Download

Check it out from Subversion:

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

Or download the latest release tarball:

http://trac.bjourne.webfactional.com/attachment/wiki/WikiStart/gtkimageview-1.0.0.tar.gz

API documentation can be found by browsing to the ./docs/reference/html/index.html file.

Project website: http://trac.bjourne.webfactiona.com

Examples

Here is the canonical example for using the widget:

#include <gtkimageview/gtkimagescrollwin.h>
#include <gtkimageview/gtkimageview.h>
...
GtkWidget *view = gtk_image_view_new ();
GtkWidget *scroll = gtk_image_scroll_win_new (GTK_IMAGE_VIEW (view));

/* Where "box" is a GtkBox already part of your layout. */
gtk_box_pack_start (GTK_BOX (box), scroll, TRUE, TRUE, 0);

GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ("someimage.png", NULL);
gtk_image_view_set_pixbuf (GTK_IMAGE_VIEW (view), pixbuf);

Future

  • Python bindings.
  • Perl bindings.
  • Gtk# bindings.

gtk-doc problems

My first reaction was that gtk-doc really sucks. For example, it requires you to write docstrings like this:

/** * my_function_name: * * Do stuff. **/ void my_function_name (GtkWidget *widget) { }

You have to repeat my_function_name in the comment even though it should be extremely simple for the documentation generator to find out the name of the function the docstring is documenting.

There is apparently no way to group multiple source code definitions to one docstring. You can't write something like this and expect it to work:

/** * Defines the minimum and maximum allowed lengths of the name. **/ #define NAME_MIN_LENGTH 10 #define NAME_MAX_LENGTH 20

And despite writing docstrings using the weird format that gtk-doc imposes, you will still have to write separate API documentation using SGML. Yay! For each c-file gtk-doc documents, it generates a file called /tmpl/someclass.sgml which contains place holders for each symbol. Here is an except of one such file:

<!-- ##### SECTION Title ##### --> GtkImageNav <!-- ##### SECTION Short_Description ##### --> Popup window showing a thumbnailed overview of a #GtkImageView <!-- ##### SECTION Long_Description ##### --> <para> GtkImageNav is a popup window that shows a downscaled preview of the pixbuf that #GtkImageView is showing. The user can drag around an rectangle which indicates the current view of the image. </para> ...

Because gtk-doc likes to write to this file, you will have a hard time keeping it version controlled and you will have to periodically merge it with the real source code. gtk-doc therefore negates the main advantage of using a documentation generator tool which is to keep the documentation close to the source code.

I am sorry for all the complaining. gtk-doc is a decent tool and using it is better than writing all documentation is Latex, for example. But gtk-doc is not the only API documentation tool available. There is doxygen, JavaDoc, Epydoc and a whole host of other documentation generators. gtk-doc just manages to be worse then all of them.

Red wine

I like the mellow taste of red wine. I wish I had some cheese too. But alas, I only have bananas. I wish I could drink red wine and code all night. It can't be. I have work tomorrow. I don't like it, and they don't like me. Maybe if I'll drink enough I'll pass out. It is unlikely.

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.

Bloggarkiv