my KDExperiments

Programming, KDE and more

Trying to solve compositing problems of Qt widgets as X11 windows July 21, 2007

Filed under: qt,x11 — FeticcioFelino @ 4:57 am

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 πŸ™‚


14 Responses to “Trying to solve compositing problems of Qt widgets as X11 windows”

  1. clee Says:

    Haven’t you heard of Composite?

  2. iax Says:

    XComposite is just that. An extension to X protocol which allows for this kind of thing.

    Unfortunately semi-transparency requires much processing, so to use composite you will require a good graphic card anyway, and hardware accel. This is why it is used almost always with OpenGL.

    The problem is not the single animation you may require. If the X server is composite enabled, *every* app could want to use it. So without accel it is intractable.

    Qt could check if Composite is enabled at runtime and use it if they were compiled to do so (a QT_NO_COMPOSITE). But that would require a fallback. KWin in KDE4 will do it, it seems. If they succeed, Qt may take the same approach. We will see.

  3. Leon Bottou Says:

    Isn’t that the purpose of
    the X11 windows of class InputOnly?
    (see Xlib reference manual, section 3.3)

    – L.

  4. Enrico Ros Says:

    I kinda worked around this problem by using a QGraphicsView as the main drawing surface in my apps and adding some QWidget like wrappers to place my custom widget-like contents on the screen. This allows to move or resize this kind of ‘widgets’ without the nasty X11 effects (but i have seen something similar on Win* too).

    I hope that the Widgets-On-The-Graphics view stuff that is being worked on at Trolltech will help to solve this very very very bloody thing!

    Ciao Maurizio!

  5. Maurizio Says:

    @clee, @iax: no, XComposite is not the solution for this problem, because compositing is done internally by Qt and we do not want X to waste additional memory for child widgets (don’t misunderstand me, for toplevel windows XComposite is the way to go), it should just behave in the correct way.

    @Leon Bottou: interesting, i didn’t know about this (i don’t know X very well). If so, maybe some troll could let us know if what i proposed would be feasible.

    @Enrico Ros: ciao Enrico! Happy to see your reply here, and to see that you solved your problem. Unluckily your solution cannot work in the most general settings, because for instance i may want to place some animation over already implemented standard Qt widgets (such as buttons, checkboxes, etc).

  6. clee Says:

    @Maurizio: On the contrary, what you’re saying is that Qt is creating a new window, which is *exactly* what Composite is for.

    Please read more on it before dismissing it.

  7. iax Says:

    @clee: Qt already uses the compositing features of X. Pixmaps and widgets are stored in X.

    It is my understanding (can be wrong) that the main problem is that they use still window hierarchy for distribuiting input, and that this way X associates the windows with the on screen pixmap in the same area. So moving the window moves the pixmap area around, instead of just triggering a redraw in the Qt.

    The flag InputOnly that Leon speaks of could change this behaviour, explaining to X the true purpose of the window. X would not try and redraw the child window when it moves but leave it to Qt. This avoids flicker.

    To sum it up: Qt already uses the XRender extension, so it should be just a matter of putting X to sleep.

  8. Maurizio Says:

    @clee: XComposite works with a double buffer for each window it will compose, and this would be a huge waste of memory.

    At the moment Qt do compositing in its own stack, and it works well in this way *except* for bad interactions of the X server when a widget/window is moved/destroyed withing its parent.

    A compositing manager is useful when the windows being composed are created by different application that cannot easily interact, in this case it is really not required because each application can succesfully take care of its own widgets.

  9. […] Trying to solve compositing problems of Qt widgets as X11 windows Since Qt 4 all widgets are double-buffered, and every widget is drawn over the parent widget, for instance allowing it […] […]

  10. Enrico Ros Says:

    Just read the comments on today Zack’s web-on-canvas-and-dashboard-widgets post.. seems like QWidgets on the canvas is coming in 4.4. This won’t solve the general case that you outlined, but will allow anyone that based his own app on QGraphicsView to have nice overlays and animations!

    @maurizio: I think that the problem you’re outlining is somewhat serious and should be reported to Trolltech.

    Con affetto,
    Enrico πŸ˜‰

  11. Maurizio Says:

    Riccardo: Yup, i already commented on that blog post too πŸ™‚

  12. Kevin Mills Says:

    I stumbled across your posting while looking for a solution for creating a transparent window in X. I am trying to do the same thing in an environment where I *know* I won’t have a capable Window Manager (older AIX and Sun machines running CDE or OpenLook). Would you be willing to share the manual solution you found? And any chance you’d know how to do something like this *without* Qt?

  13. Maurizio Says:

    No need, this problem is now officially fixed in the snapshot of Qt 4.4

Comments are closed.