Favorit i Repris

Hade en urladdning med brorsan idag. Kom som ett brev på posten kan man säga. Jag hoppades att han skulle ha mognat lite under de två år sedan vi senast träffades. Men icke.

Jag kanske skulle presentera honom först eftersom jag aldrig nämnt något om honom innan i min blogg. Jag är 25 år gammal, han 23 och sålunda är han min enda lillebrorsa. Mammas senast födda barn och åtnjuter därför en speciell ställning i hennes ögon. Grejen är den att han är mer socialt kompetent än mig, mycket mer. Det är inte så att jag är speciellt folkskygg eller har svårt att prata med folk, men han är ett proffs på socialt umgänge. Brorsan bor i Göteborg medans jag för cirka sex år sedan stadgade mig i Stockholm. Under de gångna sex åren har jag utvecklats väldigt mycket, mitt liv, sätt och utseende är helt annorlunda än innan jag flyttade.

Iallafall, över Jul och Nyår brukar jag återvända till Göteborg för att fira högtiderna med bror, mor och hennes nya gubbe. Ungefär samma historia upprepar sig år efter år. En fin tradition som stärker själen och återbekräftar varför jag har valt att bo i Stockholm, långt ifrån dem. Det här året anlände jag den 23:e, en dag innan Julafton. Det var tänkt att jag skulle slagga i broderns lägenhet medan han och hans flickvän firade Jul i Spanien. Men de hade så tråkigt där att de sket i det och avbröt semestern redan efter ett par dagar.

Jag känner inte så många i Göteborg och brukar därför hänga med min brorsas polare. Det tar tid för mig att skaffa mig vänner och en vecka vart eller vartannat år är alldeles för lite. Festerna är alltid väldigt roliga och av vad jag förstått så tycker de att jag är en trevlig person.

Detta året skulle ha blivit lite annorlunda. Eftersom brorsan var i Spanien var planen att jag skulle träffa nya människor samt att träffa mina bekanta "på egen hand" så att säga. Men så blev det naturligtvis inte. Och dagarna som har gått har varit ganska normala. Tills idag vill säga. Dagen börjar med att morsans make ger brorsan och hans flickvän skjuts till ikea. Jag hinner naturligtvis inte med på grund av att jag nyss vaknat och det går såklart inte för sig att vänta. Varför nämner jag det här? Jo, därför att det var ett medvetet val av min bror att få mig att inte hinna.

Flickvännen, brodern och maken kommer sedan tillbaka till lägenheten två timmar efter stängningsdags på ikea och brodern deklarerar att han och hon ska till flickvännens lägenhet och laga mat och titta på film. Alright säger jag, men hur ska jag göra om jag vill gå ut då utan någon nyckel? Brodern undrar ifall jag säger detta bara för att jävlas eller om jag verkligen tänker gå ut. Jag svarar att det är 50/50, att jag kanske ska gå ut men är inte säker. Jag frågar ifall det är ok om jag lämnar dörren olåst när jag går ut, då jag inte kan låsa dörren. Får ett jakande svar.

Tänker inte mer på det utan glor lite på tv och lagar lite mat. Vid tolvtiden känner jag att det börjar bli lite tråkigt och bestämmer mig för att gå ut själv. Det är trots allt lördag och det finns roligare saker att göra än att sitta hemma. När jag kommer utanför porten och försöker försäkra mig om att portkoden fungerar inser jag mitt misstag. Man måste tydligen ha nyckeln för att öppna dörren efter klockan 21:00 eller så. För att inte tvingas slagga i ett trapphus igen ringer jag brorsan. Tänker att vi måste ses någonstans så att han kan lämna över nyckeln till mig. Inget svar. Ringer flickvännen ett par gånger. Inget svar där heller. Därefter testar jag att ringa morsan som lyckas få tag i broderns flickvän. Vid det här laget är jag asförbannad och tycker att jag blivit dåligt behandlad hela dagen, men jag får inget medhåll. Det gör mig ännu argare och ledsnare.

Historien fortsätter, men jag ska sluta nu. Läs mellan raderna, det är där känslorna ligger.

Get free memory in Erlang

Here is how you get the amount of free memory available in Erlang:

17> application:start(os_mon).
...
18> memsup:get_system_memory_data().
[{total_memory,2125283328},
 {free_memory,188440576},
 {system_total_memory,2125283328}]

Minnesläcka

Jag hatar minnesluckor. Vet inte varför jag har en från igår kväll. Måste varit jättetrött för jag drack inte speciellt mycket. Bara två eller tre glas absint. Vi lyssnade på Fela Kuti och jag dansade lite själv. Vad hände sen då?

Vaknade klockan 10:20 påklädd i hennes säng. Trodde att jag var hemma, men det var jag inte. Inga spår som skulle kunna förklara någonting. Snövit var där, fast han verkade undvika mig. Han undrade nog vad jag gjorde. Världen kändes inte verklig och jag undrade om jag drömde. Jag måste tillbaka ikväll och leta efter ledtrådar.

Jag var väldigt törstig och köpte en yogurtflaska att dricka. Av någon anledning var jag mycket ledsen. Jag ville gråta och ögonen var fuktiga.

Kommer ihåg bröst. Röd blus och svarta byxor. Små tuttar. Tafsade jag på henne? Antastade jag henne? Nähä?? Var det en dröm. Antastade de mig? Jag brukar inte drömma porriga drömmar när jag är full. De sitter på flyget just nu och jag kan inte ringa och fråga.

Det är dags att bli försiktigare med spriten.

Joining stringlists

Here is how you join a list of strings in elisp:

(mapconcat (lambda (x) x) load-path "\n")

It is equivalent to this Python code:

'\n'.join(stringlist)

Example of the LZW algorithm

This is probably old stuff for most of you, but here is my Python implementation of the LZW algorithm.

# The initial LZW tables that maps codes to strings and vice-versa. code_to_str = [chr(i) for i in range(256)] str_to_code = dict((chr(i), i) for i in range(256)) def compress(seq): ''' Returns an LZW compressed list of the input character sequence. ''' output = [] table = dict(str_to_code) s = '' for ch in seq: it = s + ch if it in table: s = it else: output.append(table[s]) table[it] = len(table) s = ch output.append(table[s]) return output def decompress(seq): ''' Returns a decompressed list of the LZW compressed input. ''' table = code_to_str[:] prevcode = seq[0] output = [] output.append(table[prevcode]) for code in seq[1:]: try: entry = table[code] except IndexError: # The lzw special case when code is not yet defined. entry = table[prevcode] entry += entry[0] output.append(entry) table.append(table[prevcode] + entry[0]) prevcode = code return output

Used like this:

data = open('somefile.txt').read() data = compress(data) print decompress(data)

Explanation for how the algorithm works can be found in other places on the net.

Mina nya glasögon

I fredags var jag i Stockholm och hämtade mina nya glasögon. Jag har aldrig haft glasögon förut men eftersom jag märkt att min syn blivit sämre på längre avståd gissade jag på att jag kanske behövde ett par. Det är svårt för mig att läsa skyltarna i t-banan och stationsklockorna även på relativt korta avstånd.

Så jag gjorde ett syntest förra veckan på BlicOptik i Solna Centrum. Där finns det en jättestor galleria som heter Solna Torg där butiken ligger. Enligt syntestet ser jag såpass dåligt att jag precis måste ha på mig glasögon när jag kör bil. Men tur då att jag inte har varken bil eller körkort.

Optikerbutiker är jobbiga tycker jag. Det fanns alldeles för många olika fina glasögonmodeller att välja mellan. Tillslut valde jag två stycken par eftersom butiken hade ett erbjudande där man fick köpa två stycken för samma pris som ett. Det ena paret var ett par svarta kantiga glasögon med två millimeter tjocka bågar runt glasen. Jag tyckte de var snygga eftersom bågarna passade bra och eftersom underkanten på glasögonen var i silver. Dessutom var det extremt svårt att hitta glasögon som jag inte tyckte var för breda.

Det andra paret var också svarta fast med ultratunna böjbara skalmar. Jag tycker inte att de var lika snygga som det första paret men optikern som hette Stephanie och som hjälpte mig med smakråd tyckte de var snyggare.

Det är fan svårt att veta tycker jag vilka glasögon som är snygga. Eftersom de sitter precis mitt i ansiktet vill man ju att de ska vara så fina som möjligt. Men samtidigt tänker man inte ofta på hur de ska se ut. Tänk om de reflekterar ljuset på ett sådant sätt att ögonen ser extra små ut? Då ser det ut som om man har grisögon och det är inte bra. Kanske gör för breda och mörka bågar att man ser sur ut? Ungefär som ett extra par ögonbryn. Det är heller inte bra.

Enligt Amanda såg jag sur ut i de glasögonen som Stephanie tyckte bäst om. Det kanske stämmer, men hur kan man se det? Som tur är behöver jag inte ha på mig glasögonen jämt, utan endast när jag ska titta på TV, bio eller liknande. Det kommer nog att ta lång tid att vänja sig vid dem. :(

Positivt att de fungerar som de ska iallafall. Tydligen har världen en massa detaljer som jag aldrig tidigare lagt märke till. Allting är extremt skarpt och jag kan se folks ansikten på myckte längre håll än jag kunde innan. Speciellt att titta rakt ner i backen är intressant. Eftersom bilden är extremt skarp känns det som om marken är mycket närmare än vad den egentligen är.

Känns mycket bättre nu

Hon och Urban är tydligen ett officiellt par nu, med allt vad det innebär. Jag säger bara en sak: stackars Urban! :) Han kommer får stå ut med mycket innan ljuset går upp för honom. Man måste vara mycket korkad eller desperat för att inleda ett förhållande med den flickan.

Värdelöst

Jag hatar Urban, jag hatar Mai. Varför blev det så här? Skit och fanskap! Jag vill inte vara utan henne. Hon är kall, hård och elak men jag måste ha henne. JÄvla helvete.

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. :)

No GUADEC for me

I wish I could go to GUADEC this year. But the flight and accomodation turns out to be to expensive. :( Why didn't I think of that earlier? Than I could have booked a cheap flight and hotel. Arg!

Quote of the Week!

Management and IT there might well be clueless but I am new there and don't want to say that yet.
That is the smartest thing I have read all week. :)

Grabbing URL:s with style

urlgrabber is a fairly nice Python package for grabbing URL:s. The documentation is kind of sparse, but reading the source is easy enough.

Here is a simple example:

from urlgrabber.grabber import URLGrabber
from urlgrabber.progress import TextMeter
    
grabber = URLGrabber(progress_obj = TextMeter())
grabber.urlgrab('http://www.python.org/ftp/python/2.5.1/Python-2.5.1.tar.bz2')

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.

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. :)

Bloggarkiv