Magknip

Jag har ont i magen. Av sorg. Trodde inte jag skulle må dåligt av att göra slut. Kunde inte tänka mig att jag skulle sakna henne. Vill gråta men har inga tårar... Det är inte synd om mig. Allt är tråkigt och mörkt.

Tip of the day

if-statements in Makefile.am files cannot be indented. Thanks, that caught me off-guard.

Snip snapp snut,

så var förhållandet slut. :( Men det finns många fina tjejer kvar i världen och jag ska nog kunna hitta någon annan.

Public transport rocks

I read about the Blog Action Day on Slashdot and this is my "contribution."

For those who don't know, the object in the image is a tram. Trams are great because they run on electricity and not gasoline so they produce much less pollution than for example cars.

And this is an image of a commuter train. Those trains are also great because they don't pollute.

What is not so great is that not enough people use these services. The highways are crammed with cars (often with only a single person in them) trying to get in our out of the city centers. Trams and trains are great, but cars are bad because they pollute a lot.

What is not so great is that it costs you about 120 SEK to make a round trip from Södertälje to Stockholm. It's 160 SEK if you are travelling from Gnesta. That is to expensive. It takes longer and is not much cheaper to travel to Stockholm by mass transit than by driving a car. So if you have a car then you will use that to commute if you aren't particularly concerned about the enviroment.

Previously, it costed 40 SEK for a round trip to and from Stockholm. That price was much more palatable and quite a few people decided to use the mass transit instead of driving. It was changed because the current politicians thought it was to expensive for the state, but it was not. SL could have easily affored it, but the politicans prioritised tax cuts instead of social service.

Mass transit should be free, and it should be funded by taxes. Everyone should have equal and cheap access to travel for commuting and so on. Making the mass transit free is the simplest and cheapest way to drastically reduce carbon dioxide emissions and improving quality of life.

Lose weight with MIN, MAX and CLAMP

This article is related to two patches to cairo, #12717 and #12722. Many times in C, you want values in a certain range, or some that are not above or below a certain value. The process which ensures that values are within a certain range is called clamping.

Let us say that you have function that sets the position of something.

void set_pos (Obj *obj, int x, int y) { obj->x = x; obj->y = y; }

Further assume that the position must be contained within obj:s clip rectangle. That could be accomplished using this code:

void set_pos (Obj *obj, int x, int y) { // First clip the values if (x < obj->rect.x) x = obj->rect.x; if (x > obj->rect.x + obj->rect.width) x = obj->rect.x + obj->rect.width; if (y < obj->rect.y) y = obj->rect.y; if (y > obj->rect.y + obj->rect.height) y = obj->rect.y + obj->rect.height; // Then set them obj->x = x; obj->y = y; }

A mathematical way to write the clipping would be something like:

obj->x = x, obj->rect.x <= x <= obj->rect.x + obj->rect.width
obj->y = y, obj->rect.y <= y <= obj->rect.y + obj->rect.height

Time to introduce the MIN and MAX functions and see how they can help us. In C, they can be implemented as macros.

#define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b))

It should not be any surprise that

x = MAX (x, obj->rect.x)

and

if (x < obj->rect.x) x = obj->rect.x;

is exactly equivalent. We can therefore rewrite the boundary checking code in set_pos to take advantage of these macros:

void set_pos (Obj *obj, int x, int y) { x = MAX (x, obj->rect.x); x = MIN (x, obj->rect.x + obj->rect.width); y = MAX (y, obj->rect.y); y = MIN (y, obj->rect.y + obj->rect.height); obj->x = x; obj->y = y; }

But wait, there is more! The code can be further rewritten if we introduce a CLAMP macro.

#define CLAMP(x, l, h) (((x) > (h)) ? (h) : (((x) < (l)) ? (l) : (x)))

Now we can make the set_pos function even more readable:

void set_pos (Obj *obj, int x, int y) { obj->x = CLAMP (x, obj->rect.x, obj->rect.x + obj->rect.width); obj->y = CLAMP (y, obj->rect.y, obj->rect.y + obj->rect.height); }

Note how similar this code is to the imagined mathematical definition. It is also worth noting that the CLAMP macro doesn't work if the value of the upper bound is lower than the lower bound. That is, if obj->rect.width or obj->rect.height is negative, then the macro will give erroneous results.

Crashing is good for you

Found this post from Ryan Lortie interesting. Apparently, the optimization in this recent bug report will crash quite a lot of programs.

Totally great, now developers finally are forced to fix their (null) strings they dump in output and in configuration files. Programs become more portable and developers learn the important lession of being careful with NULL, what's not to like about that? :)

I very much like the way the gcc developers are going even if their changes affects me too. They seem to fully realize that following specified standards is much more important than preserving backwards compatibility.

Remember, what doesn't kill you only makes you stronger!

Interfaces uglier than C

I'm not to happy with what PyGTK does with my interfaces. In C, an implementation of GtkIImageTool looks like this. In Python, it looks like this:

import gobject import gtkimageview class MyTool(gobject.GObject, gtkimageview.IImageTool): def __init__(self): gobject.GObject.__init__(self) self.crosshair = gtk.gdk.Cursor(gtk.gdk.CROSSHAIR) self.cache = gtkimageview.PixbufDrawCache() def do_button_press(self, ev_button): pass def do_button_release(self, ev_button): pass def do_motion_notify(self, ev_motion): pass def do_pixbuf_changed(self, reset_fit, rect): print 'pixbuf changed' def do_paint_image(self, draw_opts, drawable): self.cache.draw(draw_opts, drawable) def do_cursor_at_point(self, x, y): return self.crosshair gobject.type_register(MyTool)

There are quite a few ugly warts here.

class MyTool(gobject.GObject, gtkimageview.IImageTool):

You have to subclass gobject.GObject, which I really would rather not. The whole point of writing programs in Python is to get rid of the stupid, annoying and complicated GObject system. Same for gtkimageview.IImageTool -- this is Python and you have duck-typing. You shouldn't need to subclass anything.

def do_cursor_at_point(self, x, y):

And why does PyGTK decide that all my interface methods should be prefixed with do_? I didn't tell it to do that. It is an extremely unpythonic convention.

gobject.type_register(MyTool)

Yet another GObject-ism. It would be plain simple to get rid of this step by making gobject.GObject a metaclass that registers the class when it is constructed. But no, PyGTK wants to remind you that you really are dealing with a C API and nothing more.

gobject.GObject.__init__(self)

As before, initialization like this shouldn't be needed for a plain Python class.

return self.crosshair

Don't try to return None, PyGTK:s code generator doesn't understand that an interface function can either return an object pointer or NULL.

But worst of all is probably that if you forget to do any of this, then IT WILL CRASH. Don't expect a nice exception, at best you'll get a cryptic GTK warning and a segfault with debug symbols.

PyGTK:s handling of GInterfaces is, as shown, currently very weak. But I expect it to be improved upon in the future. Meanwhile I'm thinking that PyGTK:s wrapping system with definition and override files isn't that good to begin with. It is fairly easy to whip something up fast, but when you want to make your binding pythonic, you run into problems.

I wonder if it wouldn't be possible to use ctypes to create more pythonic bindings with.

Fucking spam filter

GMail's spam filter seems to have gotten worse lately. Lots of "you have won!!! blaha blaha" is getting through and at the same time many non-spam mails to mailing lists are classified as spam. Why should it be so hard for GMail? They could just calculate a hash or check sum for each mail on their servers. Then if more than say 10,000 GMail users receive the exact same mail it must be spam. Problem solved, no?

Why write documentation?

This post is spurred by this blog post and Benjamin Ottes follow up. I'm not complaining on them, I just got the inspiration from their posts. A pet peeve of mine is the low quality of developer documentation available in the free software community and especially the permissive culture around it.

More than once at GUADEC did I hear someone say something along the lines

We have the implementation for our $GREAT_LIBRARY complete and we think you should use it.. But uh, sorry no documentation yet. We suck :)

You're damn right you suck! If you can't be assed to write decent enough documentation, then I can't be assed to use your code. Most often the excuse is that the source code is available so you shouldn't need so much documentation. Well, that argument is wrong for two reasons:

  1. Your code is probably not as easy to follow as you might think it is. All programmers think it is hard to read someone elses code, much harder than to write code yourself. Especially when that code lacks explanatory comments.

  2. It doesn't answer the question about how the code should behave. Here is an example:

    void some_lib_set_foo_bar (Lib *lib, FooBar *foo) { lib->foo = foo; }

    Innocent looking enough? Is foo allowed to be NULL? According to the above code it is, is that a feature or an oversight? If you only have the source code available, the only way to find out is to go through all source code and try and find code that assumes that foo is non-NULL. If you find code that assumes that foo is non-NULL, then some_lib_set_foo_bar() must not be called with a NULL foo. Otherwise NULL might be ok, but who knows?

Undocumented code that is only meant to be used by yourself is no problem, but if you write a free software library and announce it to the world, then ofcourse you want users, don't you? Users are great, they are willing beta testers of your software and are capable of providing you with great feedback and bug reports. They are doing their part by testing your code, shouldn't you do yours by providing them with documentation?

I also firmly believe that how successful your code is, is directly proportional to how well you have documented it. Documentation makes users happy, happy users use your code. Unhappy users find other tools to do their jobs.

A classical example is Subversion. Subversion is the most successful free Version Control Software (VCS) in the world. It is also the most well-documented one -- it even has a free book. But most experts in the area of VCS believe that the new Distributed Version Control Software (DVCS) basically whips Subversions butt. That is how much better software like bazaar, darcs and git is.

The catch is that their documentation isn't nowhere near as good as Subversions. So Subversion continues to be the undisputed leader of VCS until something comes up that can rival its documentation.

So please write good documentation. I know it is hard work, roughly 50% of the work in my GtkImageView project has been spent writing documentation. Of the remaining 50%, about half was spent reading about GObject internals. I still expect it to be a good investment. Documentation attracts users, users provide feedback which leads to better and more stable code.

Things have gotten better in the last years, few libraries are released without any documentation. But it still isn't as good as it can be. It truly sucks when you see a library that you know is awesome which you can't use because of incomplete documentation. Please fix it!

PyGTK on Windows

When installing PyGTK on Windows, don't forget that you must run a new cmd.exe for the changes to take effect. The PATH environment variable needs to be updated to include the path to the GTK+ libraries which by default are installed in c:/GTK/bin.

Is i magen

Såg på Nyhetsmorgon om "turbulensen" på börsen. Kul skit. Naturligtvis ska man, enligt förståsigpåarna, som småsparare ha is i magen. Sälj inte, stormen bedarrar, allt fixar sig. Varför ljuger SVT en rätt upp i ansiktet? Och varför är det alltid småspararna som ska ta det lugnt samtidigt som de stora bolagen dumpar sina aktier?

Efficient scrolling in X11

Lately, I've been trying to make scrolling as efficient as possible. On the surface, it is a simple problem, the algorithm is like this:

def scroll(surface, xscroll, yscroll): # Scroll it. Auto clip in case xscroll or yscroll is negative. surface.draw(surface, xscroll, yscroll) top = (0, 0, surface.width, yscroll) left = (0, 0, xscroll, surface.height) bottom = (0, surface.height + yscroll, surface.width, -yscroll) right = (surface.width + xscroll, 0, -xscroll, surface.height) # Filter out the ones to redraw. rects = [rect for rect in top, left, bottom, right if rect[2] * rect[3] >= 0] for x, y, width, height in rects: # Assume redraw is the expensive step. redraw(surface, x, y, width, height)

So, if you scroll a surface of size 100x100 20 steps to the right and 20 steps down the rectangles become:

xscroll = 20
yscroll = 20

top = (0, 0, 100, 20)
left = (0, 0, 20, 100)
bottom = (0, 120, 100, -20)
right = (120, 0, -20, 100)

bottom and right whose area is negative becomes discarded and you are left with two rectangles totalling 4000 pixels (100 * 20 + 100 * 20) to redraw which is not so bad.

The problem is that this algorithm is freakishly hard to realize on X11 without theComposite extension. X11 doesn't store your surface, so how are you going to redraw it? You could store it yourself, in a GdkPixbuf for example. However, that would mean that the data is stored client side and you'll run into slowdowns when transferring it to the X11 server.

... Client-server is great for some things, but definitely not for computer graphics.

GdkPixbufs are drawn with gdk_draw_pixbuf() which should (or could) be a fast operation because it uses XShmPutImage(), but it is not. GdkPixbuf has a different format from the one that X11 want's so you run into a slowdown caused by the format mismatch.

Next attempt, use a GdkPixmap as the cache. surface.draw(surface, xscroll, yscroll) becomes one fast call to gdk_draw_drawable(). But it still isn't fast enough because pixmaps aren't easy to work with. There is no gdk_pixbuf_scale() equivalent for drawables so we still have to use a pixbuf to store the result of the scale operation. That pixbuf then has to be blitted to our pixmap cache which is then blitted, for real, to the XWindow we are drawing on. In effect, we are using triple buffering and redraws becomes to slow.

Third attempt, use the actual drawable we are drawing on as the cache. It would work except that it totally breaks down when the window is minimized, then your cache is gone.

GtkImageView uses a combination of the first and third method. It special cases scrolling operations and uses the third method to redraw them. By setting exposures to true, it detects when occluded areas becomes visible and then redraws them using the first method. That is far from ideal but is more or less the best thing you can do without composite.

Halfway through GUADEC

And it has been great so far. People in Britain are very friendly and helpful. Me and my girlfriend has been at in average four talks per day. We arrived late in the Sunday night, so we missed the whole first and second day.

Britain as a country is very similar to Sweden, it almost feels like being home except that the language is different. It's funny how many and varied warning signs they have. There are warnings everywhere, for example "Caution! This door may close at any time!" But the warnings at the zebra crossings that tells you to look left or right are very useful. It is completely weird seeing the traffic going in the wrong direction all the time.

The food is cheap but quite bad. Chips are served with about every meal. Best food eaten so far was from a stand at the coach station that sold "Mediterranean Rolls" they tasted really great. Oh, and you don't have to pay tips! That's very much a plus. At least I don't think so, the waitresses and cashiers didn't seem pissed off when we didn't.

The best talk so far was the lightning talk with Michael Meeks and Federico Mena-Quintero. If a memory access is the distance from your nose to your brain, then a disk seek is all the way to the Middle East. Fun stuff. Havoc Pennington and Bryan Clark held their keynote about, unsurprisingly, the Online Desktop. They definitely have the right ideas, but I'm not attracted by their purple "mugshot" client.

Some developer from Beagle held a talk about metadata in which he said that Tracker was unfocused. It will be "interesting" to hear Jamie McCrackens retort in tomorrows talk. :-P Hurray for Open Source Soap Opera.

Alex Gravelys keynote was boring. If you have only one hour, plan for 30 minutes. It seemed like he would have needed at least three hours to communicate everything he wanted to say.

Some poor Eastern European developer got his lightning talk ruined by computer problems. It was fun, but sad that people where laughing seemingly at him. I'll definitely try out his git GUI front end anyway.

Carl Worth and Behdad Esfahbod held a very interesting talk about how the Cairo community has evolved. They are both very good speakers and the topic was interesting. I wanted to ask them how Cairo could be slower than the older xft toolkit. I mean, when you write new code, you usually try to make it faster than the old code you are replacing right? Unfortunately, I didn't have the guts.

Before that, there was a talk about building a modern multi-user desktop. The main thing I took home from that talk was that ConsoleKit, PolicyKit and HAL are boring.

Ari Jaaksi held a keynote about Nokia's involvement in open source. I don't like it so much I think. It's not like I can flash the firmware of their N800 and compile my own OS to run on it, is there? Besides, the device (which has been on sale for several months) had stability problems. Yes I'm biased because I work for a competing company. But retailing a product that is that easy to crash is just bad.

I only saw the end of the libgnomedb talk with Murray Cumming. It was quite interesting. But I don't understand why he didn't understand what I meant when I asked him which libraries libgnomedb was related to. Not many ideas are new in the DB field, even if implementations can contain innovations.

And the disaster of the week has been that my laptop broke. :( I thought I handled it very carefully, but there seems to be some seriously problem with the harddisk. Maybe it couldn't handle the British electricity current or something.

GUADEC it is!

Managed to book a last-minute trip to GUADEC, woho!! I'll be arriving at Stansted airport Sunday 15 July 18:20 with my girlfriend. We will be living at the Etap hotel with all the other GNOME:ies, it will be interesting to see how they look like. :)

Bloggarkiv