Since Qt 4 all widgets are double-buffered, and every widget is drawn over the parent widget, for instance allowing it to be transparent. But problems come if you are trying to move your semi-transparent widgets around, or you create/destroy them, because Qt will create an X window for each widget, and X is not really designed to do such things (EDIT: ok, X is designed to do this, but is not interacting well with Qt behaviour). The result is that X will copy the content of the widget when the widget is moved (and this is wrong, because it is semi-transparent!), and erase the parent window when it is destroyed (this can be avoided setting a flag for the parent, but this is not done by most Qt widgets). Then, Qt will paint the correct content, but the result is that your app will flicker as hell.
Namely, what Qt does is creating a unique double buffer for each toplevel window, compose all widgets on it, and then copy from the buffer to each X11 window. In the image above, suppose that the triangular region needs to be redrawn. Qt will draw in its internal buffer (that is an image as big as the widget A) part of the widget A, and over it the correct parts of widgets B and C, in order to completely update the triangle. Then blue, red and green regions will be copied onto the X windows that represent widgets A, B and C.
Here instead I show what happens when a X window with Qt-emulated transparency is moved. Not really nice. In the end the correct content will appear, but what X did was not really helpful.
I have been trying to solve this problem for a while because i wanted to enable a few new graphical effects for Tagua, and yesterday i also wrote a crude hack trying to solve it by placing a completely transparent widget in front of everything that would track all mouse events and dispatch all received events to the underlaying widgets. Well, i was able to get no flicker, but a lot of complex code had to be written to send move/enter/leave mouse events to the correct widget, and many cases where left unhandled (such as drag/drop events, focus, etc). Replicating a big part of Qt/X11 event management just to get rid of flickering is not the right thing to do (and almost impossible to do in the right way), so this is surely not how this problem will be solved.
A true solution would require some support in the X server. This could be solved temporarily in Qt at the price of creating only one toplevel X window that would contain all child widgets and track all mouse events, but this is surely not optimal because most widgets (such as buttons) do not require all mouse events but just enter/leave notifications, and, since applications comunicate with X through a socket, receiving all mouse events would wast resources. What is required is a flag to prevent X from copying the content of a window being moved, and some support in Qt for such flag. Or a way to tell X to just create input contexts in place of windows, in this case all painting operations would be done onto the toplevel window, and probably it would also be easer to handle for the toolkit and a bit faster (because an invalidated region that spans through many widgets could be updated all at once).
I’d like to know if some work is being done by some graphics-ninja to solve this problem 🙂