cat /dev/maxilys

A glance in the mind of a KDE/Linux developer to see how ideas turn into code.

2006-09-26

KDE: Daily build

Just after the last release of Serenity I suddenly wasn't satisfied of the result any more, so --this time-- I'm waiting a little while to find the last glitches.

And I found some. First, I drew new thinner arrows for the tree expanders. The biggest arrows of Serenity were just too thick. And this time, I didn't counted in binary on my fingers.

Well, I never did but I drew grids, numbered the columns (8, 4, 2, 1, 8, 4, 2, 1, etc) and blackened cells to be able to count in hexadecimal. That was a real P.I.T.A! I had to find a piece of paper and never was able to draw a straight grid on a white sheet. I dropped the archaic pen and paper for the mouse and screen approach. I just (re-)discovered Kolourpaint which can save bitmaps in XBM format. Just what I needed. Instead of cutting trees for Serenity's bitmaps, I now cut lines of text. That's lighter to carry. :-D

After that, I just left Serenity live its life on screen... until today. I wanted to see if I could do something for the tiny flickering that happens when the window frame is drawn over the zen borders. (To see it, you actually need to generate a massive number of redraws.) It allowed me to discover a bug that I didn't see because I never maximize my windows. I tried to be too clever and I didn't make enough tests. Any way, I fixed this and introduced a new bug: When the window is maximized and the frame deactivated, the space in between the titlebar and the content disappeared instead of the top space. That made me laugh because it took me a long time to find the bug that was right under my nose. But I decided to turn that bug into a feature that will make the "fullscreeners" happy. ;-) The titlebar now can become as small as possible without any space.

I did nothing for the tiny flickering --Seeing it isn't easy. However I disabled the zen border from the inactive windows. Just a few fractions of seconds spared for the users, even if that's not as much nice.

The only thing I need now is a new gradient style that doesn't make disappear a corner of every button to match the new "Milky Way" colorscheme... and a bunch of new snapshots!

Labels: , ,

2006-09-17

KDE: Total look

That's it. There are no widget left to style. I already said this more than once but this time, I think I did it. I reached the total serene look.

The last remaining widget was the tiny menu button in Kicker's panel. I wanted to change those 80 pixels that hurt my eyes but the first time I look in Kicker's sources, I couldn't figure how to do it. So I forgot about it... until yesterday. I scratched the surface (digging is exaggerated in this case), found the class name of the widget, polished it and intercepted its drawing in the event filter. So easy. Except, that I had no obvious way to retrieve the direction in which I should draw the little arrow. Whatever, I drew a little "+" sign that fits any direction. Nice! ;-)

And before that, I gave something unique to Serenity: Big tree expanders. I changed KDE's default 9x9 size to a gigantic 15x15. From a usability point of view, that make a big difference. And visually too! I had to draw very special bigger "+/-" symbol to fit in this gigantic space.

Any way, that was fun to do because I did something I enjoyed: ripping KDE's sources and improving them --well, at least, adapting them to Serenity. But let's start from the beginning. I first tried to enlarge the tree expanders beyond the provided rectangle. 1 pixel... 3 pixels... And I realized "somebody" was drawing the branches over the expanders. Not good. A little trip around Qt's and KDE's sources told me that the culprit was "kstyles.cpp". I just ripped the intersting part --the drawing of CC_ListView-- and applied my coding style to it. I already knew I'll have to implement it in Serenity and that gave me time to understand what was going on in there.

In a way, KDE's method is not that bad. It walks along the branches of the tree, draw the expanders and collects the branches to draw them at once. --More or less.-- The problem is that the size of the expanders is hardcoded and even if there is plenty of space around, the drawing of the branches after the drawing of the expanders prevents any change. For Serenity, I removed all the system to store the branches in order to draw them directly. I also removed any calculation for the size of the branches around the expanders because any expander will now be drawn over its branch. That was becoming better.

I built it and tested it. Nice! ...until I decided to check the "+/-" symbols. They looked thin but huge. It was the time to restart counting in binary to draw two nice bitmaps. Re-build and re-test. Nicer! I also changed the arrows a.k.a. triangular expanders to their bigger size available in Serenity. I tuned a little the colors so that the expanders don't disappear on a white background and I could go on... to the next task.

While I was playing with the tree view in Konqueror and aKregator, I noticed that I couldn't stand the column headers any more. Too big, too whatever. I decided to make them totally flat with little separators and that led me to crashing KDevDesigner more than once.

For some reason, when you click on a column (or row) header in a QTable, not exactly the same parameters than everywhere else are passed to the style to draw this header --especially the parent QHeader isn't provided. Serenity which wasn't aware of that and used the QHeader to retrieve pieces of information just exploded. I put a safety guard and no more crashing happened. I also gave another color to the headers and that was it.

Before all this, after my previous blog, I made up my mind and removed a few options from the configuration dialog so that I can point the finger and say "This is the way Serenity is". First, the so-called serene groupboxes are always activated, as well as the menu bar groove and the toolbar handles --for usability reasons. Last detail, the separators are always solid lines now. Less code, more speed. While I was at it, I totally broke apart the configuration dialog. No more groupboxes with meaningless captions. I just kept the two columns but with a simple separator in between then and I added other separators in between "logical" groups of options. That's better.

Last thing I did was to get rid of an old legacy that Serenity was carrying around like a ball and chain. The routines behind the configuration dialog were spending their time converting options from text to number, back to text, and so on. I changed all this in order to use only numbers. That allowed me to remove quite a lot of lines of code and few in Serenity itself. But that doesn't prevent it from growing bigger and bigger. The first source of the version 0.2 weighted only 112 KB to reach... 196 KB now. A diet is impossible since it would only mean loosing bones, errr, widgets. ;-) And it will grow a little more because I want to add a new gradient style beside "serene" and "zen", one that would allow you to use the same color for the background and the buttons without making them disappear. My attempts have been unsatisfying so far. I'll take care of that for the next version.

Already?! :-D

Well, time to go packing, snapshooting, whatever...

2006-09-12

KDE: Coffee break

Time for my coffee break and I really deserve it. The work I did to prevent the window captions from flickering with Serenity window decoration is amazing. (Unashamed auto-congratulation!) ;-)

What caused the flickering was the multiple redraws which could eventually take quite some time, especially with the Zen button style. So the obvious solution was to reduce the numbers of these redraws and to accelerate any that would occur.

What I did is to reduce the drawing of the caption framing --even invisible-- to one single action: drawPixmap(). Of course, I already used a buffered drawing for the caption but the whole titlebar was filled with the background color before the pixmap was shown. That could take a lot of time because the framing needed to be totally redrawn, the caption eventually shortened... And during that fraction of second of calculations all you saw was the background... Hence the flickering!

The first thing to do was to mask the titlebar so that the background never shows over the caption. Easy: setClipRegion(wholeTitlebar - captionRectangle). Then I made each window "carry" a pixmap of its caption framing. If the style or the size of the caption, or else the state active/inactive of the window didn't change since last redraw, I just use this "carried" pixmap as caption framing, otherwise I redraw it. I make a copy of the "carried" pixmap, I draw the caption text over it and I put this modified copy on screen in one move. Whatever the time all the calculations take, you can't see anything but a smooth change.

I grabbed the border of the window and resized it as quickly as possible in every direction to force numerous total redraws of the whole caption. The caption text really slides smoothly over its framing. That's what amazed me.

Hey! Whatever you code is only theory until it is executed by the CPU. Theory is a rather dry matter while the result --especially a visual result-- is what can trigger emotions, like amazement.

The next thing I had to test was multiple and quick changes of the caption text. I launched KMail, replied to whatever email it selected and typed an utterly long subject. The first that came to my mind: "Attention à la marche en descendant du bus et en entrant dans la gare routière" followed by a bunch of random characters and spaces. Then I hold the Backspace down until KMail changes the subject to "(No subject)". Second amazement of the day. No flickering either while typing in or while deleting. And that definitively wasn't the case before I began theorizing. '\x3a\x2d\x44' (Coder's happy face.) ;-)

Another theory regarding Fitts' law "Bigger target, easier target" and the menubar. It's just a theory, I have absolutely no idea about how it would turn out. According to some usability rules, the menu entries in the menubar should be as large as possible and there shouldn't be no useless space in between them.

How to implement this in a style while neither Qt nor KDE are aware of this?

Qt allow a style to reduce the space in between the menu entries, eventually to nothing. Serenity already puts the entries closer than what KDE's default settings are. It's only a matter of a few pixels otherwise the menubar would look like too crammed. Now, imagine that I actually remove the spaces in between the entries. How could I space them another way?

There's nothing Qt allows you to do to put spaces only on each side of the content of a widget. Nothing unless you're ready to see the menu entries grow and grow indefinitely after each redraw. That's what would happen if I tried to resize the entries "on the fly". There would be no way to know if I already enlarged an entry on not. The only way is to enlarge the content, i.e. the text of the entry.

Here is my theory: What if I caught the redraw of a QMenuBar in the event filter and added, well, 2 or 3 white spaces around each of its entries before to let the redraw happen? (To check if an entry already begins with spaces is easy so we wouldn't see the entries grow indefinitely.)

In theory, that should work without taking too much time. A menu seldom contains more than a dozen of entries.

if ( ::qt_cast<QMenuBar*>(obj) && (ev->type() == QEvent::Paint))
{
QMenuBar* menubar = static_cast<QMenuBar*>(obj);
for (uint index = 0; index < menubar->count(); index++)
{
int id = menubar->QMenuData::idAt(index);
QString entry = menubar->text(id);
if (! entry.startsWith(" ") )
{
entry = " " + entry + " ";
menubar->changeItem(id, entry);
}
}
return false;
}

It even compiles.

:-> (Devilish smile...)

And it actually works! Yes, that's just simple. (And only one white space is enough to retrieve the same spacing as before my patch.)

Before:
The menubar without the patch


After:
The menubar after the patch


The usability avantage: You can't "fall" in between the menu entries. Whenever the mouse cursor is somewhere in between the first and the last entry, an entry is always under it. That's better.

I shouldn't say it but I surprize myself sometimes. :-b

Well, the coffee break has been over for a long time, now. I'm gonna find the way not to generate too many intermediate QString's along my patch.

2006-09-08

KDE: And again...

No, I won't release any new version of Serenity today or tomorrow... But I already made modifications to the version I use. Already!

Just the day after I released Serenity 1.2, I kinda felt that the so-called Zen borders of the widgets weren't so zen after all. They were in fact too hard. Here came the first patch: I made them wider so they look smoother.

Still, that wasn't enough to justify an official update. I did some more modifications.

I started to use KMail and KNode instead of Thunderbird. Why KMail? That's because Thunderbird didn't allow me any more to type all the accented characters I was used to. To type the very common french û ("u" with a circonflexe accent), I had to copy and paste it from outside Thunderbird. I did it once, twice, thrice... And no more. KMail offered me the full support of my keyboard through KDE.

The transition was however a bit rough. When I asked KMail to import all the mails from Thunderbird, it took hours! KMail imported absolutely everything: mails, newsgroups... and all the available files! I had archives for my mailing lists which went back to 2004 --one with over 16000 mails-- and it took so much time that I killed KMail several times when I was obviously slow to react.

Creating filters for my mailing lists was another issue. I forgot once or twice to tell what to do with the mails matching the criterions I entered, KMail accepted it and I found myself wondering why some filters did nothing. And the fact that KMail wants by default that all the defined criterions apply to filter a mail didn't help either. Everything was correct but the mails couldn't match all the criterions together and the filter didn't work.

After that, I dealt with the usual toolbar bloat --I left nothing more than "Compose", "Reply", "Mark all as read" and the useful "Mark as SPAM".-- and I could start to feel at home after a little trip through the Jungle of Options.

Next, I had to set up KNode. I couldn't use Thunderbird any more or it would mess with my mails. That what easier because the filters are somewhat already defined... but I couldn't avoid another trip through the Jungle of Options. I treated the toolbar the same way I did with KMail: "Compose", "Reply", "Jump to next unread" and "Load all" --since KNode doesn't do it automatically. That's more than enough, I added the "Jump" action because KNode doesn't do it by itself when you click on a newsgroup otherwise there would be no more than 3 icons in my toolbar. As for feeling at home, I will when I'll be able to sort the newsgroups by hand... and through another means than inserting a number in front of the name of each newsgroup.

All this led me to more patches for Serenity. The reason: KNode is ugly! The big blocky panel resizers made my eyes bleed and the tiny buttons on top of the panels finished the job. These widgets could definitively not stay on screen with their pointy corners hurting my eyes. That was another job for Serenity.

The tiny buttons were relatively easy to style once I found another style which takes care of them: Domino. (Hi, Michael!) Well, I first made extensive researches in KNode sources to find the class of the widgets. ("KDockButton_Private" for those who are interested.) Then I searched through my "database" of styles and through KDE's default styles. Only Domino knew what a KDockButton_Private is. The way these widgets are handled in Domino isn't obvious but I understood how to recognize them. A little more digging into KDE sources and that was it! Serenity could handle these ugly widgets and turn them into something nice with new symbols.

The panel resizers were a totally different story. I already saw what they were somewhere while I was looking for KDockButton_Private but I spent quite some time turning around before I realized I had already found it. Needless to say that this so-called "panel resizer" widget is another proof of the (twisted) imagination of KDE's developers. It isn't a "real" widget with a class of its own but only a sub-widget of another one --drawn on the fly--, almost out of reach of a style plugin. For those interested in details, it's a QFrame of which the name() is "pannerdivider". Once you know that, it's easy to catch its QEvent::Paint in your event filter to do what you want about it. And what I did was to re-design all the resizers/splitters within Serenity in order that they become more visible.

The last thing I did in Serenity is almost invisible. Well, in our world of free standards, we shouldn't see much of them but Konqueror recognize these proprietary extensions of the CSS standard to change the colors of the scrollbar on an HTML page. I already did something for the slider. This time, I added the scrollbar groove and the arrow colors. The somewhat standard style of KDE doesn't do as good as Serenity. I'm proud of myself... :-D ...and of Konqueror which does better than Firefox. For me who enjoy --I don't know why-- seeing my widgets with unexpected colors, the colored scrollbars are another (futile) reason to prefer Konqueror. (See for yourself how the style you use handles them.)

It's way too early to make an update... so I'm going to find some more lost widgets... to justify it. ;-)

2006-09-04

KDE: I did it again!

That's it, Serenity 1.2 is out in the wild. It took me longer than expected because I took the time to do all the changes I wanted.

First, there was that little itch in the titlebar. I had resisted since version 0.9 to the urge to scratch it. With the BeOS/B2-alike titlebars, there wasn't always enough room left for the title. It was never more than a dozen of pixels but that was irritating to me. Now Serenity automagically cuts parts on both ends to make the title fit. It's not perfect but that's an improvement over the past. I played a lot with it and enjoyed seeing the title shrink and grow while I was resizing the window. (Boys will be boys.) ;-)

Second, two things I noted in a corner of my mind: The separators in the tabbars and in the scrollbars. For some reason they were simple lines and I never took the time to changed them into gradients... until yesterday. That's more "serene" and that fits well with the new soft gradient in the active tab. I was touching the tab drawing routine so I did the most I could, and that meant to soften these flashy gradients I couldn't stand. Now, the "Serene gradient" is the way I like to see an active tab. --I can even stand the "Highlighted gradient" sometimes with the right colors.

Next: The radiobuttons. The problem was that with the new Zen gradients, the radiobuttons looked too square. The outline was still a circle but it didn't matter, the inner gradients just turned it into a square. My job was just the opposite: to turn a square into a circle, well, to turn four straight gradients into a circle. It was easier to do than to say! I already had the image and the algorithm in my mind before to start to code. These radiobuttons however drove me nuts! I made no error... except in the way I chose the colors. I broke everything into pieces before to realize where I turned right instead of left --more or less. Any way, the result is so nice that I updated my previous blog so that it keeps on making sense with the new image. ;-)

Now, I'm gonna drop Serenity for a while... a long while and take care of patching KDE before version 3.5.5 comes out. Something I'd like to fix is the fact that KDE opens a file in the first available supporting application --if it is already opened-- instead of looking for it in the current desktop first. In clear, for example, Kate is running on 1st and 2nd desktops. The current desktop is #2. You click on a text file and it get --silently-- opened on desktop #1. Stoopid! Any way, I think I'm gonna have fun with this bug. A little challenge...

2006-09-01

KDE: Never enough...

It looks like I can never get enough. I updated Serenity once again. But I didn't release it immediately because, when I was looking for a good colorscheme to make a snapshot, I realized that the progress bars definitively should have another color.

Here is what Serenity 1.2 looks like with the colorscheme "Caloris Planitia". Notice how the progress bar fits in the dialog. That wasn't always the case and that's what led me to stop the release. I had to achieve the same effect with any colorscheme but the colors I chose for the progress bars didn't make it.

I just launched a "background process" in my mind to work on this and I got the solution when I finished typing in my blog. Multiple personalities is a good thing... sometimes. ;-)

Well, if you looked at the snapshot, you couldn't miss the new Zen gradients. I was growing dissatisfied of the titlebar the way Serenity drew it. Too flat, probably.

My first idea was to fill the titlebar and the window frame with some color. It lasted less than one day. To make things look better, it was necessary to make the menubar groove match the titlebar. It got me into troubles. It wasn't so hard to get the color of the titlebar gradient from within the style but I couldn't find the right way to know if the window where I was drawing the menubar groove was the active one or not. And even without that, I got a big problem: The GTK apps refused to start because the GTK-Qt engine --I guess-- was complaining about something I did.

Next idea, please!

I did it again but the other way around. I filled the titlebar with color of the menubar groove. That was much easier... but I didn't really like the result. Too dull.

Next idea again, please!

I totally dropped the idea of filling the titlebar with any color. Instead, I focused on the frame. First, I wanted to make the whole window have a diagonal gradient like Serenity's buttons. It was a stupid idea implying a lot of calculations to get the right colors to draw all the needed gradients that would be barely distinguishable in the so tiny space of a window decoration. Nevermind, I could get close through some simplifications and in a little more space. That led to the new framing you can see on the snapshot. It doesn't require that much calculations and I found the result amazing. (Yes, I know I flatter myself... but that's because I know what's behind the result. And especially behind the 35 pixels at the bottom right of the maximizer!)

Then I thought: "What would the buttons look like if I used the same design?"

The result --as you can see-- is very nice. So, that was it! I got a new way of drawing buttons and surfaces in Serenity. I called it the "Zen gradient". I removed the "Soft" and "Hard" gradient to leave only three gradient styles in Serenity: "Serene" (diagonal formerly known as "Regular"), "Zen" and "Flat". As usual, everything is switchable to be able to make Serenity look like its former self. I personally fell in love with the new Zen surfaces. I was very proud of my diagonal gradient routine and now I can see it in every corner... literally.

At this very moment, one of my secondary personalities was knocking inside my skull to have the keyboard and implement the new progress bar colors. ;-)

And I said: Expect the new Serenity sooner than expected. --If you see what I mean. ;-)