Qt Invaded By Aliens — The End of All Flicker

No, this is not a wet dream -- it's all true; with Qt 4.4 you will be able to get rid of issues you have had with flickering. Just to make sure we are talking the same terminology, I've created a small movie demonstrating the problem:

Given the fact that we've passed the 90's, this is not acceptable and up to Qt's standard. As of today, every single widget in Qt has a native window that is managed by the window system -- in this case the X server. The flicker you see on the movie is a result of multiple X windows trying to synchronize and play funny games with the X server.

But how can we improve? With Qt 4.1 we took a huge step towards resolving similar issues when introducing the backing store, but it can't cover resize flicker as it's fully caused by the X server. The only consequent and necessary next step is therefore to bypass the X server and let Qt do the job. In order to do that we must make our child widgets non-native -- a.k.a. alien -- such that X doesn't know they exist. That sounds pretty easy, doesn't it?

Moving away from native windows isn't done over the night. Window handles have been in Qt from day one, and consequently our GUI kernel is heavily built around them. The main technical challenges in that respect have been core functionality such as mouse events, widget cursors, enter/leave events, drag'n'drop and so on. With native windows all widget events are related to a window handle and our job is simply to map system events into Qt events. Consequently, when we make our child widgets windowless, all events are related to the top-level window and we have to figure out ourselves which widget is the correct receiver for the given event. To make it even more interesting, all this depends on the platform your application is running on, so there's no way it can be fixed properly in cross-platform code.

A somewhat funny scenario is drag'n'drop on Windows which is based on Object Linking and Embedding (OLE). Every drag'n'drop operation consists of at least two COM objects representing the source and the target. A widget acting as a drop target must register its window handle such that Windows can communicate between the source and the target. It's not hard to imagine that some black magic is needed when the top-level window is the only native window we have, possibly acting as source and target at the same time.

And what happens if we suddenly create a widget that requires a window handle? Consider the scenario where a QGLWidget is the central widget of QMainWindow. Widgets with the Qt::WA_PaintOnScreen attribute set -- in this case the QGLWidget -- must have a native window to function properly. That's OK, but the fun starts when we have to deal with clipping between native and non-native windows. Clipping between native windows is indeed handled by the window system, but it doesn't help much when the only clipping we get for free is between the top-level and the GL widget.

Needless to say, but apart from reducing flickering, an application with windowless child widgets is much more light-weight and resource friendly as we don't allocate native windows for every single widget.

I wish we could have taken this step a bit earlier, now that KDE 4 is around the corner, but there's little point in adding hacks and workarounds now to avoid flicker with Qt 4.4 bringing the real solution soon.

I could probably tell you a lot more, but I'll keep this blog short. Currently this work is going on in a separate research branch so it won't show up in our snapshots, but within few weeks you should be able to try it out. I'll blog with more details as soon as we have it integrated.

Last, but not least, here's the obligatory movie showing how resizing with windowless child widgets looks like:

Blog Topics: