Ikke's Blog

Archives for: 2007

Dec 26
Blog moved

This blog is moved. You can find my new blog on http://eikke.com. Thanks for visiting!

Dec 14
Python strangeness

Could someone explain this?


list = (
    (0, 'foo'),
    (1, 'bar'),
    (2, 'baz'),

class Klass:
    def bat(self):
        print '-1'

for l in list:
    if not hasattr(Klass, l[1]):
        print '%s should print %d' % (l[1], l[0])
        def _f(self):
            print l[0]
        _f.__doc__ = 'Get %s' % l[1]
        setattr(Klass, l[1], _f)

k = Klass()
print 'Docstrings:'
print 'Foo:', k.foo.__doc__
print 'Bar:', k.bar.__doc__
print 'Baz:', k.baz.__doc__


print 'Executed:'
print 'bat:',
print 'foo:',
print 'bar:',
print 'baz:',


print 'Locations:'
print 'bat:', str(k.bat.im_func)
print 'foo:', str(k.foo.im_func)
print 'bar:', str(k.bar.im_func)
print 'baz:', str(k.baz.im_func)


foo should print 0
bar should print 1
baz should print 2

Foo: Get foo
Bar: Get bar
Baz: Get baz

bat: -1
foo: 2
bar: 2
baz: 2

bat: <function bat at 0xb7c58e2c>
foo: <function _f at 0xb7c58df4>
bar: <function _f at 0xb7c58f0c>
baz: <function _f at 0xb7c58f44>
$ python -V
Python 2.4.4

Maybe I'm just missing something... Don't flame ;-)

Nov 9
More Clutter

This afternoon I wanted to implement some custom ClutterActor. I made a very basic actor which is basicly a simple rectangle, like ClutterRectangle, but allows you to define a color for every corner, which are blended by OpenGL.

Like this:

I also added a simple animation sequence which changes all corner colors over time, so you get some visual effect, and added some motion effects (a simple rotation around 2 axes). The color changing effect is badly written now, should become a ClutterBehaviour, if possible.

Code is here, it could be a good starting point to learn how to write a custom actor using OpenGL (first time I ever wrote OpenGL code myself, it's not that hard, more experimenting later).

Performance and anti-aliasing is rather sluggish now, but I don't think it's related to my code as doing the same rotations on a single-color ClutterRectangle gives the same result.

Oh: yes, this code leaks at exit.

Enjoy :-)

Nov 8
Clutter reflections

Clutter reflections

See src/view-reflection.c in your local gallery git clone. Suboptimal code, no slideshow (only displays the first picture for a given tag), but well.

Maybe I should try to load images (using GdkPixbuf or something alike), use GEGL to do some transforms on them (more optimized than my hackish filters :-P), then use these transformed images on a Clutter texture...

I wonder how hard it would be to play a movie using clutter-gst and add reflections of it.

Nov 8
Clutter, advanced UI graphics made fun

Today I looked at Clutter, a nifty "rich UI" creation library using OpenGL and the like. After playing around with some of the samples, reading some API docs and writing one dumb simple text-rotating application (think Windows' text-message screensaver, you know), I wanted to make something more advanced (hum-hum).

I decided writing some photo slideshow application would be cool. We already have several of those, obviously, remember this is just a playground.
Having some sort of F-Spot (a great photo management application) integration would be nifty too, so I started with that: loading taglists and picture-paths for one tag. In the end it turned out writing that took more time than writing the simple view I created.

Next I wrote the Clutter driver code and some system to be able to easily switch view functions. I only implemented one so far, which just fades between images (in, out, next image in, out etc) and stores the GdkPixbuf's in a ringbuffer. Not optimal, no cleanup code yet, jadajadajada.

No screenshots as a static screenshot would not be very impressive (the current application neither but hey ;-)).

Anyway, it might be useful as a sample/basic Clutter application for some people. You can find the source code, clone URL and compilation instructions here. If you implement some nifty view, share it!


Oct 29
Using your belgian eID for SSL authentication

Some time ago I got a very basic cardreader to use with my eID. It was fairly easy to get this working under Linux, only had to create one ebuild for the acr38 driver. Looks like you don't even need the Zetes/FedICT tools to do authentication in Firefox, the standard OpenSC libs work too.

For the record: what you need is opensc, pcsc, and the acr38 driver, that's about it to start playing around. The FedICT tools are nice to play around and view which data is stored on the card.

Anyway, on-topic now :-) In my previous post I wondered whether it'd be possible to get an SSL certificate, using the key on my card. Looks like this is easier than I thought :-)

You need to have openssl (du-uh) and engine-pkcs11 installed to do this.

To generate a request, open a console and launch openssh. Once at the OpenSSL prompt, issue these 2 commands:
engine -t dynamic -pre SO_PATH:/usr/lib/engines/engine_pkcs11.so -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre MODULE_PATH:/usr/lib/opensc-pkcs11.so
Adjust paths if necessary, of course. This loads the pkcs11 engine inside OpenSSL.
req -engine pkcs11 -new -days 100 -key id_02 -keyform engine -out myrequest.csr -subj "/C=BE/ST=O-VL/O=My Organisation/CN=My Name/emailAddress=my@email.tld"
Adjust the days, out and subj parameters, at least. The key ID can be found using
pkcs15-tool -cUse the ID of the Authentication X509 certificate.

You'll be asked to enter your PIN code, once this is done your certificate signing request will be stored in myrequest.csr (or whatever filename you chose), ready to be sent to some CA administrator, after which he can sign the request (added code to do this to CAAdmin some minutes ago, about to commit), send back the certificate, and you're all set.

How to use the certificate depends on your application, of course. You can add the pkcs11 authentication provider to Firefox, OpenVPN got some pkcs11-related settings, etc.

I'll try the OpenVPN stuff in a minute :-)

Pretty cool stuff, if this'd work... Both VPN and SSH authentication will be done using my eID if this turns out well.

Edit: right, I was able to sign my generated request (using my eID's authentication certificate) using our VPN's CA, but now I got some issue with issuer certificates: OpenVPN seems to look for an issuer certificate matching the C/CN/SN/GN/serialNumber of the certificate on my eID. This is, obviously, not the way I'd want it to work... Isn't it possible to tell OpenVPN to use some_file.crt as certificate, but use the key in some slot on my eID as key? Using PKCS11 seems to disable the ability to use file-based certificates :-(

Oct 29
Being a Certificate Authority made easier than ever

Lately at VTK we started to use SSL (and X509 keys) at more places than just one webserver. We figured out using a central CA (and not one per server) and managing keys centralised would be A Good Thing.

So I created a LUKS volume on one of our servers (which is only usable by us admins) to store CA data. OpenSSL is kinda tough to work with though (well, lots of commands with lots of command line parameters ;-)), so I decided to create some sort of text-based interface around it, inspired by OpenVPN's EasyRSA scripts.

I titled the end result CAAdmin. You can find a gitweb view (including pull URL) here if interested. Fixes or patches to add functionality are very welcome (email :-)).

Currently it allows you to:

  • Create a new CA
  • Generate server keys and certificates
  • Generate client keys and certificates (both password protected and without password)
  • List your CA's CRL
  • Create a CRL file to distribute to your servers
  • Revoke a certificate

Functionality to sign an incoming certificate request should be added. I'd love to figure out whether it's possible to use my (belgian) eID card (and reader): I can read the data on it and use it for SSH authentication, but I didn't figure out yet whether it's possible to pull out a signature request out of it, so I can use the private key stored on it to access some of our key-based SSL services... Any pointers?

Sep 8
Oh so true...

Spend 10 minutes collecting everything you need to work on a problem, and unplug the internet for 2 hours. You’ll finish in 30 minutes.

Matt Mullenweg

Ikke • LifePermalink 1 comment
Sep 3

Maths exam was a complete disaster, don't really know where to go next. Is it really that hard if one hasn't got a diploma to get a decent job (both now and in the far future)?

Ikke • LifePermalink 4 comments
Sep 2
Seam Carving: Content-aware image resizing

Most people most likely saw the YouTube movie on content-aware image resizing which got blogged quite a lot lately. I read the corresponding paper, and wrote an implementation (not finished/perfect at all, but well) in Python. If it would ever become "production quality" a Gimp and/or GEGL plugin would be nice.

Here's a sample:
Original image

Resized using Gimp, cubic interpolation, 150px
Resized using Gimp

Resized image, 150px
Resized using seam carving

Overview of removed pixels
Removed pixels

This transformation is done in about 2 seconds (mainly because of some calculations in pure Python. For most calculations I use the Python Imaging Library and SciPy/NumPy, which are mainly C modules and much faster). As you can see the implementation still needs lots of love.

You can see another sample (image resized from 1000 to 250px in 8 seconds) here.

Git repository is here. Please email any patches!

The algorithm itself is surprisingly "simple" and easy to understand, great job by the researchers! More on that later. I should be studying mathematical analysis now, 2nd time I got to redo this exam, bloody university :-(

Using very expensive algorithm
Expensive algorithm
This image was generated by:

  • Loading the input image
  • 150 times:
    • Calculate energy and cost of current working picture
    • For every pixel in the top row, calculate the cost of the "best path" starting at this pixel
    • Figure out which path is the cheapest
    • Create an image which is the working image, minus this best path
    • Replace the working image with the image generated in the previous step

This took 273 seconds on my system, as the complexity is something like O(150*N*N*N*N*N*N*M) where M is the complexity of the gradient magnitude calculation.
Conclusion: not a workable solution :D
Do notice there are significant changes between this image and the one posted above. As I wrote this as a quick hack, I didn't include code to show which paths were removed from the original image.

Aug 22
ReST + git + hooks = useful

Recently I had to write some article. There are several formats to write articles: one can use plain text, some use something like OOo Writer or MS Word, others use LaTeX, some XML fanatics use DocBook, etc. Personally I like writing texts in plain text format, especially using the ReST (ReStructured Text) markup, so the text document is very easy to read, including some basic formatting, and you can transform the text format to XHTML, LaTeX/PDF and several other formats using some simple tools provided by the DocUtils project.

As I'm using a plain text format, it's pretty useful to make use of some revision control system. And guess what, once again Git is a good choice ;-)

Now in this specific case, I got to have this article online too on my webserver. I got a bunch of public git repositories on that machine, including the one containing the article, but obviously this is not very useful as the HTML file rendered from the ReST source file should not be in Git.

So here's what I did: first I created a very basic Makefile which does the output file generation. Here it is:

RSTOPTS=--time --strict --language=en

HTML=$(foreach t,$(filter %.txt,$(txt_SOURCES)),$(basename $(t)).html)
PDF=$(foreach t,$(filter %.txt,$(txt_SOURCES)),$(basename $(t)).pdf)
TMPS=$(foreach t,$(filter %.txt,$(txt_SOURCES)),$(basename $(t)).txt.tmp)

COMMIT_DATE=$(shell git-show | grep ^Date | sed "s/^Date: *//")
COMMIT_REV=$(shell git-show | grep ^commit | sed "s/^commit *//")

default: all

%.txt.tmp: %.txt
        @sed -e "s/@DATE@/$(COMMIT_DATE)/" -e "s/@REV@/$(COMMIT_REV)/" $^ > $@

%.html: %.txt.tmp
        rst2html.py $(RSTOPTS) $(RSTHTMLOPTS) $^ > $@

%.pdf: %.txt.tmp
        rst2latex.py $(RSTOPTS) $^ > $(basename $@).tex
        pdflatex $(basename $@).tex
        rm -f $(basename $@).log $(basename $@).out $(basename $@).tex $(basename $@).aux

html: $(HTML)
pdf: $(PDF)

all: html pdf

        rm -f $(HTML)
        rm -f $(PDF)
        rm -f $(TMPS)

There are 3 variables on top you should/could edit: RSTOPTS which are the options passed to all rst2* tools, RSTHTMLOPTS which are the options passed to rst2html.py and txt_SOURCES, which is a simple list of all input files.

I also added functionality to add @DATE@ and @REV@ tags in your source files. These will be expanded to the commit date and commit/revision SHA1 sum of the tree you're working with. In ReST this is useful in the top part of your document where you define the author, contact address, version information, date,...

I committed this Makefile and my input ReST text file to some bare repository on my server (eg. /home/me/public_git/myarticle.git). Once this was done, I created a directory in my htdocs directory (let's call it "/home/me/public_html/myarticle"), chdir'ed into it, and made a clone of the repository: git-clone /home/me/public_git/myarticle.git

Now the Makefile and ReST file were in place, and I could run make html. After making a symlink to generate an index.html file which points to myarticle.html, it was available online.

Now one more feature had to be added: I want the public article HTML to be up-to-date with my repository, whenever I push new changes from my laptop to my server. This is very easy to achieve using git's hook script support. In /home/me/public_git/myarticle.git/hooks I created a file called post-update and ran chmod +x on it. Here's the content:

export GIT_DIR=$CODIR/.git
pushd $CODIR > /dev/null
/usr/bin/git-pull > /dev/null 2>&1
make html > /dev/null
popd > /dev/null

exec git-update-server-info

Now whenever I run git-push myserver in my local tree, this script is executed. When it runs, the checkout I got inside my public_html directory is updated, and the HTML file is rerendered, so the last version is online.

Pretty useful!

Aug 15
XKCD "Compiling"

Today's XKCD is just hilareous:

Aug 15
ASUS laptops, multimedia keys and INPUT

For quite a while on several systems where ACPI is used to deliver key press events to the operating system (mostly laptops, that's why we got the asus_acpi, thinkpad, toshiba, sony,... drivers in the kernel). In userspace acpid was used then to fetch these commands, a callout script was used which used some application to inject the corresponding keycode (based on the ACPI event ID, which is just "randomly chosen" by the hardware manufacturers) on some input device, so applications (eg your X server) were able to see the key press events. Especially the acpid -> callout -> map scancode to keycode -> inject in input device isn't such a "nice" solution, but it worked, most of the time.

Recently people (one of them Richard Hughes of GPM fame, you know, that power-eating applet ;-)) started to rework these in-kernel drivers to use the kernel input subsystem directly, so no more round-trip to userspace would be necessary.
There are 2 possibilities here: you can store a scancode to keycode mapping table in the driver itself, or you can remap scancodes to a keycode from userspace on some device using ioctl's.

This last method is made easy by HAL (0.5.10 or git), which includes a callout which allows you to store the mappings in an FDI file, and then performs the remapping when a matched device is found on the system. More information about this can be found here.

IMHO this method is the cleanest, as it doesn't force us to store big device-specific mapping tables in the kernel driver. It's userspace so much easier to make changes, add new device information,...

ASUS laptop owners couldn't make use of this yet as nor the in-kernel driver, asus_laptop, or it's -cvs version provide relaying to a kernel input device. Yesterday I decided to implement this, and today it got somewhat finished, after some minor issues. You can find the resulting patch here, it's against current acpi4asus CVS, but I think it should apply cleanly against a vanilla kernel too. I'll submit it to the acpi4asus list tomorrow. Git repository is here, you want the "acpi_keys_to_input_layer_no_internal_mapping" branch.

After compiling the driver and insmoding it (or modprobe if you install it too, make sure you don't load the old version by accident) you should see some information in dmesg: a message the driver is loaded, the name of your laptop model, and the fact a new input device called "Asus Extra Buttons" was created. Now when you press some multimedia buttons and check dmesg again, it should tell you some keys were pressed it can't map to a known keycode, also providing the scancode. You can use this information to generate an FDI file as described in the pages I linked to before.

If you're using an "old" HAL version, you can download a small utility here to emulate HAL's behaviour using hard-coded information. You need to make a list of scancodes and their meaning using KEY_* values. You can find these constants in /usr/include/linux/input.h, or in include/linux/input.h of your local kernel source tree.
Once you know which scancodes map to which KEY_* value, you can add them to the "mappings" variable defined at the top of the C file. The format is simple: scancode1, keycode1, scancode2, keycode2,...,-1. Make sure you always add pairs of scancode/keycode values, and end the array with a -1.

Once you entered the values, compile the program (gcc -o set-asus-keymap set-asus-keymap.c), figure out the event device node for the Asus Extra Buttons device (check /proc/bus/input/devices, where Name is Asus Extra Buttons, see which eventX is after Handlers), and run the program (as root) using ./set-asus-keymap /dev/event/eventX (now I don't want *any* comments on this entry regarding "I have no eventX node").

When you're done with this, create a nice FDI file too, and send it to the HAL mailing list so others can enjoy your research too :-)

That's about it, your special keys should "just work" and acpid is no longer necessary to handle them.

Aug 9
An introduction to the git bisect feature

Recently git is becoming a very popular revision control system for several projects. I tend to use it regularly too, both for my own projects, because it's used by a projects I hack on, or because I can get all powerful git features when working on a project which uses SVN as RCS (which is a good thing in some environments) through git-svn.

One of the very nice features of git is "bisect", which allows you to pin down the commit which broke code (or functionality) pretty easily. I used it eg. some days ago to figure out which commit in the "avivo" driver caused the driver to break on my system.

How does it work? Basicly, you clone a git repository, you start a bisect session, say "this commit did work", "this one doesnt work", and that's it. git will checkout a commit "in the middle" of the good and bad revisions, you compile/run/test the result, and tell git whether this version did work as expected or not. If it did work, git will checkout the revision between the current one (which was already at the middle between good and bad) and bad for you to test. If it did not work you'll get the revision in the middle of the "good" revision and the current one.
Think about binary search, it's similar (actually, bisect *is* a binary search).

This way you're able to figure out which commit broke the app in a very short time (unless it crashes your system and it takes 3minutes to boot ;-)).

There is even more: if your application got a nice test suite consisting of unit test and alike, you're able to automate the whole process. The only thing you need is some script/tool/... which runs the test suites and returns a 0 exit code on success, or something else on failure. If you got this, git will do the whole bisect automagicly and tell you without any intervention what broke your application.

To demonstrate this I wrote a simple script. You can find it here using gitweb, or git-clone http://git.nicolast.be/git-bisect-sample.git.

Once you got the script on your system, you can test it. It takes 2 arguments: the number of commits to make, and which commit should break the application. The script will create a branch, then start creating a simple bash script. All this script does is assign 0 to i, increment i and decrement i. Every revision one increment and one decrement will be added. At the "bad" revision, one more increment will be added though. At the end i is used as return value.
As you can see, before the bad revision the script will return 0, after it it will return 1, so it's a test suite on its own ;-)

Here's a sample run:

$ sh createrepo.sh 20 16
Switched to a new branch "git_bisect_test"
Doing commit number 1
Created commit 9ce7f50f937b4e0e82c9c7fe143bb0483eb8e308
 1 files changed, 5 insertions(+), 0 deletions(-)
 create mode 100755 testcase.sh
Creating good_tag
Doing commit number 2

Doing commit number 20
Created commit 0298fc50cb61eca005053a1c948f8651b2a346eb
 1 files changed, 2 insertions(+), 0 deletions(-)
Creating bad_tag

So, it created a branch called "git_bisect_test" (just to keep our repository clean), did a first commit, tagged this as "good_tag" (we assume our first commit is a working application here. The good and bad revisions shouldn't be tagged, but this makes it easier for us further on). Then the script is created/updated and committed 20 times, breaking at the 16th commit. At the end, "bad_tag" is created. Once again, this is not necessary at all.

Now we found out our application is broken, so we'll bisect to figure out where it broke.

$ git-bisect start
$ git-bisect good good_tag
$ git-bisect bad bad_tag 
Bisecting: 10 revisions left to test after this
[632c9c04b97578d674a2980648ee4ab748a8b147] commit number 11

We're at "revision #11".

No the magic can start:

$ git-bisect run ./testcase.sh
running ./testcase.sh
Bisecting: 5 revisions left to test after this
[d6514e8d9fe55827fe78d650548d948a4647fc50] commit number 16
running ./testcase.sh
Bisecting: 3 revisions left to test after this
[79e4ce719557e53c203789e1991f1ec00be823f7] commit number 14
running ./testcase.sh
Bisecting: 1 revisions left to test after this
[09f09d9a4e322a49b40de3f9d595f5132198c9b3] commit number 15
running ./testcase.sh
d6514e8d9fe55827fe78d650548d948a4647fc50 is first bad commit
commit d6514e8d9fe55827fe78d650548d948a4647fc50
Author: Nicolas Trangez < >
Date:   Thu Aug 9 23:43:48 2007 +0200

    commit number 16

:100755 100755 bd66b47cf24d9d3d00ac289395851d436b404774 ba01220423f64ea8b92a9df75c36a1a7ddda89ac M      testcase.sh
bisect run success

Exactly, like it should, it figured out commit 16 (well, git got no commit numbers, this is just the commit message to keep things understandable easily) broke our application.

All we got to do now is stop the bisect process

$ git-bisect reset

and fix our application by looking up a diff of the bad revision.

In this sample case we should also clear the cruft the createrepo.sh script created:

$ git-tag -d good_tag
$ git-tag -d bad_tag
$ git-checkout master
$ git-branch -D git_bisect_test

That's it. More information can be found in the git manual and in the git bisect manpage.

May 8
OpenOffice rant

As I wrote in my last entry, I did some presentation on Django yesterday.
I started creating this presentation some days ago, but still had to write most stuff yesterday. So in the afternoon, I took my laptop, sat back, and added new slides to the presentation.

I must confess, I'm not a frequent saver (will change now, read on). Anyway, when I had written +- 30 new slides, I pressed ctrl-s in OpenOffice Impress. Disaster strikes. All of a sudden, Impress crashes, and the OOo document recovery dialog pops up. Before recovering the document, I created a copy of the on-disk original file, then did the recovery. Result: same file as I had before the save, 30 slides lost.

The problem: my / partition (on which /tmp resides) was at 100% (only some bytes left). The reason: some beagled-helper got >150MB .tmp files left in there.
I almost went insane.


  • OOo guys, *please* make your app not crash when a user attempts to save a file and /tmp is at 100%. Use some other scratch location, warn the user (and make a quick backup/recovery dump automagicly in case something goes wrong),... whatever, but do not crash on a save operation, that's completely irrational.
  • beagled-helper, please remove cruft earlier and don't flood my /tmp, thanks


Ikke • DesktopPermalink 13 comments
May 8
Development-related presentations using Git

Yesterday I had to give some introduction presentation on Django, a Python-based web-application development framework (really cool, if you don't know it yet, take a look!).
The goal was to build some simple blog-like application during the presentation to give the audience an overview of the framework and some of it's basic capabilities (whilst still hand-coding everything, not using newforms/generic views/..., providing pointers to these great features though).

Obviously, at several points of the presentation, you got to show some example code. As most of the time you work on one source file during several stages of the presentation, you don't want to show the end file from the beginning, you want to incrementally add code.

There are some obvious ways to do this:

  • Type everything by hand at every stage
  • Have a source tree for each state in different directories
  • Give files a special name, like blog/models.py_slide19

These "solutions" got several problems though:

  • The first one is slow, error-prone and boring for the public
  • The second one is acceptable but uses a lot of diskspace
  • The last one is not acceptable as (in this case) because of the "wrong" filenames, you won't be able to run the django development server at the separate stages of development

The way I did it: put the code of your first slide in a (local) Git repository, create a new branch whenever you change code, check-out the branch, change the code and commit. Then when the presentation starts, git-check-out master, then everytime you're at a slide where you changed some code, git-check-out (name of the branch for this slide). I used "slideXX" as branch names, using just 1, 2, 3 etc might be better as my schema'd break if I had inserted a slide somewhere.

Really quick and easy to work this way!

Apr 28
How to fix your ACPI buttons, the hackish way

Some time ago my ACPI-driven laptop keyboard buttons (volume control, music player controls,...) stopped working. I'm using the acpi-support package (although not running a Debian derivate) driven by acpid.
Today I decided I wanted my buttons back, so I started to find out what was going wrong.

The issue: acpi_fakekey checks all /dev/input/eventX devices whether or not it's a keyboard device, and if it finds one, it writes the necessary scancode to this device. Since some recent kernel, /dev/input/event0 is no longer my AT keyboard, but one of these ACPI buttons, so writing scancodes to the device won't work: my X server keyboard driver won't see them.

/proc/bus/input/devices told me I need event4 (or use this command: hal-get-property --udi `hal-find-by-capability --capability input | grep KBD` --key input.device | sed "s:/dev/input/event::g"
). Patching acpi_fakekey.c is pretty trivial:

--- acpi-support-0.94/acpi_fakekey.c.orig       2007-04-28 18:09:37.078953488 +0200
+++ acpi-support-0.94/acpi_fakekey.c    2007-04-28 18:09:49.578470914 +0200
@@ -13,7 +13,7 @@
         char filename[32];
         char key_bitmask[(KEY_MAX + 7) / 8];
-        for (i=0; i<32; i++) {
+        for (i=4; i<32; i++) {
                 snprintf(filename,sizeof(filename), "/dev/input/event%d", i);
                 fd = open(filename, O_RDWR);

Replace the 4 with the correct number on your system.

Now my buttons "work" again. Patching acpi_fakekey so it uses HAL to figure out the correct device to write to might be somewhat more reasonable though :-)

Apr 15
About the lack of Java-style interfaces in Python

Just had some discussion about OO concepts, abstract classes and interfaces in Java and Python in #gnome-nl. I still dislike the fact Python and other interpreted languages got no enforced interface implementation support.

A little comparison (not meant to be disrespectful againt anyone):
When you're living in a Java world, you can go out on friday night, meet some person implementing the Girl interface, invite her at your place and have some fun (you know ;-)).

When you're Python, you might go out on friday night, meet some person who tells you "it" implements the Girl interface and at a first sight does so, as get_voice_timbre returns "girl" and has_boobs returns true. Then you take the person home, to your bedroom, and find out, well, it's a shemale.

Got the picture? :-)

Anyway... SoC news will follow later on!

Apr 3
Quote of the day

A quote from the weblog of Bruno Segers, former topman at Microsoft Belgium:

Eerst en vooral laten we nu reacties toe. De vrees dat de bijna religieuze anti-Microsoft lobby mijn blog als hun ‘Uitlaat’ rubriek zou gebruiken is immers niet meer aanwezig. We blijven met Windows Live Spaces werken maar vanaf nu is commentaar mogelijk. Bruno goes open source !

In english:

First and foremost, we allow comments now. The fear an almost religious anti-Microsoft lobby will use my blog to show their dissatisfaction *(somewhat bad translation, I know)* is gone. We continue using Windows Live Spaces but from now on writing reactions is possible. Bruno goes open source !

So enabling comments in a blog is "going open source". Hmm... I'd figure people who used to be at top positions inside Microsoft would at least *know* what Free/Open Source is all about. Looks like I've been somewhat naive.

Via Kris.

Apr 2
Summer of code

Application deadline for Google's Summer of Code 2007 is already some time behind us. Might be interesting to provide a list of proposals I submitted, maybe some other people might pick up a project ;-)

I submitted 3 of them:
- GNOME: HID handling
Basicly, integration of XInputHotplug in the desktop, including per-device settings, and better Bluetooth mouse/keyboard handling (if possible without any command line magic etc.). Enhancing multimedia key support (especially ACPI-based) was a subproject too.
- Django: Row-level permissions
Title says it all. A pretty important project for the Django community.
- Gaim: Porting the Bonjour protocol module to Avahi, and enhance it's functionality
Bonjour-based IM (iChat) is pretty cool and should be (ab)used more. libhowl isn't so nice though as we got the Avahi guys providing us a completely free, glib-integrated mdns/dns-sd stack.

That's about it... I do hope at least one of them gets selected :-) All projects do deserve some love though, that's for sure.

Anyway, while waiting, I'm going to implement some little gimmick panel applet, more about that one later... Still doubting whether to take the Mono/C# or Python road.

Mar 29
Ubuntu joke

Actually I think it's a pretty funny one, not intending to be disrespectful against anyone.

Wonder what this is all about? Read more.
Maybe compare it with this mailing.

Mar 26
Multi-screen setup

I got the multi-display setup I blogged about working after all.
Some issues though:

  • Desktop items are on the secondary monitor while they *should* (imho) be on the primary one. Top panel is on the primary, nice
  • AWN is displayed in the middle of the secondary monitor, not at the bottom, so it's in front of all fullscreen windows etc. See ticket #182
  • The virtual display size is (2*1280)x1024, whilst the primary monitor is only 768px high. Result: things like libnotify notifications in the right bottom corner of the desktop (eg generated by gaim-libnotify) are invisible. New windows are partially in this invisible zone too. Looks like the X stack doesn't handle non-rectangular virtual displays

Beryl runs fine, but I kinda dislike the fact my cube is split over both monitor. Here's what'd really rock, IMHO: instead of having only 4 workspaces, allow me to have 8 workspaces. These are split, 1-4 go on one cube on my primary monitor, 5-8 are on another cube on the secondary display, so I got *2* cubes. It should still be possible to drag windows though: when workspace 2 and 7 are displayed, I should be able to drag a window from one to the other. There might be "overlap" issues here though, ie when the window is not completely on 2, nor completely on 7.
This might fix the different height issue too: workspaces 1-4 are 1280x768, workspaces 5-8 1280x1024. I don't know whether the necessary information can be queried (I guess RandR1.2 will allow this, but my bet is FGLRX won't have RandR1.2 support for over a year).

Last but not least I was thinking it could be pretty cool if composited window managers could handle output cloning. If you got 2 monitors attached to your computer, the WM/CM would see these as one large virtual monitor. It should be able to know about the different monitors though, the boundaries inside the virtual monitor,... If something is displayed then in the part of the virtual monitor (where windows are displayed) this should be copied to the other virtual part, so it's displayed on the secondary monitor too (sounds vague, hard to explain). While doing this, some resolution-bound enhancements could be done on the image to display too (you don't want to run a 4:3 17" TFT at 1280x768, everything looks *strange*), so all monitors can run at their native resolution. This is fairly easy to do using some matrix transformations on the input image, I guess OpenGL also allows this (windows are pixmaps on OpenGL vertices anyway IIRC).

Don't shoot me if some of these ideas are insane or technicly not feasible, this is just a braindump, I'm no X guru.

Anyway, up to writing my Gnome SoC proposal.

*edit* Beryl seems to have a setting to have 2 cubes indeed, but they just rotate their part of one workspace (enable the "3D world display" of windows, you'll see the borders), it's not 2 different workspaces, so when you rotate one cube, the other one rotates too.

Ikke • DesktopPermalink 6 comments
Mar 24
Beryl and Compiz might merge again

Some pretty good news. Let's hope this will allow some more giant leaps on the FOSS Desktop "Bling" (including "useful" bling ;-)) front.

Going to write my SoC application(s) today, also fairly desktop-centered using not-yet-exploited features of our desktop infrastructure. Interesting times! I'll post more information later, mentors welcome ;-)

Mar 23
Dear web, please fix my screens

Old situation = laptop with 1280x768 display + Ati X1600 + fglrx + XGL + Beryl working fine.
New situation = old situation + 1280x1024 TFT connected to laptop VGA out
Desired situation = new situation + working Xinerama-like multihead setup (ie being able to move windows across both monitors, etc) including XGL/Beryl

What I got: after playing with fglrx settings, pairmode line etc, a normal Xorg server with TWM works, windows can be dragged across monitors,...

Whenever I restart GDM (and XGL) though, I can log in, then my standard Beryl-driven GNOME desktop is displayed on my laptop screen, and a second desktop (with its own panel etc) on the external screen. I'm unable though to move my mouse pointer to this screen, can not drag windows,... Basicly, the monitor and the desktop on it can't be used.

This is what I got in my XGL session:
$ fglrxinfo -display :1.0
Xlib: extension "XFree86-DRI" missing on display ":1.0".
Xlib: extension "XFree86-DRI" missing on display ":1.0".
display: :1.0 screen: 0
OpenGL vendor string: ATI Technologies Inc.
OpenGL renderer string: ATI Mobility Radeon X1600
OpenGL version string: 1.2 (2.0.6334 (8.34.8))

display: :1.0 screen: 1
OpenGL vendor string: ATI Technologies Inc.
OpenGL renderer string: ATI Mobility Radeon X1600
OpenGL version string: 1.2 (2.0.6334 (8.34.8))

$ xrandr
SZ: Pixels Physical Refresh
*0 1280 x 768 ( 342mm x 203mm ) *60 75 70 72 56 47
Current rotation - normal
Current reflection - none
Rotations possible - normal
Reflections possible - none

$ xdpyinfo | grep dimensions
dimensions: 1280x768 pixels (342x203 millimeters)
dimensions: 1280x1024 pixels (342x271 millimeters)

$ less /etc/X11/xorg.conf
Section "Device"
Identifier "ATI Graphics Adapter1"
Driver "fglrx"
VendorName "ATI Technologies Inc"
BoardName "ATI Radeon Mobility X1600"
Option "OpenGLOverlay" "on"
BusID "PCI:1:0:0"
Option "MonitorLayout" "LVDS, AUTO"
Option "Mode2" "1280x1024"
#Option "ForceMonitors" "LVDS, AUTO"
Option "DesktopSetup" "horizontal,reverse"
#Option "EnablePrivateBackZ" "yes"
Option "PairMode" "1280x768+1280x1024"

It seems like the creation of Xwindows (when opening a menu, or a new application, etc) is very slow too :-( This might be just an impression though.

*update* Enabling Xinerama not by adding it in xorg.conf (doesn't work, enabling Xinerama disables DRI, so Xgl won't work), but by adding "+xinerama" to the Xgl start line in my custom gdm config file, seems to work... somewhat. I get my normal desktop on my laptop monitor, but only the standard grey-like X checkerboard on the external one. I can move my mouse pointer on it though, but get the default X cursor, not my normal one. I can't drag windows to it either, they seem not to get rendered. Maybe I got to recompile some packages to get Xinerama support...
Window creation isn't "slow" anymore too :-)
Strange though:
$ xdpyinfo | grep dimensions
dimensions: 1280x768 pixels (313x181 millimeters)

*update 2* Playing around some more with aticonfig doesn't solve the issue. It's pretty strange: whenever I'm in GDM, all looks fine. Once my GNOME session starts though, the system starts to clone the 1280x768 laptop monitor to the external monitor, which doesn't look very nice (wrong resolution), instead of providing me with a bigger screen, as when GDM is running. Pretty strange!
This is what xrandr says:
$ xrandr
SZ: Pixels Physical Refresh
0 2560 x 1024 ( 684mm x 271mm ) 60
1 1280 x 1024 ( 684mm x 271mm ) 75 70 60
*2 1280 x 768 ( 684mm x 271mm ) *60
3 1024 x 768 ( 684mm x 271mm ) 75 72 70 60
(omitted last lines) Choosing another mode doesn't solve the issue though :(

Mar 22
Who's abusing my SATA controller?

Just read this interesting post. Had to change the read command somewhat to match my dmesg format (timestamps, you know).

Anyway, here's the result:
$ su -
# /etc/init.d/syslog-ng stop
# echo 1 > /proc/sys/vm/block_dump
# echo "Wait some time here, just use your desktop as usual"
# dmesg | gawk '/(READ|WRITE|dirtied)/ {activity[$3]++} END {for (x in activity) print activity[x],x}'| sort -nr | head -n 10 | gawk '{print $2 " " $1}'
pdflush(215): 160
evolution(7736): 149
pdflush(7670): 126
firefox-bin(7748): 26
gaim(7146): 12
jfsCommit(221): 5
gconfd-2(7114): 5
mono(7200): 4
mono(7199): 4
jfsIO(220): 4
# echo 0 > /proc/sys/vm/block_dump
# /etc/init.d/syslog-ng start
# exit

Feb 21
Recovering a crashed LVM2 PV harddrive

2 weeks ago, due to a power failure, a harddrive in a (UPS protected) server at VTK crashed. Unable to boot the machine, unrecoverable IDE errors,...
The machine was only used as a database server for now (both MySQL and PostgreSQL), and did not make external backups (yet). Yeah I know, stupid, but managing our network isn't that easy.

Anyway, the harddrive consisted of 3 partitions:

  • /boot, ext3
  • /, ext3
  • an LVM2 PV

Both /boot and / were not of any use (except maybe some files in /etc), but the database files inside the LVM2 VG were pretty important, so they had to be recovered.

Do note all 3 partitions were the first part of a RAID1 volume, a second disk still had to be added.

Here's the recovery procedure, could be useful for some people out there:

  • Get the harddrive out of the machine (other parts of it might be broken too, we want to use other hardware)
  • Put the disk in a second machine, including another harddrive, big enough to contain images of all recovered partitions. This means this hard drive might need to be bigger than the original one!
  • Run Linux on the machine. I had no Linux box around, so I used Knoppix (as I knew it had all tools I need)
  • Make sure you got dd_rescue on the box (Knoppix got it), and dd_rhelp. In Knoppix, just download the tarball, extract it, run ./configure && make && sudo make install
  • Become root: sudo su -
  • Mount the new harddrive, first creating partitions/filesystems as necessary. I mounted it on /mnt/sda1
  • cd /mnt/sda1
  • dd_rhelp /dev/hda4 hda4-lvm-pv.img
    (where hda4 is the PV's partition)
  • This can take an enormous amount of time, get some coffee, sleep, a life, whatever
  • When the process is done, poweroff the machine (in a clean way). At this point, the broken harddrive was even more broken: fdisk -l /dev/hda didnt even show hda4 any longer.
  • Take the broken harddrive out of the machine, and make a backup of the image you created, on another harddrive, a network share,... I used another harddrive.
  • Remove the hard drive on which you made the backup copy from the system (just in case).
  • Now real recovery can start. Boot the machine, mount the partition on which you made the image.
  • From this point, all depends on how broken the disk was. As only some minor part of the 120GB PV contained important data, I was able to recover everything necessary.
  • Export the image as if it's a block device:
    losetup /dev/loop0 /mnt/sda1/hda4-lvm-pv.img
    Now /dev/loop0 is just like the old /dev/hda4
  • As the image is taken from a RAID-volume part in this case, I had to remove the RAID signature to let the LVM2 tools recognize it as an LVM2 PV:
    mdadm --zero-superblock /dev/loop0
  • Let the system search for LVM2 PVs:
    This should show you it found some PV
  • Activate the volume groups:
    vgchange -a y
  • Now the old LV's should be back. If your VG used to be called "vg":
    ls /dev/vg
  • fsck the necessary partitions:
    fsck /dev/vg/var-lib-mysql
    If this passes nicely, you're almost saved
  • mkdir /mnt/mysql
    mount /dev/vg/var-lib-mysql /mnt/mysql
  • Now you can use the files in /mnt/mysql to regenerate all necessary services. As I needed the databases to be up and running ASAP, I did a quick Debian install, using MySQL 4.1 (which was also the version running on the crashed server), and moved the recovered mysql database files to the correct locations. Some "check table", "myisamchk", "myisamchk -r" and "repair table"s later, the databases were up and running nicely

That's about it... Obviously, everything should be adapted to your specific setup/situation. The MySQL recovery might not work at all when the MySQL versions and binary formats defer, or the files are damaged too much. See the application-specific documentation for recovery techniques.

The new harddrive we bought to put images on, crashed itself too after 5 hours of operation. Luckily it could be replaced ;-)

For the record: the first broken harddrive was a Maxtor, 120GB PATA (not bought by me), the second one a Seagate 320GB PATA (bought by me, although I wanted to get a WesternDigital, but there were no more in the shop, and I needed a drive quickly). This Seagate was then replace by a WD 320GB SATA2 (which forced me to buy another PCI SATA controller), which works fine. Now don't start a brand-war.

/me is pretty happy all data is back, after all... Now up to reinstalling some webservices that were running on the crashed server.

Feb 17
Python, Cairo, XShape and clocks

Tonight I wrote some little Python application to play around with Cairo (PyCairo that is), and XShape. The result? Something similar to MacSlow's Cairo-Clock, although much more basic.

Application image

You can find the result in my code section.

Just start it in some terminal. Clicking on the clock allows you to move it, clicking it while pressing a shift keys starts resizing mode. When running on top of a terminal/browser/whatever with scrollbars, try to move your pointer close to the clock's circle, inside the area that's normally covered by the clock's window/frame, then use your scrollwheel. As you should notice, the scroll events are not sent to the clock window, but to the underlying window: it's really a circle, not a transparant rectangular window which still catches all events anyway.

Have fun with it!

Edit: there's a little screencast online. Warning: colors look bad, this is caused by the recording software.

Jan 30
Linux kernel drivers

Nice move by the kernel developers.
Now hardware companies got almost no reason at all not to provide Linux drivers for their devices. Especially since "Linux Compatible" starts to become more important everyday.

Jan 16
Dutch webdesign rules

The Dutch government created a law some time ago enforcing all government sites to be W3C valid, accessible,... There's a list of 125 guidelines to which a site should comply.
Some highlights:

  • valid HTML 4.01 or XHTML 1.0
  • CSS and semantic HTML and separation of structure and presentation
  • the W3C DOM (instead of the old Microsoft document.all)
  • meaningful values of class and id
  • meaningful alt attributes on all images
  • information offered in a closed format (think Word) should also be offered in an open format

Imagine a world where all websites would be compliant to these rules... Maybe the need of meaningful values for classes and id's and some more rules aren't that important, but every new page on the web should at least valid be XHTML1.0 Transitional... When writing new pages I try to comply to most of the rules (although I didn't know about them yet), I'll take a look at the whole list, some of them might be useful too.

Now if all browsers would render XHTML/CSS code that validates properly...

More information here.

Jan 6
Web2.0 comic

I want my kids to become that smart ;-)


Who's Online?

  • Guest Users: 466


XML Feeds

What is RSS?