My blog has been moved to ariya.ofilabs.com.

Wednesday, December 26, 2007

aubergine meets fusilli

rainbow_trouts

I love aubergine (or eggplant, for the Americans). I love pasta. Imagine how exciting I was when I stumbled upon Pasta alla Norma recipe from Jamie's Italy (which is also a great book, BTW). It is simply a crime not to try this fabulous Sicilian dish. For my experiment, I substituted spaghetti with fusilli (I hope it isn't an offense to do that) and added few more fresh vegetables. I could also just do with extra chilli for a good decoration and additional wonderful taste.

Sunday, December 09, 2007

chicken tandoori masala

Walking around in Weihnachtsmarkt, we noticed someone selling spices. It looks convincing, actually they sell products from Dudel. Among others, there was Tandoori masala so we bought it and gave it a try. It is more expensive that a spice bag found in typical Asian shop, but according to Dudel's website, their spices are 100% natural and without any additives or flavorings.

This tandoori masala, according to the descriptions, comprises of coriander, cumin, ginger, garlic, chili, and salt. Sounds good. The poor man's way to prepare it is by marinate the chicken with the spices and leave it overnight. Adding extra fresh garlic and ginger in pieces will do no harm. After then, cook everyhing with a pressure cooker. Halfway, let it cool and add yoghurt. You can add coconut milk, but personally I think yoghurt gives better look. Add some vegetables and enjoy!

P.S: sorry for the quality of the picture, my Nikon camera gets older and its picture gets worse.

Breach

Breach is a film adapated from the story of O'Neill vs Hanssen. O'Neill is an FBI agent wannabe, given an assignment to watch every single step of Hanssen, an FBI senior agent. FBI believes Hanssen is a double-agent, working for the Soviet but there is no proof. They want to catch Hanssen red-handed, hence the need for constant surveillance. But the fact that Hanssen does so many useful things and goes to church every day casts a doubt to O'Neill. Can he accomplish that task?

Breach is a type of thriller that is quite rare nowadays. Granted, there is almost no puzzle to solve, the plot is pretty much predictable and likely not as cat-and-mouse as one would expect; but it is not polluted with unnecessary explosion-type actions. Sure, it would definitely bore Bourne's fans, but Breach just has different targets. Chris Cooper's performance (as Hannsen) is pretty convincing, he says more with his face and gestures than just his lines. He's supposed to be traitor, yet we can have a feel of his intimate plays running in his mind. Not that it matters, but I wouldn't hesitate to nominate him for an Oscar.

In short: Breach is too good to skip.

Wednesday, December 05, 2007

attack of the clones (or PictureFlow-ing a phone, a set-top box, and an iPod)

Cover Flow effect for Greenphone

Trolltech Greenphone is a smartphone for Qtopia-based mobile-platform development. Although not available anymore, developing Greenphone is useful to learn Qtopia, and vice versa. You can still learn Qtopia/Greenphone without the real device using the Greenphone SDK within VMWare trick, which what I used to test my PictureFlow code some time ago.

But of course running a program inside an emulator is different than in a real 3-d device. Seeing is believing. Jonas Hurrelmann was very nice to check PictureFlow on Greenphone, as evidenced from his YouTube video. As expected, the performance is quite satisfactory. Kudos to Jonas!

Cover Flow effect for Dreambox

Dreambox is a satellite set-top box running Linux. Because it runs Linux and can be modified, it is popular among hackers. In case you miss it, few weeks ago Brad Hughes compiled and built Qt for his Dreambox DM 7000. Check his demo video...

...and wait 41 seconds and see what is shown. Does that look familiar to you? (Hint: read this blog post again from top)

Cover Flow effect for iPod

Huh? Doesn't "Cover Flow for iPod" sounds too Zen-like? Didn't His Steveness show it before?

Well, this one is different. Jonas Hurrelmann (yes, the same Jonas, kudos to him again) ported the PictureFlow code to Rockbox and then ran it on the iPod 5.5G. The obligatory video is his YouTube clip:

Careful readers might notice that it should be a Rockbox plugin (for those who live under the rock, Rockbox is the ultimate firmware replacement for many music players and it is completely open-source). Since Rockbox can support not only Apple iPod, but also Archos Jukebox, Sandisk Sansa, Cowon and many other popular MP3 players, this opens the possibility that those devices might enjoy CoverFlow-effect as well. Let's wait for Jonas (and perhaps others) for further development.

More attacks are still needed....

Update: check also PictureFlow attacking other mobile devices.

looking for simple but fast 32-bit microcontroller

Dear Lazyweb,

It's been a while since I have been doing microcontroller-related projects. Now it's time to get my feet wet again. For an exciting new project, I'm a looking for an evaluation/development kit for an affordable but high-performance (best-bang-for-the-buck) microcontroller. Preferred is 32-bit, but 16-bit is manageable. Important here is the availability of the I/O ports, I don't care much for USB or Ethernet or even wireless support. Power is also not important. Built-in ADC will be a bonus, but not necessary. The program will be lightweight enough so no need for megabytes of memory.

Surprisingly, I have difficulties finding such a board/microcontroller. Seems that 32-bit microcontrollers todays are geared more toward multimedia solution (image+audio processing), portable networked device, or automotive/industrial applications with different (and confusing) bus types. All I want to do is relatively simple but fast processing of some data. Unfortunately, I can't stick with 8-bit system anymore because of the nature of the application. So what I am searching is rather a bare-bone, blazing-fast microcontroller with tons of digital I/O. The good old 8051 on steroids.

The closest I could find so far is Microchip PIC32 (though I wish it had more input output pins) with its $50 Starter Kit. However, I'm sure there are loads of similar stuff. Where are they?

PS: I'm quite proficient with FPGA so I guess the fallback solution will be a soft-processor in an FPGA, but I would like to stay with the plain microcontroller if I have the choice.

Tuesday, December 04, 2007

q.o.t.d

Open source is a radical idea itself. I think you either get open source or you don't.

-- Donald Rosenberg, on The secret to Red Hat's success

Monday, November 26, 2007

Fun with rotations

The following puzzle might be trivial if you study physics and deal with lots of optics. Or, if you are simply good enough with math, especially with geometry.

First, visualize a 3-d Euclidean space where x-y plane is the "floor" and z points "upward". You are somewhere in this space.

Now assume you have two rotation operators denoted as Q and H. The idea is: both have fixed rotation angle but freely chosen rotation axis.

The common thing of both operators is that the rotation axis can be anything but it must lie on the x-y plane (i.e. the floor), so you can have [1 0 0]T or [0 1 0]T as the rotation vector but not [0 0 1]T. This way, the rotation vector can also be specified by its angle with the x axis. If we denote the angles as a and b for the rotation vectors of Q and H, we write the rotation operators as Q(a) and H(b). Hint: the rotation vector of Q(a) is thus [cos(a) sin(a) 0]T.

Next comes the difference. The rotation angle for Q is 90 degrees, while the rotation angle for H is 180 degrees.

Here is the quiz. Supposed you have a point at [0 0 1]T. This point is first rotated by Q(a). The result is then rotated again by H(b). The questions are:

1. What will be the locus of the final result?
(Hint: find the result as function of a and b).

2. Can you replace the whole transformation (for the point at [0 0 1]T only) by just one Q operator? If yes, determine the rotation vector of this Q.
(Hint: compare the answer to first question with the transformation result by only one Q).

Spoiler Warning: if you have passion for puzzles, go away and solve this one by yourself first. Then come back again here and compare it with the following analysis.

Remark

Although at a glance it looks complicated, the questions are quite easy to solve. It is a matter of doing rotation (couldn't be simpler!). The standard 3x3 transformation matrix will do the job, but usually you can do it much faster if you are familiar with quaternion. For convenience, here are the quaternions for Q and H:

Q(a) = 1 + i*cos(a) + j*sin(a)
H(b) = i*cos(b) + j*sin(b)

(Exercise: normalize the above quarternions)

Then, use the quarternions to find the rotation result with the usual quaternion algebra.

Answer to question #1

After rotated by Q(a), the point [0 0 1]T will become [sin(a) -cos(a) 0]. Transform it with H(b) and you will get [-sin(2*b-a) cos(2*b-a) 0]T.

Note: what you get is actually [x y 0]T with:

x = cos(b)*sin(a-b) - sin(b)*cos(a-b)
y = cos(b)*cos(a-b) + sin(b)*sin(a-b)

which could be simplified using some trigonometric relations.

For the trained eyes, [-sin(2*b-a) cos(2*b-a) 0]T is the equation for a circle because sin(2*b-a)^2+cos(2*b-a)^2 = 1. The z coordinate is 0, means the circle is on the floor.

So, the answer to the first question: the locus will be a unit circle on the x-y plane.

Answer to question #2

After rotated by Q(p), the point [0 0 1]T will become [sin(p) -cos(p) 0]T. This is also a unit circle. It means, direct transformation of [0 0 1]T by Q(p) will also give a circle. That's the answer: yes, rotation by Q(a) followed by H(b), for the point at [0 0 1]T, can be replaced by one Q operator.

But how to find p in Q(p)? Recall [-sin(2*b-a) cos(2*b-a) 0]T from the answer to the first question. Comparing it with [sin(p) -cos(p) 0]T yields p = pi - a + 2*b.

Or, you can specify the rotation vector of Q(p) directly as [-cos(2*b-a) -sin(2*b-a) 0]T.

Not too difficult, isn't it?

three is the magic number

The best thing about cooking is: there is no right or wrong. It means, you will not make any mistake.

After some experiments, I found that adding some extra stuff when preparing mie goreng (a.k.a fried noodles) gives it a distinctive and unique taste. It's not like the common fried noodles anymore. Here I share the secret: basil leaves cut into pieces, few slices of ginger, and a bit of curry powder. Like a charm.

Aller guten Dinge sind drei.

Thursday, November 22, 2007

iPhone in Germany

In Germany, iPhone is sold with a price tag of 399 euros. But then you must sign a 24 months exclusive contract with T-Mobile, with a minimum plan of 49 euros monthly fee. This means (ignoring depreciation) at least you'll lose 1575 euros in total. With one time activation fee, that makes it 1600 euros. On top of that, if you want to actually make a call, be ready to face the 39 cents/minute rate, which is (insanely) expensive compared to other offers. The fact that it is T-Mobile is also interesting, I don't know whether it means a bless or a disaster.

Due to a move from Vodafone, T-Mobile is also forced to sell an unlocked iPhone. So you can pick your favorite provider but only if you're ready to shell out 999 euros for that. Might be better, but 999 euros? You can get 21 Motorola w205 with that amount of money :-) Or do/buy other sensible stuff.

Usually I am not that skeptical. But this does not sound like a success recipe at all.

Monday, November 19, 2007

SpeedCrunch: "Nona" edition

SpeedCrunch version 0.9 has just been released. The improvements are not really user visible, but check the ChangeLog and fixed bugs, nevertheless. Also, this release is available in 17 languages (and contributions are welcomed).

Source tarball and Windows installer are ready for consumption. Go to http://code.google.com/p/speedcrunch/ and get it while it's hot. Binary packages for major Linux distributions usually follow soon.

And now that the first ever release of KDE 4 is on the horizon, it's time to think to start enabling KDE integration in SpeedCrunch.

Note: Nona is nine ninth in Portuguese.

Sunday, November 18, 2007

extraordinary

The only extraordinary thing about me is that I am just an ordinary man.

(on thinking about myself)

Friday, November 09, 2007

Random number 1..5 to 1..7

The task is to solve this puzzle:

Given a function which produces a random day Kliwon, Legi, Paing, Pon, Wage, write a function which produces a random day Sunday to Saturday

OK, I modified the question a bit. Read about Anno Javanico if the names of the day sound strange to you. Originally, it says:

Given a function which produces a random integer in the range of 1 to 5, write a function which produces a random integer in the range of 1 to 7

This is well-known as one of the so called Microsoft/Google interview questions. There are million ways to solve it. Here is my take. Bear in my mind that my math skill is mediocre and I never studied computer science, so don't be surprised if the next few paragraphs look bogus and stupid.

Spoiler warning: If you have passion for puzzles, go away and solve it and then come back again later. Don't let this blog entry spoils the fun for you.

First, let's assume the random number 1..5 is generated by the following (the randomness, or lack thereof, of stdlib's rand() doesn't play any significant role here):

#include <stdlib.h>
int rand5()
{
 return 1 + rand() % 5;
}

Now we must write rand7() which gives an integer between 1 and 7 and which is allowed to call only the above rand5().

The trivial solution, which you should have in mind in a fraction of seconds, is:

int rand7()
{
  return rand5();
}

because nowhere it says that the original nor the new function must give a random number following a specific distribution, e.g. uniform distribution. Of course this can or can't be the real answer, depends on how you look at it.

The next logical step is assuming that the return value of rand7() must have a uniform distribution. The probability to get one of the number in the range of 1..7 is therefore approximately 0.143.

So what comes to mind is to reduce 1/5 probability from rand5() to 1/35, then increase it again to 5/35, which equals to 1/7. The former can be done by calling rand5() several times and treating the first result as 1..5, the second as 6..11 and so on until 31..35. The latter is easier, it's just a modulus operator. The code for this idea (which is shorter than the explanation above):

int rand7()
{
 static int c = 0;
 int x = rand5() + c;
 c = (c + 5) % 35;

 return (x % 7)+1;
}

(I know static variables can be evil, but that's another chapter...)

The disadvantage is obvious, the result is not completely random. For example, the first call will not yield 1 or 7 at all. Another variant is then by making c a bit random, though now that requires two calls to rand():

int rand7()
{
 static int c = 0;
 int x = rand5() + c;
 c = (c + 5*rand5()) % 35;

 return (x % 7)+1;
}

Another nice solution is by using rejection sampling, similar to the famous Box-Muller transform. Here we expand the range of 1...5 to 1..25 and reject anything larger than 7. The code is:

int rand7()
{
 int x = 8;
 while( x > 7)
  x = rand5() + 5*rand5() - 5;
 return x;
}

Pity that we throw away 8..25. It can be improved by reducing the rejection range to 22..25, IOW we would take anything in the range 1..21:

int rand7()
{
 int x = 22;
 while( x > 21)
  x = rand5() + 5*rand5() - 5;
 int r = 1 + (x % 7);
 return r;
}

(or, further by going to 1...125 and rejecting 120..125).

Modulus of 7 can be "optimized" by hand, this is because 7 is a Mersenne prime. For the details, see what I wrote before on modulus with Mersenne prime. This looks useless and even obfuscates the code, but it's harmless and you can tease your interviewer :-)

int rand7()
{
 int x = 25;
 while( x > 21)
  x = rand5() + 5*rand5() - 5;

 int r = (x >> 3) + (x & 7);
 r = (r >= 7) ? r - 6 : r + 1;
 return r;
}

Care to share your solutions?

Thursday, November 08, 2007

PictureFlow on another real device (or Cover Flow for HTC Touch)

Update: see also PictureFlow running on different mobile devices.

HTC Touch is a touch-screen smartphone running Windows Mobile 6.0. It is armed with 200 MHz 32bit Texas Instruments OMAP 850 processor and 2.8 inch color transflective 240 x 320 screen. Like other Windows Mobile devices, HTC Touch is interesting because Qt runs also there, using Qt/WinCE.

After Chumby, HTC Touch is another real device that enjoys Apple-like Cover Flow effect, of course by using PictureFlow. Espen recently showed PictureFlow running on his HTC Touch, as can be seen in his YouTube video:

"Awesome", according to him. We trust you, Espen :-)

Now I know that someone must have tried this on the Greenphone. Can anyone give a video or even a picture?

(Picture from HTC Touch product page)

Thursday, November 01, 2007

long weekend

Downtown is like a dead city.

Today is Allerheiligen (All Saint's day) and it's public holiday in some states in Germany (Baden-Württemberg, Bayern, Nordrhein-Westfalen, Rheinland-Pfalz und Saarland).

Of course, like many others, wisely I take vacation on Friday, thereby giving me a very nice and enjoyable long weekend.

Wednesday, October 31, 2007

10 signs that you aren’t cut out to be a developer

As pointed out by Andry, Justin James' 10 signs that you are not cut out to be a developer is an absolutely obligatory reading for anyone.

Here is the checklist, go there for the details:

  • You’d rather be trained than self-teach
  • You like regular working hours
  • You prefer regular raises to job-hopping
  • You do not get along well with others
  • You are easily frustrated
  • You are close-minded to others’ ideas
  • You are not a "details person"
  • You do not take personal pride in your work
  • You prefer to shoot first and ask questions later
  • You do not like the geek type of person

My favorite is the close-mindness. Long time ago, I was told by someone that in order to be a great programmer (substitute this with other type of profession), you must unconditionally accept the fact that there are better ones than you. Only then you can reach the "enlightment".

Which one is your favorite?

Tuesday, October 30, 2007

Motorola w205: some tips

After using Motorola w205 for some time, here I would like to share common tips which might be useful for others new w205 users:

Does it support key lock? Yes, of course. To lock the keypad, press menu button (middle button in the four-way pad) followed by * (star). If the screen becomes suddenly black, then the key locking is successful. To unlock, do the same step.

How to disable iTAP? iTAP is intelligent typing (or rather TAP-ping) technology from Motorola, used for writing text message (SMS). It's claimed to be better than T9 (text-on-nine) which is used everywhere else (Nokia, SE, Siemens, ...), but my personal experience shows that iTAP is inferior to T9.

There is no really menu item for disabling iTAP. The trick here is to switch the input method from iTAP to TAP . So iTAP means intelligent typing and TAP means non-intelligent typing. Yes, it's very confusing and not usable at all.

While you're composing an SMS, just press the menu button so that Input IME Menu shows up. There you can move from iTAP English (or German, French, etc) to TAP English (or German, French, etc). Then press the soft-button for Select. Now, word autoguessing is inactive and you can enjoy normal typing thumbing again.

If you feel like using iTAP again, just change the input method to iTAP English (or German, French, etc).

How to switch between capital and lower-case letters? This is also not obvious. When typing an SMS, suppose now the display always shows capital letters for each button that you tap. When you press 2, A will show up and it is highlighted. Right away press 0 and that A will be transformed to a. If you continue thumbing, only lower-case letters are produced. To switch to capital letters, just do it again (press a button, continue with 0 while the character is highlighted).

Why right away? Because 3 seconds after you press a button, the displayed letter will not be highlighted anymore and thus you can't change the case from lower-case to capital and vice versa.

Why 0 button? If you see carefully, there is a symbol that resembles an up-pointing arrow that button. So, it is supposed to be a shift key like in a typewriter or a keyboard.

(Picture from official Motorola w205 site)

Monday, October 29, 2007

PictureFlow on real device (or CoverFlow on Chumby)

Update: see also PictureFlow running on different mobile devices, from Greenphone to HTC smartphones.

Chumby is a new hardware widget with open systems design. Jesper recently showed how to put Qt on Chumby, along with PictureFlow, as can be seen in his YouTube video:

Chumby is not even yet available on stores, you got it only if you're an insider. And it's like only a week after I placed the code of PictureFlow on the net. And with Jesper's nice work, this cool little Chumby has already CoverFlow-like effect on par with iPod.

It is also a proof that PictureFlow's performance is satisfactory even on portable device. Chumby has only a 300Mhz ARM9 processor, but the effect is quite smooth.

So, who's next?

Thursday, October 25, 2007

Still PictureFlow: improving the rendering quality

Still about PictureFlow, my CoverFlow-effect clone, I did give some thoughts on improving its rendering quality without sacrificing the performance and still doing it in software (no help from graphics card).

The first that came to my mind is by using bilinear filtering in the texture mapper. As you might predict, the texture mapper itself needs only affine transformation, each cover/slide is rendered column-by-column. Since the z distance for all pixels in a column is constant, affine transformation is enough and can be implemented efficiently. Adding bilinear filter, however, means doing linear interpolation for each and every pixel. If it is done in one dimension only, i.e. vertically, that is still manageable. But since (to assure the quality), we need to perform it in both dimension, the whole stuff would become too slow.

Then one morning I realized that I don't really need to do the filtering on-the-fly. Just transform the cover image before it is rendered to screen, we can take advantage of Qt's smooth pixmap scaling for this purpose. Won't be as good as real interpolations, but everything up to now are dirty hacks anyway.

Here is the result so far (clink to enlarge). Compare the filtered version against the original nearest-neighbor approach. Can you spot the improvement?

For starter, you can see that the jaggy lines between the cover images and the black background (obvious when the cover is white) become less noticeable in the filtered version, as shown below. Left is nearest neighbor, right is bilinear filter:

There is no impact at all on performance when doing the animation effect, everything is as smooth as before.

There are however disadvantages with my first approach. First, the cover image is enlarged four times in both dimension, thus making it consuming 16x more memory space. The surface cache becomes very large. Even for book covers (150x200, stored in ARGB32 format), each of them requires 1.8 MB. This is terrible for portable device, although still manageable on modern desktop machine. In addition, creating the surface cache is slower now due to the necessary image scaling.

The next steps would be more optimizations. First, the surface cache will still keep the original dimension (150x200 in the above example). The scaled version will be constructed only whenever necessary, i.e. right before it is texture-mapped. In addition, there is no need to perform filtering while the animation still takes place. The covers move so fast, a bit sacrifice in the quality won't be noticeable to human eyes.

Let's see where this brings me further. Seems that software-rendered CoverFlow effect done in C++ with a quality that can match hardware-assisted version is quite feasible.

Monday, October 22, 2007

PictureFlow, a clone of CoverFlow as a Qt widget

Another no-time-yet-to-finish-it pet project of mine is a media player, something like for media center or portable device. I code it in SDL, in a hope that targeting platforms like GP2x and Nokia N800 are easy. But knowing that Qtopia (soon) runs also on N800, I am thinking of moving the code to pure Qt for ease of maintenance.

Unless you live under the rocks, CoverFlow should sound familiar. For the said media player, I have an efficient implementation of CoverFlow effect, called PictureFlow. Last weekend I decided to port the code to sane C++ and Qt and here is what I get now:

PictureFlow: a clone of CoverFlow effect

or, like the trend nowadays, in the following short screencast (if it is not visible, go to http://youtube.com/watch?v=uwE_UIHSWnY directly):

You can see that the typical "flowing" ala CoverFlow is implemented already. Even, the first and last covers always fades in and fades out during the animation (so a cover just doesn't come in out of nowhere). Reflection is also there, done by crude-blending the cover with black (that's why black background is so sweet!) and then placing it in the surface cache.

The important feature of PictureFlow is that it does not need 3-d accelerated graphics system. Everything is done in a software renderer. This is not so surprising, consider that I target the original media player for portable device(s). Even the latest sub-GHz iPod can have CoverFlow, so there is no reason to demand fast OpenGL implementation just to enjoy this little piece of eye candy. As long as blitting to screen is fast, you're set. Moreover, no floating-point operation is carried out so that it's fast enough even on ARM-like platforms.

On the other, using pure software renderer has a major drawback, namely the rather lower rendering quality (traded for optimal speed). As you witness from the screenshot, the edges of the tilted images are jaggy. However, with 225 dpi screen like in N800, these jaggy lines (hopefully) won't be noticeable. This can't be avoided without causing too much performance penalty. In fact, technically there is not even a perspective-correct texture mapper. It is just the same hack like the texture mapper done in raycasting-based game, e.g. the classic Wolfenstein 3-D ages ago. This is also the reason to bypass Qt own rasterizer, as we can do some sort of "cheating" and map the texture really fast. Texturing is done more like nearest neighbor approach rather than bilinear filtering, which gives less pleasant result if you stare at the rendering result too long.

Also, software renderer is much slower than hardware-assisted one. Thus, the trick is to keep the widget as small as possible, but not smaller. With reasonable size like 800x350 pixels, on fairly modern machines, you'd get something like 45 fps, which is quite satisfactory. I even tested on old 800Mhz box, it is not as smooth as in a dual-core system, but runs nevertheless well enough.

Overall, this widget is still very basic though already functional. For example, there is no text nor fancy scrollbar which are typically superimposed on bottom side. I guess, in this case, you can subclass PictureFlow widget and add the extra gimmicks by yourself. In addition, as trade-off, covers with alpha channel and covers with non-uniform size won't be supported, this is to minimize texture overdraw.

Anyway, this widget is released as open-source (under MIT license), see http://pictureflow.googlecode.com. So, just grab it while it's hot.

Some ideas where it could be useful elsewhere:

  • For album browsing in Amarok. At the moment, Amarok for KDE4 has its own CoverFlow-like feature, but last time I check it requires OpenGL so it works well only when the graphics system is 3-d accelerated.
  • Choosing a slide in a presentation (so maybe it could be integrated into KPresenter?). Imagine you're running your presentation and one of your audience ask you to show some previous slides, wouldn't be cool when you flip through the slides with this flowing effect?
  • Quickly skim through photos, useful in Digikam, Gwenview, or similar imaging tools. Since it's used as a chooser, not full-fledged slide show, the size could be kept small and thus the performance should be acceptable.

Any more ideas?

Sunday, October 21, 2007

Thai Sambal Oelek?

Starting from Monday, for few days Lidl Germany will sell some Thai stuff, mostly food and spices. While reading the flyer and also its website, I stumbled upon this:

I have no doubt that similar type of strong sambal is available elsewhere, and/or maybe the supplier of the said sambal oelek is indeed from Thailand. But at least let's not claim it as Thailändische Würzpaste. It is even so obvious from the van Ophuijsen spelling of "oelek". When speaking about sambal oelek, it is definitely typical Indonesian sambal.

Das ist die Wahrheit.

Wednesday, October 10, 2007

back to basics: Motorola w205

During my adventure to find an ideal mobile phone, I often get arguments like: well, if you don't need a particular feature, just don't use it. The counter-argument is easy: if I don't need a feature, why should it exist after all? Reducing the complexity of software and hardware in a mobile phone could simplify a lot of things, increase the battery life, ease the technical support, and possibly even as far as improve its environment-friendliness factor. However, normally it also means less profit for phone sellers.

Fortunately, for those who are old-fashioned and need simple and basic mobile phone without all the unnecessary gimmicks, nowadays there are already choices from Nokia (1110, 1600, 2610), Sony Ericsson (J110, J120, J220), Samsung (SGH-C300), Motorola (F3, w205, w208), and many others.

Some time ago, I decided to bite the bullet and switch from the lovely black Motorola RAZR V3 to another phone: Motorola w205 (SAR head: 0.83 W/kg, body: 0.48 W/kg). It is considered one of the latest entry-level basic mobile phone as it is available only since Q1 this year. From Amazon.de, it costs only 46 euros including VAT and shipping. There are even cheaper offers, if you are willing to take SIM-locked phone in a prepaid bundle.

The phone is compact and light. It can do SMS but not MMS. I don't really care for MMS, all these 6 years using mobile phone, I have sent like 2 or 3 (useless) MMS. As for typing SMS, instead the common T9, again Motorola's own iTAP is used for intelligent/predictive typing. It is a minus point for me, for I always hate iTAP and disable it all time, but I guess I can live with that.

Its 1 MB memory is enough for 500 address book entries or 750 SMS. With 850 mAh Li-Ion battery, it is claimed to have talk time up to 8 hours and stand-by time up to 12 days. For sure, I reach the charger less often than with RAZR. If this is not enough, more powerful 1700 mAh battery is available for less than 7 euros.

The phone has a decent color display, 128x128 pixels with 65 thousand colors. Actually, I'd prefer to get a sharp black-and-white display with e-ink technology (as in Motofone F3, but the dot-matrix version thereof) as I'm sure the battery life would even be improved. But again, this one is already good enough.

There is no camera in this phone. Also no infrared. No Bluetooth. No WAP. No GPRS. No MP3 player. No radio. No singing-and-dancing stuff. No extra bells-and-whistles.

I am a happy man.

(Picture from official Motorola w205 site)

Sunday, October 07, 2007

OpenSUSE 10.3: first look

I know I should be doing something "useful", but the fresh-from-oven OpenSUSE 10.3 is just too good to skip. Thus, I decided to waste a weekend to try it. In short: it's very solid and attractive, without doubt the best OpenSUSE release so far.

Installation (and upgrade) was easier than ever. Now we need only one CD. I choose KDE of course. For most users, this means getting openSUSE-10.3-GM-KDE-i386.iso through http/ftp/torrent, burning it, and using it to perform the installation.

The first boot after the installation (yes, it's green again!) shows that boot time is needed really improved. My laptop needs 54 seconds until I get a fully functional KDE desktop, it takes at least 70 seconds with OpenSUSE 10.2, 90 seconds with Windows XP.

Green Desktop

Post installation, I had little problem trying to connect to Internet using my DSL modem, even after the usual steps of removing NetworkManager and installing KInternet. It turned out, somehow smpppd is not activated by default. If you experience the same problem, the solution is easy: run YaST, System, System Services (Runlevel) and then enable smpppd. While you're there, try to tweak some services and turn off what you don't need (e.g. for pure desktop, no need for postfix).

And while doing software management, one quickly notices that package management is thousand times better compared to the previous versions. With OpenSUSE 10.1/10.2, doing things with packages is just unbearable without Smart, IMO zmd along with its Mono stuff are not for mere mortals. However, now zmd is gone, zypp is already greatly improved and thus making application installation in OpenSUSE 10.3 significantly faster than ever. Even better, if you are used to subscribe to alternative repositories (e.g. Guru, Packman, KDE:Backports, etc), there is a new Community Repositories module in YaST which allows you to add common non-official repositories with only few mouse clicks. This is extremely simple even for novices.

OpenSUSE 10.3: Click-and-install feature

But the best is yet to come. Now OpenSUSE offers one-click application install. This is a new feature which will be appreciated by typical desktop users. Rather than using YaST to install new software, you just go to http://software.opensuse.org/search, search for the program, and then click on the 1-Click Install button to start the installer, which will download the packages (and handle the dependencies, if necessary) and install them for you. It couldn't be easier, extremely useful for Linux newbies. It also resembles the way most applications are installed in Windows, a plus for those who switched or want to switch.

Of course you can still use the familiar YaST to install and remove programs as usual. At first, maybe you'll be a bit surprised because the icons in YaST have been changed. Looks like these new icons are designed to match Tango icon sets. If you prefer the good old Crystal style, just follow binner's tips: remove package yast2-theme-openSUSE and install yast2-theme-openSUSE-Crystal instead.

As with any fresh Linux box nowadays, you need to perform the extra steps to install non open-sourced stuff so that you can enjoy e.g. your MP3 music. With the new click-and-install, this also couldn't be easier. Just go to http://opensuse-community.org/Restricted_Formats/10.3 and click on codecs-kde.ymp link. The same installation wizard will pop-up, then just follow the step-by-step instructions. In addition to multimedia codecs, you can have the option to install Java (1.5 or 1.6) and Flash plug-in as well. All with few mouse clicks.

The same easy procedures apply also for installation of proprietary NVIDIA or ATI driver. For example, for ATI graphics card, just read the super-simple instructions, again a matter of clicking a link (even a child can do that!). You don't even need to know the model of the graphics card.

Conclusion: with one CD install, faster boot, easier package management, single-click application install, OpenSUSE 10.3 is definitely worth to try. For 10.2 users: upgrade!

just one chance, just one breath

It is definitely interesting to know Oslo, one of the most beautiful and also most expensive city in the world.

My first touchdown wasn't that smooth, however. Just a day before I left, I caught a terrible cold. This was likely because I was too tired after the 5-day conference in Berlin and had only few hours to rest. I travel very seldom, but just when I had these important flights, both were delayed and caused some incoveniences. I still managed to get the very last express train from the Oslo airport to the crowded downtown (this was weekend afterall) and found my hotel. So here I was cold, sick, hungry, with this bad fever, looking around trying to feed myself with some sensible food and hot drink at over midnight in a completely foreign land, at the same still trying to understand the Norwegian Kroner. Fortunately everyone here does understand English. And fortunately there is Deli de Luca everywhere. In the end I was finished with my business at 3 am and fell asleep almost immediately.

Nationaltheater Oslo

I took the time on Sunday to take some needed rest. In the afternoon I met Helder, the current maintainer of SpeedCrunch, and he became my just-in-time guide and showed me some nice spots of Oslo, although the weather wasn't so friendly. We had a nice dinner together. Of course we discussed a bit about SpeedCrunch. Unfortunately Johan did not manage to come here; otherwise we're set for a SpeedCrunch Developer Conference :-)

I spent Monday mostly in Trolltech office. Some faces were already familiar to me and it's good also to finally meet some others chaps I know only in names as well as few other famous Trolls. Simon gave me a tour of all the cool stuff they have. It was definitely very impressive.

My time in Oslo was obviously too short. And due to the weather, I still missed some beautiful sights Helder told me. For sure, I must go back again someday...

Saturday, September 15, 2007

with 8 seconds left in overtime

Within hours, I'll be in a train to Berlin. This is my third trip to Berlin this year, the first was for KOffice weekend, the second was for LinuxTag. Unlike the first two, this time it's not for "personal satisfaction" only because I'll be attending this year's ECOC (European Conference on Optical Communications). My last ECOC was in Glasgow, 2005. So it's nice to have a chance again to look around, rebuild contacts, and find out what other researchers are doing.

Update: I am already in Berlin. The conference started already, there are many exciting topics. We even get free WiFi so I'm not really fully isolated from the net, thanks to my N800.

Sunday, September 09, 2007

The Bourne Ultimatum

Ultimatum is the last of the Bourne trilogy films. Here Jason was back, among others in Europe, on the search for his past. CIA tried to stop him by all means, but due to an internal conflict, some (including Nicky, again) tried to help him. You'll be following his journey and his struggles with a couple of flying bullets, dangerous car chasing, intense hand combats, as well as puzzles solving.

Ultimatum is, without doubt, the best of Bourne ever. Recommended.

Sunday, September 02, 2007

Le Trote

rainbow_trouts

These are rainbow trouts, marinated with some drops of lemon, salt and pepper, vegetable oil, soy sauce, tomato ketchup, spicy sambal, covered in aluminum foil together with slices of vegetables (e.g. carrot and kohlrabi), and baked for 15 minutes at 200 C. Simply delicious.

Wednesday, August 29, 2007

Legacy vs Lateral (3): Solution space isn't always in two dimensions

This one also happens not so seldom.

Supervisor: Hey, can you do Visual Basic?
Developer: (surprised) Ahm, it depends....
S: Look, I finally got the library that we need for our development. It comes with lots of VB examples, so please integrate a VB module with our app.
D: Could you send me that stuff first?
S: Sure.

Few minutes later, the "stuff" has been received by the developer. After carefully examined it for few minutes, our hero found out that it's just a normal dynamic library, it can be loaded by standard mechanism that every experienced programmer (worth his salt) is familiar with. The VB thing is just because examples are given for VB, presumably to show how easy it can be. But it is not necessary to restrict the solution space to VB.

Setting aside VB & friends, what is important is the concern: often, you are already given a (very) limited set of solutions for a given problem. Long long time ago, that may work well. But nowadays, it won't be that easy. Systems become exponentially more complex, our brain is bombarded with lots of useful information as well as useless junks, there are A to Z details that the brain cells won't bother anymore. It becomes very challenging to be able to have an overview, let alone to always play the polymath rule all time. And the devil is always in the details.

Share the problem descriptions, not always the proposed solutions. And thus, triggers creative thinking and discussions.

Super Funny Mario

(Found via ogmaciel.com)

Tuesday, August 21, 2007

Linus on git (again)

(No, this isn't about the Linus' Tech Talk video on git).

The nice thing working on KDE project is because Linus likes KDE. Thus, it is not (so) surprising (he used to help with bugs, e.g. #27340) to see Linus himself writing something (read: sending some "enlightment") to kde-core-devel, again on the topic of git:

Centralized _works_. It's just *inferior*.

I'd like to see a ThinkGeek shirt with that quote.

Sunday, August 19, 2007

Transformers

One word: it rocks!

(Well, that's more than one, but you get the idea...)

Saturday, August 18, 2007

c.o.t.d

Who is going to pay almost $500 for a phone?

Browser: Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1C25 Safari/419.3

(A comment to the $491 Linux-based Motorola RAZR V8, posted from an iPhone).

Thursday, August 16, 2007

Legacy vs Lateral (2): Design for the future, not for today

Did you ever try to assemble and create a great product but lately much more better, powerful and yet cheaper components are suddenly available, and were they available sooner, your life would have been significantly simplified? Setting aside first that nobody can really predict the future, it is important here to emphasize that often - but not always [1] - it makes more sense to design something for tomorrow or next year, rather than just for today.

The classic example for this is game development. Unless you're coding a simple Pong clone, the whole process of game development (think the upcoming id's Rage or Crytek's Crysis - but certainly not Duke Nukem Forever) can take ages. By the time the game is finished, the whole digital world already makes a few leaps here and there. Thus, it is absolutely necessary to predict the trend and ride the curves so that the shipped game will match the available technology and cover the intended market as it may completely change many design decisions during the development phase.

For the sake of giving an example (I'm not saying this is what's going to really happen), say you're 1000% absolutely sure that Physics Processing Unit card ala Ageia would be ubiquitous in platforms you're targeting, just like today's accelerated graphics chip, then it will be less sensible [2] to use physics engine which won't take advantage of the said unit, let alone optimize it to death, because right after you launch the game, it might have hard-time competing with other games which are e.g. specifically designed to exploit the physics processor.

The same goes for any non-trivial things that needs engineering love. We're not in the 70's anymore, a satisfactory achievement needs more than just a weekend, a copy of Popular Electronics, a bunch of vacuum tubes, plus a TV [3].

But the real challenge remains: how can you convince your superior that it's the right thing to do?

Notes:
[1] For example, if your software is supposed to work well even on old systems
[2] There are of course obvious exceptions to this, e.g. you don't need fancy graphics nor physics
[3] Like a project to show the actual time at the corner of the TV screen

Postscript: To avoid misunderstanding, it does not mean that things like software bloatness is endorsed. Quite contrary, because bloatness is typically caused by careless uses of system resources and superfluous features while design for today implies imposing restrictions (which will not exist anymore in the future) unnecessarily. Between these two extremes we must stand.

Tracing the diagonals

This is a real-world problem, but could also serve well as an interview question. The task is to create two sequences of numbers which when plotted against each other (ala Lissajous curve) give the following (the knots are there to emphasize the points):

Here was my quick hack to solve it (written for Qt 4.x). The important part is in the constructor, the rest is only to show the result. I'm sure there are way better and much more elegant solutions. Care to share yours?

#define NSIZE 5 // must be odd

#include <QApplication>
#include <QPainter>
#include <QPainterPath>
#include <QWidget>

class W: public QWidget
{
private:
  int* x;
  int* y;
public:
  W(): QWidget(0)
  {
    x = new int[NSIZE*NSIZE];
    y = new int[NSIZE*NSIZE];
    x[0] = y[0] = 0;
    int xs = 1, ys = 0;
    for(int i = 1; i < NSIZE*NSIZE; i++)
    {
      x[i] = x[i-1] + xs;
      y[i] = y[i-1] + ys;
      xs = (x[i]-x[i-1]+y[i]-y[i-1] == 1) ?
           (xs) ? (y[i] ? 1 : -1) : (x[i] ? -1 : 1) :
           (!x[i] || x[i]==NSIZE-1) ? 0 :
           (y[i]==NSIZE-1) ? 1 : xs;
      ys = (x[i]-x[i-1]+y[i]-y[i-1] == 1) ?
           (ys) ? (x[i] ? 1 : -1) : (y[i] ? -1 : 1) :
           (x[i]==NSIZE-1) ? 1 :
           (!y[i] || y[i]==NSIZE-1) ? 0 : ys;
    }
  }

  ~W()
  {
    delete [] x;
    delete [] y;
  }

  #define DD 0.05
  void paintEvent(QPaintEvent*)
  {
    QPainterPath d;
    d.moveTo(x[0],y[0]);
    for(int i = 0; i < NSIZE*NSIZE; i++)
    {
      d.lineTo(x[i], y[i]);
      d.lineTo(x[i]+DD, y[i]+DD);
      d.lineTo(x[i]+DD, y[i]-DD);
      d.lineTo(x[i]-DD, y[i]-DD);
      d.lineTo(x[i]-DD, y[i]+DD);
      d.lineTo(x[i]+DD, y[i]+DD);
      d.lineTo(x[i], y[i]);
    }

    QPainter p(this);
    p.setRenderHint(QPainter::Antialiasing);
    p.fillRect(rect(), Qt::white);
    p.setPen(QPen(Qt::red, DD));
    p.translate(10, 10);
    p.scale((width()-20)/(NSIZE-1), (height()-20)/(NSIZE-1));
    p.drawPath(d);
  }
};

int main( int argc, char ** argv )
{
  QApplication a( argc, argv );

  W* w = new W;
  w->setWindowTitle("Diagonal Tracing");
  w->show();

  a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) );
  return a.exec();
}

Wednesday, August 15, 2007

Legacy vs Lateral (1): Google is here to help

Did you ever experience the typical scenario like this before?

The phone rings.
Engineer 1: Yes?
Engineer 2: Hi, it's me. Look, I have a problem here with my <insert-your-favorite-CAD-application>. Can you help me?
E1: Fine, I'll come over.

Few minutes later.
E1: So, what kind of problem do you have?
E2: I'm trying to run this-and-that. And out of sudden, what I've got is the following error message: bla...bla..bla..
E1: Hmm, that's strange (thinking for a minute or two).
E2: Yeah, that's not supposed to happen, isn't it?
E1: Did you google already?
E2: Google..what? Ah, I see. No, I didn't try googling for that problem...
E1: Well, let's try it now.

And after 5 minutes of googling and flipping web pages, the problem was easily solved. As a matter of fact, it could have been solved earlier.

Although it looks simple, the above scene happens quite a lot. Those who grow up in the late nineties and take for granted that Internet exists for their conveniences often quickly open google.com whenever they find a problem (even as far as replacing the pocket calculator) and most of the time just mechanically and without too much thinking. Whether it's about using Google or other search engines, searching for some support articles, or even reading discussion archives, the idea is the same: let's tap into the vast amount of knowledge available out there. Given enough brains, likely one of them solved the problem already. However, the previous generations (granted, not all of them of course) sometimes struggle with this concept of "information at your fingertip".

Ever witnessed something similar?

Tuesday, August 07, 2007

Three Envelopes

A fellow had just been hired as the new CEO of a large high tech corporation. The CEO who was stepping down met with him privately and presented him with three numbered envelopes. "Open these if you run up against a problem you don't think you can solve," he said.

Well, things went along pretty smoothly, but six months later, sales took a downturn and he was really catching a lot of heat. About at his wit's end, he remembered the envelopes. He went to his drawer and took out the first envelope. The message read, "Blame your predecessor."

The new CEO called a press conference and tactfully laid the blame at the feet of the previous CEO. Satisfied with his comments, the press -- and Wall Street - responded positively, sales began to pick up and the problem was soon behind him.

About a year later, the company was again experiencing a slight dip in sales, combined with serious product problems. Having learned from his previous experience, the CEO quickly opened the second envelope. The message read, "Reorganize." This he did, and the company quickly rebounded.

After several consecutive profitable quarters, the company once again fell on difficult times. The CEO went to his office, closed the door and opened the third envelope.

The message said, "Prepare three envelopes."

(From www.notboring.com/jokes/work/3.htm)

Monday, July 16, 2007

deaf in the trenches

Soldier 1: Just go and let me die in peace...
Soldier 2: Do you want any gravy, sir?

That brilliant line is enough to show that Catherine Tate and Little Britain are for me still miles away from the Two Ronnies.

Sunday, July 15, 2007

English breakfast (or Two Ronnies: Swedish Made Simple)

Man: L.O.
Waiter: L.O.
Man: R.U.B.C.
Waiter: S.V.R.B.C.
Waitress: L.O.
Waiter: L.O.
Man: L.O.
Man: F.U.N.E.X.
Waiter: S.V.F.X.
Man: F.U.N.E.M.
Waiter: 9.
Man: I.F.C.D.M.
Waiter: V.F.N.10.E.M.
Waitress: A. V.F.M.
Man: R.
Waiter: O.
Waitress: C. D.M.
Waiter: O.S. V.F.M.
Man: O.K. M.N.X.
Waiter: M.N.X.
Man: F.U.N.E.T.
Waiter: 1 T.
Man: 1 T.
Waiter: O.K. M.X.N.T. M.X.N.T.4.1.
Waitress: V.F.N.10.E.X.
Man: U.Z.U.F.X.
Waiter: Y.F.N.U.N.E.X.
Waitress: I.F.E.10.M.
Waiter: S.I.L.L.Y. C.O.W.

Monday, July 02, 2007

11,000 downloads and a new alpha

If the download counter is correct, we have already more than 11,000 downloads for SpeedCrunch 0.7, the latest stable release. And this of course doesn't include installation via package manager (from apt to pirut). Not bad, considered it's just released over 2 months ago.

But it's all about "release early, relase often", right? So now the SpeedCrunch team has just announced the first alpha for version 0.8. There is Win32 installer and the source code is known to build on Debian Etch, Gentoo and SUSE 10.2. Helder, the new maintainer, aims for a final release at the end of this month. So we have a month of bug fixing session.

There are couple of new features in this 0.8. Most of them are features suggested by you.

An important highlight is the support for other radix systems: hexadecimal, octal and binary (thanks to Thomas Lübking of Baghira and Oxygen fame). IIRC this is the most wanted feature. It is evidenced by the new radio button (Hex/Dec/Oct/Bin) on the main window:

Since the documentation is not ready yet (will be for final release of course), I thought it's worth mentioning here that the radio button only changes the formatting of the values shown in the display, not how you type in the expression. If you want to enter an expression containing hex number, you should prefix with 0x. For octal it's 0o and for binary it's 0b. So, you are allowed to do something like: 0xfe + 1, i.e. mixing between hex and decimal. The result will be shown as 255 or 0xff, depends on what you choose in that radix radio button.

Beside that, there are also other new goodies, like tons of new functions, factorial operator, choices for decimal point (auto/comma/dot), engineering notation, case-sensitivity for variable names, and assorted bug fixes. You can also have non-modal, docked/floating lists to display built-in functions, variables, constants, and history.

Remember, this is alpha, so there are rough edges here and there. But if you feel brave, just get it while it's hot!

Monday, June 04, 2007

I must have done it half a dozen times

Coming back from Berlin, I just realized that I got that stream of ideas again, of all things just now when my TODO list is unbelievably long, filled with all those backlog items for Real Life, KOffice, my PhD, and assorted fun projects. Granted, probably filling the TODO is still much better than having an empty one...

My time in Berlin was too short, I managed to have conversations with some, but unfortunately so little time to do everything.

(Picture taken in Berlin Hauptbahnhof)

Friday, June 01, 2007

Berlin (again)

Yeah, it was only two weeks ago but soon I'll be visiting Berlin again. This time is however only to have some fun in LinuxTag 2007, which, for the first time takes place in Berlin's Messe. KDE will be there and there are lots of interesting talks.

Thursday, May 24, 2007

SpeedCrunch's tip of the day

Typically, "tip of the day" feature is not really loved. Often, the dialog for showing the tip blocks the main view of the application. Worse, this dialog is even modal, you have to click it to make it disappear.

For SpeedCrunch upcoming version 0.8, I play around with the idea of showing a short tip as a yellowish widget inside the main window. It will disappear automatically after couple of seconds (even with some smooth translucent and animation effect). I'm still thinking whether the tip should be displayed at start up, or only from a menu item.

SpeedCrunch tip of the day

I hope this kind of tip is non-intrusive and yet allows the users to learn a thing or two about SpeedCrunch features.

So, what do you think?

(Yes, I know there is typo in the screenshot :-)

Monday, May 21, 2007

digest the curves, honor the pixels

Continuing my last year's GSOC, finally I managed to implement support for importing embedded raster images in libwpg. As with other graphics formats such as SVG, PDF, and ODG, WPG allows pixmaps or images to be combined with the vector graphics. It was a bit difficult because raster images are typically compressed using RLE (run-length encoding) and it was not too trivial to decode it. And I still do not code all possible depth/format yet. But finally, here is the mandatory click-to-enlarge screenshot:

WPG in Corel PresentationsWPG shown in Perfectspot

Left is the original WPG which I made in Corel Presentations by placing this beautiful windmill in Bremen together with a windmill picture from the clip art. Right is the WPG file opened and showed in Perfectspot (the all-around WPG viewer and converter).

Note that I'm waiting for Qt 4.3 before making a first stable release of Perfectspot (and also libwpg, provided that all image loading support is good enough). The reason is because it needs ObjectBoundingMode for QGradient which really simplifies the code. That's why, in the above screenshot, the gradient is not yet properly rendered in Perfectspot.

In related story, thanks to our very own Master Fridrich, libwpg-based WPG importer is going into ooo-build. So at least the next version of Novell's OpenOffice.org will be able handle those WPG files.

Sunday, May 20, 2007

Alternating row colors, in group

Alternating row colors is a very common user interface pattern, the most used example is the playlist in Apple iTunes. With different color every other row, the table or a long list looks more pleasant and easier to use.

However, if your list is rather vertical than horizontal, i.e. it is not that wide, but rather quite tall, and only consists of one or two columns, sometimes it helps to color not every row but a group of row. The example is shown here. The leftmost list widget has the same white color for all rows, the middle one uses alternating row colors (which looks rather "busy"), and the last one colors every 3 rows. Which one do you think is better?

Plain color Row Grouped

If your list is an instance of QListWidget, QListView or anything derived from QAbstractItemView, it is very easy to enable the alternating colors, just use alternatingRowColors property.

Alas, for grouped alternating colors for QListWidget, you must do some additional work, e.g. (works well for rather static items):

  int group = 3;
  list->setUpdatesEnabled( false );
  for(int i = 0; i < list->count(); i++)
  {
    QListWidgetItem* item = list->item(i);
    QBrush c = ((int)(i/group))&1 ? palette().base() : palette().alternateBase();
    item->setBackground( c );
  }
  list->setUpdatesEnabled( true );

Multiple column list is often made from QTreeWidget with only top level tree items. In this case, grouped alternating colors can be achieved using e.g. (for two columns, create a loop for more):

    int group = 3;
    tree->setUpdatesEnabled( false );
    for(int i = 0; i < tree->topLevelItemCount(); i++)
    {
      QTreeWidgetItem* item = tree->topLevelItem(i);
      QBrush c = ((int)(i/group))&1 ? palette().base() : palette().alternateBase();
      item->setBackground( 0, c );
      item->setBackground( 1, c );
    }
    tree->setUpdatesEnabled( true );

You can of course save some microseconds if you cycle the background color while iterating the items.

In addition, you may want to put some logic to prevent coloring if the number is item is e.g. less that 2*group. Otherwise, 4-item list will look odd, as only the last item has different background color.

Saturday, May 19, 2007

QEMU 0.9 with acceleration on SUSE 10.2

QEMU version 0.9 is already out for some time, but AFAIK no official package is available for openSUSE Linux 10.2 yet. Here are some steps I did to have QEMU 0.9 with accelerator (kqemu) on SUSE 10.2. The motivation is simple: I'd like to have a faster system for filter development.

QEMU 0.9 comes, among others, in binary package. I found out that this works well, so just download qemu-0.9.0-i386.tar.gz then unpack it to /. You'll see some new stuff in /usr/local/.

Next step is to install and use accelerator. This time I did compile it from source. First, get kqemu-1.3.0pre11.tar.gz, unpack it, then run the usual steps: ./configure follows by make and sudo make install. Don't forget to have kernel sources (install kernel-source package from YaST if necessary) in your system before doing this.

Now do the following:

export device="/dev/kqemu"
sudo rm -f $device
sudo mknod --mode=0666 $device c 250 0

After that, load the accelerator (kqemu) kernel module:

sudo /sbin/modprobe kqemu major=250

Now, run your virtual machine using the extra -kernel-kqemu option, e.g:

qemu -hda vdisk.qcow -kernel-kqemu

If you forget to load the kqemu kernel module, you'll get the following error message:

Could not open '/dev/kqemu' - QEMU acceleration layer not activated

otherwise, nothing shows up and your virtual machine is executed as usual.

To verify that kqemu works, activate the monitor using Ctrl+Alt+2, then type in info kqemu followed by Enter. You should see:

kqemu support: enabled for user and kernel code

(Exit from the monitor using Ctrl+Alt+1)

If, for some reason, you don't want to run the virtual machine with acceleration, use the option -no-kqemu, e.g.:

qemu -hda vdisk.qcow -no-kqemu

Now, info kqemu on the monitor would give:

kqemu support: disabled

I tested QEMU 0.9 with Windows NT 4.0 as the guest operating system. Even without acceleration, I've seen performance improvement compared to previous versions of QEMU. With acceleration (kqemu), it was even faster, although the kqemu documentation says only Windows 2000 and XP are supported. Benchmark done using CPUBench showed that the virtual machine runs roughly equal to a 300 Mhz and 1.3 GHz system without and with kqemu, respectively. Now, that's an improvement!

Happy virtualizing...

Sources:
http://fabrice.bellard.free.fr/qemu/kqemu-doc.html
http://fabrice.bellard.free.fr/qemu/kqemu-doc.html
http://kidsquid.com/cgi-bin/moin.cgi/QemuOnLinux

Thursday, May 17, 2007

Newton and the apple

Physics Teacher: "Isaac Newton was sitting under a tree when an apple fell on his head and he discovered gravity. Isn't that wonderful?"

Student: "Yes sir, if he had been sitting in class looking at books like us, he wouldn't have discovered anything."

from jokes4all.net

Monday, May 14, 2007

On these hands and knees I'm crawlin'

Time flies. KOffice sprint weekend in Berlin was just over. I couldn't believe I was on my bed again this morning. It was lots of fun, plenty of food, interesting talks, endless excitement, and most importantly, I got to see many great fellow KOffice hackers in real-life.

In terms of lines of code, I wasn't that productive. But I did managed to fix the annoying column/row resizing tip in KSpread and cleaned up some stuff so that krazy score is going to the sane level again. I checked our list of bugs and already had plan for few of them. The unit test for some spreadsheet functions would hopefully get some love as well. Also, thanks to our filter framework, I could work on a Karbon filter even before Karbon 2.0 is 100% ready. And I promised jaham that I'll help with the SVG to/from ODG stuff. There was also a buzz to finally start really using my latest work on KoXmlReader for all KOffice ODF loading code so that we won't have problem with memory consumption again when working with big documents.

For more details, summary and pictures, see KOffice ODF Sprint Kickoff on the Dot™. Update: and also KOffice ODF Sprint Report.

Thursday, May 10, 2007

berlin, berlin

So it'll be my n-th trip to Berlin. We're going to have KOffice ODF Weekend, supported by KDE e.V and KDAB. 17 16 heads, lots of hacking, and rainy weather look like a great combination.

Monday, May 07, 2007

point seven

Finally, SpeedCrunch version 0.7 has been released. Compared to the last beta, this final release has some fixes for potential crash (due to Q3TextEdit), which is also reported in Launchpad.

So, get it while it's hot. Packages are already available for Windows, Mac OS X (universal binary), Fedora, OpenSUSE, Gentoo, and Debian. Or just compile it from source if you feel brave. See the download page for details.

For some stuff which will make it into the upcoming 0.8, I'm still preparing an interesting screencast. Stay tuned.

Friday, April 20, 2007

Custom toggle action for QDockWidget

Thanks to QDockWidget::toggleViewAction, if you want to create an action (and placed in in the menu, for example) to switch a dock widget on and off, it is very simple indeed. The text of the action will be the title of the dock. If you have more than dock widgets, this can be combined together in a sub menu "Show Docks", just as illustrated below:

When that menu item (and the corresponding action) is checked/unchecked by the user, magically the dock will show/disappear.

But what if you want to create your own toggle action? For example, you want to customize the text of the action to be a bit more descriptive, say "Show Function List". Or perhaps you just want the total control.

Well, you can create your own actions and get this result:

which can be realized by the following code:

  m_actions->showHistory = new QAction( tr("Show Expression &History"), this );
  m_actions->showFunctions = new QAction( tr("Show &Functions List"), this );
  m_actions->showHistory->setToggleAction( true );
  m_actions->showFunctions->setToggleAction( true );
  connect( m_actions->showHistory, SIGNAL( toggled(bool) ), 
    m_historyDock, SLOT( setVisible(bool) ) );
  connect( m_actions->showFunctions, SIGNAL( toggled(bool) ), 
    m_functionsDock, SLOT( setVisible(bool) ) );

So far so good. Everytime you toggle the menu item, the docks can disappear and reappear.

However, it's not completely foolproof. You can, infact, make the dock disappear by closing it manually, i.e. clicking on the X button on the dock title bar. But by doing that, the "checked" status of the action itself is not properly adjusted (i.e. it is still "checked" while the dock is long gone).

With Qt 4.3, the solution is easy: use visibilityChanged signal of QDockWidget:

  connect( m_historyDock, SIGNAL( visibilityChanged(bool) ), 
    m_actions->showHistory, SLOT( setChecked(bool) ) );
  connect( m_functionsDock, SIGNAL( visibilityChanged(bool) ), 
    m_actions->showFunctions, SLOT( setChecked(bool) ) );

If, for whatever reason, you're stucked with Qt 4.2, then you have to find another remedy since visibilityChanged does not exist there. There are many ways to do this.

A particularly complicated but looks-elegant solution is by hijacking trapping the show and hide event of the docks using eventFilter trick. So, hook the event filters during docks construction:

  m_historyDock->installEventFilter( this );
  m_functionsDock->installEventFilter( this );

and do something like this in the window's event filter:

bool MyWindow::eventFilter( QObject* object, QEvent* event )
{
  if( object == m_historyDock )
    if( event->type() == QEvent::Hide || event->type() == QEvent::Show )
      m_actions->showHistory->setChecked( event->type() == QEvent::Show );

  if( object == m_functionsDock )
    if( event->type() == QEvent::Hide || event->type() == QEvent::Show )
      m_actions->showFunctions->setChecked( event->type() == QEvent::Show );

  return false;
}

Looks good? Not really. Because for all this trouble, you can just do the same in these two lines of code (the simple and yet effective solution):

  connect( m_historyDock->toggleViewAction(), SIGNAL( toggled( bool ) ),
    m_actions->showHistory, SLOT( setChecked( bool ) ) );
  connect( m_functionsDock->toggleViewAction(), SIGNAL( toggled( bool ) ),
    m_actions->showFunctions, SLOT( setChecked( bool ) ) );

Any other solution, perhaps?

Thursday, April 19, 2007

on winning in life

Life is a game, and if you aren't in it to win, what the heck are you still doing here?

-- Linus Torvalds

Wednesday, April 18, 2007

Tab bar with RoundedNorth for tabbed dock widgets

Warning: don't try this in real world's application!

Update: I found a trick to reduce the flicker, just read further on.

One advantage of dock widgets (using QDockWidget) is that the docks can be "stacked", either programatically using tabifyDockWidget or when the user explicitly places one dock on top of another. Example is shown below (for future version of SpeedCrunch, more about this in another blog post). There are two dock widgets: History and Functions, and at the moment they are stacked.

However, apparently the tab bar (QTabBar) which is used to choose the dock is always placed at the bottom. Or, using the Qt's terminology, it has the shape of QTabBar::RoundedSouth. Since there are other possibilities for tab bar's shape, e.g. RoundedNorth, would it be possible to make something like this, where the tab is place at the top?

Unfortunately until Qt 4.2 this is not possible yet (issue 146772), although according to issue 145880, "vertical tab bar layout" will be possible in Qt 4.3.

Just for fun, I found a very hackish way to make RoundedNorth for the tab bar (hence, the screenshot above). The trick is to find the tab bar using run-time introspection feature of Qt and then change the geometry manually. If I know in advance that there will be only one tab bar in my main window and there are only two dock widgets, this can be accomplished with a private slot like this:

void MainWindow::hackTabbedDocks()
{
 QDockWidget* topDock = d->historyDock;
 if( topDock->height() == 0)
   topDock = d->functionsDock;

 QList<QTabBar *> allTabs = findChildren<QTabBar *>();
 for(int ii = 0; ii < allTabs.size(); ++ii)
 {
   QTabBar* tab = allTabs[ii];
   if(tab->parentWidget() == this)
   {
     if(tab->geometry().top() > topDock->geometry().top())
     {
       tab->setShape( QTabBar::RoundedNorth );
       int h = tab->geometry().height();
       tab->move(tab->geometry().left(), topDock->geometry().top());
       topDock->move(topDock->geometry().left(), topDock->geometry().top()+h);
     }
     break;
   }
 }
}

I found out, I always need to call this slot twice so that it can work. To simplify, there two other slots which manage it:

void MainWindow::handleTabChange()
{
  QTimer::singleShot(0, this, SLOT(hack1()));
}

void MainWindow::hack1()
{
  hackTabbedDocks();
  QTimer::singleShot(100, this, SLOT(hackTabbedDocks()));
}

And I need to bind any signals which indicate that the tab bar has been relayouted, e.g. when a new tab is selected , when it is resized, etc, to handleTabChange slot above. For illustration purpose, let's just do the first. Of course, this can be done only when tab bar already exists. So, time for another silly slot:

void MainWindow::initHack()
{
  QList<QTabBar *> allTabs = findChildren<QTabBar *>();
  for(int ii = 0; ii < allTabs.size(); ++ii)
  {
    QTabBar* tab = allTabs[ii];
    if(tab->parentWidget() == this)
    {
      connect(tab, SIGNAL(currentChanged(int)), this, SLOT(handleTabChange()));
      break;
    }
  }
  handleTabChange();
}

which will be called from MainWindow's constructor by abusing QTimer once more:

  tabifyDockWidget( d->historyDock, d->functionsDock );
  QTimer::singleShot(0, this, SLOT(initHack()));

That's it!

The big disadvantage of this trick is obvious: flicker occurs everytime you do something with the docks, e.g. changing the tab. It will be quite annoying, but all of this is just a hack anyway. So was it fun? Yes. Useful? No.

(I guess the real "solution" is only waiting for the Trolls to implement it)

UPDATE. Here is the trick to reduce the flicker so that it becomes acceptable (even almost not noticeable). I need another private slot and some magic with setUpdatesEnabled as follows:

void MainWindow::handleTabChange()
{
  setUpdatesEnabled(false);
  QTimer::singleShot(0, this, SLOT(hack1()));
}

void MainWindow::hack1()
{
  hackTabbedDocks();
  QTimer::singleShot(0, this, SLOT(hack2()));
}

void MainWindow::hack2()
{
  hackTabbedDocks();
  setUpdatesEnabled(true);
}