CoreText backend now in Pango master

A few days ago I merged the first part of the CoreText backend into Pango’s master branch, after bitrotting on my disk for a full year (apologies for that). The upside is that it also got a year of testing on my machine :) The CoreText backend is enabled by default on machines running Mac OS X 10.5 or higher and used instead of the older ATSUI backend. Because the older ATSUI API has been deprecated since Mac OS X 10.5, and more importantly because the ATSUI API is not fully available in 64-bit mode on Mac OS X 10.6, we were in need of this CoreText backend. When using GTK+ on Mac OS X 10.4, nothing changes, since CoreText is not (publicly) available on these systems.

So far, the CoreText backend was mostly based on the existing ATSUI code, so it should be working nicely for most people. If not, you are welcome to file bugs in the new coretext component in the Pango module in GNOME bugzilla.

There is one missing piece and that is also where the CoreText backend’s structure is going to deviate from the ATSUI backend. The ATSUI backend has never been really good at handling font fallbacks and fonts for non-Latin languages (see 608929). This is one of the things I want to get right in the CoreText backend and will be the second part of this project. I do have some things in place in a local branch on my disk, but it is not working yet as it should. Hopefully, I can find some spare time in the coming months to finish this. Progress can be tracked in bug 647969.

Though up first is a context switch back to GTK+ to review and fix a couple of things around GtkTreeModelFilter, GtkTreeModel’s row-deleted signal and to further extend the unit tests in this area.

GDK 3.0 on Mac OS X

In the GTK+ 3.0 branch, GDK saw quite some changes recently. Firstly, a last part of Benjamin Otte’s rendering-cleanup was merged, which removes GdkDrawable. Now that GdkPixmap and GdkImage were already removed before (in favor of using their Cairo counterparts), there’s no need to abstract these away behind a GdkDrawable. Only GdkWindow is left to deal with basically.

The other large refactoring is the “GDK backend” branch that was recently merged. Before, you could only select a single backend at compile time, resulting in a libgdk-<platform> and libgtk-<platform>. GDK has now been refactored to properly separate the backends from the generic “core” GDK code. It is now possible to compile multiple backends into the GDK library. Perhaps in the future loadable backends will be possible as well. This work is in particular interesting for linking in both the X11 and Quartz backends on Mac OS X (for testing, comparing and debugging), and X11 and the upcoming Wayland backend on Linux. I am pretty eager to try a both X11 and Quartz enabled GDK on Mac OS X, but still some work is left to do sorting out the platform-specific code in libgtk. But once that is done, it should be possible, the GDK part is already done.

All in all, I am pretty excited about all the attention GDK has received in the last months after being neglected for a long time. In GTK+ 3.0, GDK is much easier to port to other platforms than it was before. I hope a trend has been set and GDK will be further simplified in the future.

I have tried my best to keep the OS X backend up to date over all these changes and refactorings. It seems to be working fine, so it is in shape for GTK+ 3.0. Let’s say it is at least as good as the last GTK+ 2.x releases, maybe even better.

I really hope we are done with refactoring for a while now, so I can focus again on reviewing and implementing missing features in the backend :).

Refactoring GtkTreeView using GtkCellArea

Over the last few months Tristan van Berkom has been working on GtkCellArea. GtkCellArea can be described as a generic class that can be used for layouting and rendering sets of GtkCellRenderers. Before, widgets dealing with GtkCellRenders, such as GtkTreeView, GtkCellView and GtkIconview, all implemented this by themselves. In GtkTreeView, most of this code was hidden in gtk_tree_view_column_cell_process_action(), a function that not many people dared to touch and a function more fragile than a box of wine glasses.

I tried to support Tristan by showing him around in the more obscure parts of the GtkTreeView code, showing him some interesting corner cases and by reviewing the new code. As soon as it was possible I attempted a migration of GtkTreeViewColumn to use the new GtkCellArea. To my surprise, this was much less painful than I had expected, which is a good thing :) After that we had to spend a lot of time polishing things and fixing corner cases, finally everything was merged in the GTK+ 3 branch. Furthermore, Tristan has worked on porting GtkComboBox/GtkCellView and GtkIconView over to use GtkCellArea as well. We expect these changes to be merged in time for GTK+ 3.0 as well. What is great is that we managed to do all of this without introducing API incompatible changes, so existing GTK+2 code using GtkTreeView will continue to compile and work as is.

I think the end result is great, the GtkTreeViewColumn code got a well-needed refactoring, code duplication amongst GtkTreeView/GtkIconView/etc. has been reduced and we have paved the road to properly support height-for-width in GtkTreeView. We hope to work on the height-for-width support in the near future, this will not be trivial task as we will have to take a closer look at the validation machinery of GtkTreeView and perhaps revamp that as well. During this process I hope to incorporate some changes I made to the validation code in a local branch, with these changes it is possible to remove the idle handler that goes over all rows in the GtkTreeModel in the background for measurement[1] by trading in scrollbar accuracy and perfectly sized columns. With this, we can support large models without having to explicitly enable fixed height mode (in fact, this mode can then be removed). There is a possibility that we end up moving this code into a separate class (maybe GTK+-internal at first) as well, which can be re-used by GtkIconView to support displaying very large models (currently GtkIconView will likely fall apart when you try that).

Rests me to thank Tristan for the hard work!


[1] Footnote for users of large GtkTreeModels: However, the entire model will still be fully iterated because of the reference counting mechanism in GtkTreeView/GtkTreeModel. Properly supporting lazy loading of models will require different changes to GtkTreeView but mainly to the GtkTreeModel interface to have real support for this.

Optimizing legacy code

Earlier this week, I finally traced down an interesting “bug” in GTK+’s Mac backend. People were complaining that scrolling in certain applications worked very slowly. Which got me puzzled for a good while, since all tests I use showed no obvious performance problems. Profiling a test that did expose this slowness showed that a lot of time was spent on color conversion. Also, it turned out this problem only occurred when drawing to a GdkPixmap first and later copying this GdkPixmap to a window.

So why was this color conversion going on? We were creating a CGImage backing the GdkPixmap using the colorspace returned by CGColorSpaceCreateDeviceRGB(). Judging from the function name, this seems alright. But closely, very closely, reading the documentation revealed the gory details. After switching this to use a different, now generic, color space (as suggested by the documentation), all performance issues were solved. Basically, color conversion from the “device” color space to the “generic” color space was happening, which is now no longer needed.

But not so fast! This change seemed to work fine, after all it is just a color space change, but for the particular test case I was debugging it introduced very awkward drawing issues. This took a long while to track down and it turned out to be another problem with how we implemented GdkPixmaps. Also this has been fixed.

(For details see bug 615917 and especially 624025).

People may wonder why I am spending my copious spare time on debugging GdkPixmaps while all of this is removed in GTK+ 3. The reasons are twofold, firstly debugging problems like this greatly extend my understanding of the Mac platform. This will also help when I am profiling GTK+ 3 code in the future, perhaps the same problems are encountered.

Secondly, I want to leave GTK+ 2.x in a mostly stable shape before fully turning my attention to GTK+ 3. I am planning to fix two more rendering issues in 2.x: one rendering glitch with scrolling windows that are inside an offscreen window and another with drawing depth 1 pixmaps. After that, GTK+ 2.x should be in a pretty good shape rendering-wise.

That might be a good point to switch focus to GTK+ 3.x. Of course, we can always backmerge changes to GTK+ 2.x if useful, for example fixes and improvements to the GtkSelection/DnD code.

To end with a brief note on Mac OS Tiger compatibility. We have always attempted to keep GTK+ working on both (Snow) Leopard and Tiger. I think we will continue with that for the time being, since I still have access to a machine running Tiger. However, in case Cairo goes Leopard-only and drops support for Tiger and earlier, GTK+ will have to follow suit.

Unfortunately, I couldn’t make it to the GTK+ hackfest this year. There seems to be good stuff going on, particularly interested in the GTK+ 4 plans but haven’t seen much elaboration on those yet.

More GTK+ rendering cleanup and Mac

Since my last blog post two or more rendering-cleanup branches followed, which all got merged into master. So some more debugging was needed to get everything to work again on Mac. An interesting observation is that with each subsequent rendering cleanup, it became easier to get things going again on Mac. Very likely a good sign that we are on the right track to make GDK more X11-agnostic and easier to port.

Either way, as far as I can see GTK+ master runs pretty well on OS X now (including offscreen windows). The last rendering thing that really needed fixing was GtkTreeView (surprising or not?), which was actually sometimes resizing its GdkWindow while in the expose handler. This has mostly worked for a decade, but fell apart on OS X recently, since Cairo Quartz does not support resizing surfaces, so instead we destroy and re-create. The tree view is now patched in such a way that all resizing is done before we get to the draw method, so this resizing is no longer needed from inside the draw handler. I added a bunch of old scrolling test cases to the main tree view scrolling unit test, and all tests pass, so we should be safe. If your application depends heavily on tree view scrolling and you experience issues with GTK+ master, report this ASAP and we can get it fixed. Stand-alone test cases are appreciated as always :)

With the rendering working fine again on Mac, I hope to focus on other improvements now.

Finally: the work that has been done on the resize grip for GtkWindows is actually great news for GTK+ on Mac. Mac applications typically don’t have a window manager frame and thus rely on a resize grip. We had to leave the default Mac resize grip enabled, even though the GTK+ application didn’t expect such a grip there, obviously leading to sometimes awkward situations. So far I didn’t turn off the Mac resize grip (they seem to work fine together), since for GtkWindows without resize grip we still need some kind of fallback.

GUADEC, and the GTK+ rendering-cleanup branch and Mac

Lanedo was so generous again to provide accommodation for GUADEC so I could be around for pretty much the entire week. For the first time in years we had proper space for hacking, so a bunch of my colleagues and me spent most of the week hacking. We also talked with people, honest! Also power was plentiful available (often a problem). In its entirety GUADEC was pretty well arranged this year, thanks to all volunteers involved!

Either way, for most of the week I worked on getting GTK+’s rendering-cleanup branch to work properly with GTK+’s native Mac port. This involved debugging a bunch of evil/nasty clipping issues and hunting for missing cairo_destroy() calls after I figured that that can actually be an issue (on Mac). Result: the rendering-cleanup branch works fine on Mac now. As a second project I got offscreen windows to work in the Mac port, for now only in the rendering-cleanup branch. I hear all of this was merged in master yesterday!

The good part is that most of the rendering code has now been dealt with and doesn’t need much additional work as far I can see now. There’s still enough to do though, should be looking into selection/clipboard support (there’s some patches pending for this), keyboard/input methods, perhaps some of the performance issues people have mentioned (though in general, performance is pretty okay), etc. Ah yea, I must really finish up the CoreText backend for Pango as well before my code for that starts bitrotting…

Recent hacking – March 2010

I want to try to keep posting on any hacking I get done, so here we go an update on my post from March 5 (of this year ;).

I managed to clean up my port of the GTK+ Quartz backend to the xi2 branch that I wrote about in my previous “recent hacking” blog post. The patch has been sent off to Carlos Garnacho for some sanity checking. Before or immediately after the xi2 branch will be merged with GTK+ master, this patch will be applied so that the Mac port will continue to work just fine. More work has to be done on the xi2 branch in general to figure out some semantics so that different kinds of multi-touch devices/drivers can be generically supported. The main difference here is that some drivers always have, say, 10 fingers/pointers active, and other drivers add/remove these fingers/pointers on the fly. This discussion will hopefully take place on gtk-devel-list soonish.

Also I continued to work on the CoreText backend. Ran into some trouble figuring out how to implement font matching and fallback fonts. It looks like we will not be able to depend on CoreText to do this for us (the interfaces it exports for this are insufficient to implement a proper Pango backend with), so we get to do it ourselves. I hope to find the time soon to complete this work and push the branch somewhere.

My first cairo patch got accepted! On 64-bit Snow Leopard there were issues with drawing dashed lines in GTK+. Turns out this was caused by the introduction of the new CGFloat types in CoreGraphics. The patch in FreeDesktop bug 25814 that resolves this has been committed now and it looks like other projects using Cairo took advantage of this as well.

Recently I spent time on preparing review of bug 71926. In here, we received a very large contribution that implements bg_pixmap in GtkTreeView (finally!) amongst some other fixes. I have split up the patch into digestible chunks and plan to start processing these soon.

When all above is done I plan to most likely work on moving all my ideas and unfinished patches for GtkTreeView to the wiki and Bugzilla. Hopefully somebody will find inspiration in there and start hacking and contributing, since I have realized that I cannot do it all by myself and won’t be able to do so in the near future.

Recent hacking

Over the last week I finally made extensive time for some spare time hacking. I ended up writing a CoreText backend for Pango, which is much needed as the old ATSUI backend that is used on Mac OS X uses the ATSUI API that has been deprecated since 10.5.

While writing this backend I finally got a greater understanding of how Pango works internally. Also I managed to fix the most annoying bug on 64-bit Snow Leopard wherein some ligatures were incorrectly displayed using the wrong glyph (bug 608923).

I hope to be wrapping up development of this new backend soon. Further development and review will be tracked in bug 611943.

Oh yeah, so Lanedo flew all of us to Brussels for FOSDEM this year. (Well actually I went by train. The train was supposed to be hitting 300km/h, but that didn’t really happen, “software issues”, really!). Either way, had lots of time for hacking there as well. With Carlos Garnacho sitting next to me, I managed to port the GTK+ Quartz/Mac OS X backend to his shiny GTK+ xi2 branch in 1.2 days. In the remaining time I looked into getting support for the multitouch trackpads found on all recent Apple laptops going in GTK+/xi2. Even though the branch is called xi2, it is really the GTK+ multi-pointer branch. This last part has been moderately successful. We identified a few kinks in the new API that have to be fixed first. When that has been arranged, it seems well possible to have support for these multitouch trackpads in GTK+ Quartz, and that should be really cool.

When the above mentioned CoreText backend is done, I hope to find the time to at least push the port of GTK+ Quartz to the xi2 branch into the xi2 branch. This means that when the xi2 branch is merged into GTK+ master, the required OS X backend changes will already be included so the backend won’t be broken at that point.

Unit testing the filter model

One thing that has been on my todo list for many years was writing proper unit tests for GtkTreeModelFilter (the “filter model”). The state keeping that the filter model has to do is enormously complex. Sadly, this has caused the filter model to get to a state where it was basically impossible to maintain it, a patch fixing something would almost always break something else. Getting out of such a state is generally only possible by bringing the entire thing under test. And that’s what I have done about 2 weeks ago and took a week to get the basics of the unit tests right.

The majority of the filter model code is now under test. Not only the correctness of the model’s structure is tested (are the right nodes there? Also at the correct position? Are the right nodes designated as parents? etc.), but also whether the right signals are emitted at the right moment (and with the correct details/arguments).

While writing the unit tests, 2 or 3 bugs were uncovered and also fixed. Using the unit tests I was also able to clear the long outstanding filter model bug reports from Bugzilla. Actually, being able to do that was the entire point of writing the test suite ;). When handling those reports, the usefulness of the unit tests immediately proved themselves: when patching one of the problems (with a fix that looked generally okay), one of the other tests started to fail. This regression would not have been noticed without the test suite.

Hopefully, we’ll soon get support for seeing the testing coverage (from what I heard there is a bug/patch for this in Bugzilla). Some parts of the filter model are not under test yet, most importantly the intricate reference counting of nodes. Some day I will get back to this.

What I am also hoping for is to re-use some of the concepts used for these unit tests in unit tests for other tree models. And, of course, to come up with a generic tree model tester that can be used to test custom tree models.

Many people might find such a generic tree model tester overkill and say that tree models must be much more trivial to implement. That’s something for the future really. I will promise to blog about the plans/ideas I have for GtkTreeView and friends later on. (You can imagine that a lot of ideas have been brewing while I was busy finishing my studies ;) ).

Oh by the way, currently I am doing some work on GTK+’s Quartz backend. It has suffered from some regressions after the introduction of client side windows in GTK+ and I am trying to get those under control as well as cleaning up the Quartz patch queue in Bugzilla. After that I will most probably be looking into extending/improving the CellEditable API to finally get proper acceptance/cancellation behavior.

Abort, Retry, Fail?

So let’s try this blogging thing again — now from an all new location (I am at now) and a brand-new hackergotchi courtesy of Andreas. WordPress Mu supports importing old LiveJournals these days, which also worked fine for me, except for all new lines to have disappeared. But who is interested in old news anyway?

This blog post is really long overdue. Over the summer I slowly started to hack on a full rewrite of GtkTreeView’s drag and drop implementation and related exported API. People familair with the matter know about the numerous problems. Unfamiliar people probably still know about #70479: “DnD with multiple selected items won’t work”. Yes, this bug has been open since 2002 and it feels really great to be finally getting somewhere. I think I’ve got the new API basically nailed (it really works beautifully and I am personally quite fond of it) and I am currently trying to get support for the old API back in place in some kind of compatible fashion. As I also rewrote all of the internal drag and drop signal handling in GtkTreeView, I really threw out everything and started from scratch. For me this also means I now have a fairly good knowledge of how drag and drop actually works ;) I got a huge amount of inspiration out of a reply from Federico on my earlier attempts to get multiple item DnD going.

Another thing that has been brewing originated at the GTK+ Hackfest earlier this year in Berlin. I sat down with both Johan Dahlin and Emmanuele Bassi to have a quick look at “simple list APIs” for GtkTreeView in python and perl (matching person and languange is left as an exercise for the reader ;). Here “simple list API” really means an easy to use wrapper around GtkTreeView (and its companion objects). From the API found in both language bindings, I devised a nice, simple and easy to use C API. The implementation for this is also already there.

Both of these projects are really getting somewhere so expect detailed API proposals and review on gtk-devel-list in 1.5 month or so. I don’t know yet what to tackle next, I really want to finish off these two first. However, my to do and idea list is infinite, so finding something else shouldn’t be hard.

In other news, the end of my time at a University is finally in sight. I really hope to have received my Master’s degree well before the start of Summer 2009. I am really enjoying the classes I am taking this semester, but still it will be great when I have finally finished my degrees. Having the end (finally) in sight here also gives me a lot more inspiration, hence the GTK+ stuff I am getting done these days. And I also reached the age of 24 years 1.5 weeks ago … I am really getting old now :/ ;)