Thursday, July 24, 2008

How to easily mix QWidgets and OpenGL

Around a month ago there was a post at Trolltech Labs Blogs about embedding widgets in QGLWidget. I had been wanting to do something like that for KGLLib, so I downloaded the demo and took a look. It worked fine, but the code didn't exactly fit my purposes.
The demo did all the OpenGL rendering in the QGraphicsScene subclass. Usually it is done in QGLWidget subclass and I wanted a solution which would be as transparent as possible. Thus the rendering had to stay in GLWidget.
The second problem was the events. The event handling could have been done in QGraphicsView or QGraphicsScene subclass. But if I already have a GLWidget using event handlers, I'd prefer them to continue working as before. So some kind of smart event forwarding was needed to send the events either to the gl widget or to the graphicsview, depending on whether any of the QGV widgets had focus.

I have now solved both problems and the result is a class called WidgetProxy. It takes a GLWidget as an argument and creates a QGraphicsView object, using the GL widget as viewport. The OpenGL rendering is done in your GLWidget as usual and QWidgets can be drawn onto the OpenGL scene. It also tries to do the right thing concerning events: mouse events are sent to whatever is behind the cursor (QGV widget if there is one behind the cursor, otherwise to the GL widget). Keyboard events are sent to whatever has the focus.

It's really easy to use: if you have a toplevel QGLWidget and want to add widgets into it, all you have to do is first create the WidgetProxy object:
WidgetProxy* proxy = new WidgetProxy(myGLWidget);
and then add some widgets:
QWidget* embeddedWindow = proxy->createWindow("Window title"); embeddedWindow->layout()->addWidget(new QLabel("This is an embedded widget!", embeddedWindow));
embeddedWindow->move(10, 10); proxy->addWidget(embeddedWindow);
If the GLWidget is not toplevel but in a layout then the only difference is that you have to add the proxy, not the GLWidget, into the layout.

You can even show() or hide() the GLWidget and it works as before since the WidgetProxy intercepts those events, showing or hiding the QGraphicsView instead.
The aim is to make it possible to have widgets in OpenGL with pretty much a single line of code - often the user of the GL widget doesn't even need to know about it.

The code is now part of my KGLLib, along with an example ("widgets"). KGLLib's code can be found in KDE's SVN, in trunk/playground/libs/kgllib/.

Wednesday, January 2, 2008

New year, KWin and other stuff

First let me wish you all happy new year :-)
2008 is certainly going to be an interesting year for KDE with the next major version finally being released and the focus shifting from refactoring to polishing and using the new APIs. I can't wait to see what people will come up with by the time KDE 4.1 or even 4.2 gets out.

KWin's compositing has seen many improvements in the last months, but we're still not completely sure if we want to enable it by default (even only for the selected cards and drivers). If we enable compositing and it unexpectedly fails for someone then there's the chance of him/her not getting a usable desktop at all and we're not sure if we want to risk with that...
Should we disable it for everyone by default (it's not difficult to enable anyway) and wait until we implement some safeguards for 4.1? Or should we enable it because it works for most people for whom it's enabled by default and end-users are less likely to adopt 4.0 anyway? What do you think?

I've also got a few more interesting things coming up, but I'll keep those for the next time ;-)