Making clang GObject aware

Before it’s Christmas again, I should blog about the nifty hack I did last Christmas, already nine months ago.

Often, I am quickly coding up test cases. Compiling and running usually goes like this (insert cheering after successful compile):

$ clang `pkg-config --libs --cflags gtk+-3.0` -o test/foo3 test/foo3.c
$ ./test/foo3  

(foo3:84880): GLib-GObject-WARNING **: g_object_set_valist: object class `GtkWindow' has no property named `width'

(foo3:84880): GLib-GObject-WARNING **: gsignal.c:2293: signal `delet-event' is invalid for instance `0x101865000'

And insert a sigh of disappointment after witnessing the GObject warnings. I figured that with all the GObject Introspection work going on, it would be quite nice to teach the compiler about GObject Introspection. So while snow was pouring down last Christmas, I hacked up a quick and dirty clang plugin. It looks like this:

$ clang -cc1 -fcolor-diagnostics `pkg-config --cflags gtk+-3.0` -load libGObjectHelper.dylib -plugin gobject-helper test/foo3.c
test/foo3.c:23:25: warning: object 'GtkWindow' has no property 'width'
  g_object_set (window, "width", 320, "height", 240, NULL);
                        ^
test/foo3.c:23:39: warning: object 'GtkWindow' has no property 'height' 
  g_object_set (window, "width", 320, "height", 240, NULL);
                                      ^
test/foo3.c:24:29: warning: object 'GtkWindow' has no signal 'delet-event' 
  g_signal_connect (window, "delet-event",
                            ^
3 warnings generated.

One of the features I wanted to add before blogging, was to also use the clang-style spelling corrections. For the last warning, it would say "did you mean ‘delete-event’?" Of course, there’s still much more to do than that to make the plugin feature complete.

This plugin will not work just with GTK+ source code. Because it’s using GObject Introspection data, it should work for any GObject library for which the GObject Introspection data has been generated.

The code is not ready for public consumption, so I am not releasing it just yet. My plan is to find time in the very near feature once my critical bugs are under control (or worst case during Christmas again :) and work on bringing the plugin into shape and trying it out on some larger examples. See below why trying it on larger examples first is quite important to figure out whether this plugin will ever be useful for the general public. When that is done, I plan to dump it in a public git repository for all to enjoy.

So, how does it work?

At its very core, the plugin walks over the Abstract Syntax Tree (AST) produced by clang. For the above example we simply handle calls to g_signal_connect_data and g_object_set. In order to verify whether the given signal or property name exists, we need to know the exact type of the object we are calling this function on. This is a problem that cannot always be solved.

What the plugin can currently do to solve this problem, is to determine where exactly the object pointer is assigned in the same function. If the object pointer is a GtkWidget *, we could at least assume that the object contains all signals and properties belonging to GtkWidget objects. In the next line, it is possible that the value of a call to gtk_label_new() is assigned to the object pointer. In this case we know the object is of type GtkLabel and as a result we can catch more errors.

The above strategy works fine on simple examples. The challenge is to make this work for larger programs. It might be a reasonable assumption to say that often an object is created, properties set and signals attached in the same function. However, there might be many cases where an object is created in a separate function and only a GtkWidget * type is returned. When the function is in the same compilation unit, it will still be possible to find out the full type though.

It is already clear that the plugin will never be able to catch all errors. Still I expect it to be pretty helpful. Another case which is interesting to handle is the following:

GtkWidget *widget;

if (can_edit)
  widget = gtk_entry_new ();
else
  widget = gtk_label_new ();

g_object_set (widget, ...

We will never be able to report all possible errors in this case. For example, if widget is assigned a GtkLabel and we use a property from GtkEntry, we cannot catch it. What we can do is tag the widget variable with both the GtkLabel and GtkEntry types and put out an error if a property or signal is used that is neither in GtkLabel nor in GtkEntry.

Why not just program in a higher-level language, then you would not need a plugin like this?

Good question.


To be continued …

ANSI to HTML conversion courtesy of a2h

Merged “treemodel-fix” branch into GTK+: call for testing, blog post series

Over the last few months I have been working on a “treemodel-fix” branch, which I just merged into GTK+ as announced on gtk-devel-list. Two commits in February of this year touched the row-deleted handling of GtkTreeModelFilter and GtkTreeModel:row-deleted documentation (0c3da06 and f632956). When exactly GtkTreeModel:row-deleted should be emitted has always been a nasty inconsistency amongst models (I wrote about it in May 2007, which turned out to be wrong), so my interest was sparked into really trying to understand this inconsistency and how to fix it.

This resulted in the “treemodel-fix” branch, which I could only start working on in May this year. After I finally solved the GtkTreeModel:row-deleted issue for real (details will be in my next blog post), I decided it would be good to also solve problems in another area which has never been 100% clear to me: reference counting GtkTreeModelSort and GtkTreeModelFilter. I brought these under unit test and fixed any issue I could find, which took much longer than I expected. And finally, after adding quite some unit tests, I now dared to review and apply a couple of GtkTreeModelSort/GtkTreeModelFilter patches which were waiting in Bugzilla.

The code is now in the master branch and will end up in GTK+ 3.2. For heavy users of GtkTreeModelSort/Filter, this would be a good time to test your code against GTK+ from master and report any regressions you may encounter. If things look good, I will consider merging the branch in GTK+ 2.24 as well in 1 to 2 months from now.

It has been 9 years since I first started working on GtkTreeModelSort and GtkTreeModelFilter. Finally having the feeling that you fully understand what is going in these pieces of code is an interesting one after so many years ;) To make sure this knowledge does not get lost, I wrote extensive documentation containing most of what I’ve learned in the last months, which has been committed as part of the branch (see files gtktreemodel.c, gtktreemodelfilter.c, gtktreemodelsort.c). I will also run a series of blog posts on the matter, covering:

  • The real story behind GtkTreeModel::row-deleted
  • Reference counting in GtkTreeModel
  • Improved performance in GtkTreeModelSort and GtkTreeModelFilter
  • Limitations on visible functions in GtkTreeModelFilter

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 live.gnome.org 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.

The Hague has a University??

In a blog post it was mentioned that GUADEC will be held at The Hague University this year. I immediately wondered; does The Hague have a University?? Although The Hague is the political capital of the Netherlands, it does not have a University. Looking at the English website of this “University”, they call themselves “The Hague University of applied science”, with “of applied science” in a very tiny font. And that is the correct name, since it is not a regular, real University. Right now they can use the shorter “The Hague University” even though they are not a University because the name University is not protected by law in the Netherlands. In Dutch the name “hogeschool” or HBO is used for this kind of educational institutes, I hear this is similar to “Fachhochschule” in German.

More and more “hogescholen” in the Netherlands are naming themselves Universities, which I think is a shame and misleading. Why misleading? These institutes are not allowed to hand out the academic BSc or MSc degrees, they can only offer “professional” bachelor or master degrees. Some actually offer BSc and MSc education, but they can only do so by using course material of a recognized University that can actually hand out these academic degrees. In this case, you will not receive a BSc or MSc from this “hogeschool”, but from that recognized University. Pure re-sale of education. Things like this are not clearly stated on their website and might be very misleading to prospective foreign students (who will hopefully look more closely to see what kind of degrees are actually offered). Why a shame? It might devaluate the proper academic degrees that people have obtained at a real University because of confusion and fraud.

Most likely this is being caused by the shitty state of education in the Netherlands. Especially at these “universities of applied science” the focus is on making money and not on providing proper education to the students. (Yes, there are real world examples of this). This focus results in appointing leaders that have no clue about teaching, only about making money. Add to this a secondary school system that has been changed twice or thrice in the last 10 years and is still failing, a system wherein Universities are paid by the number of graduated students but not by quality of education and research, and a constant threat of cutting budgets even further, and you have a recipe for failure. The Dutch government has ambitions to offer the best education in the world, but is falling short due to mismanagement across the board.

The good news is that legislation is apparently in the works to protect usage of “universiteit”, “university” and “hogeschool”.