[Interest] How to integrate Qt's event loop with our own without losing Windows messages

Catalin Iacob iacobcatalin at gmail.com
Mon Apr 22 22:36:28 CEST 2013


We're using Qt 5.0.2, specifically WebkitWidgets to render HTML on top
of a 3D scene which itself is rendered with Direct3D or OpenGL.

Some more details: we have an existing 3D rendering application which
wasn't using Qt at all until recently. We want to overlay buttons,
indicators etc. on that 3D surface and we want to implement that in
HTML and Javascript. With quite little effort (Qt's APIs are awesomely
easy to use) we now have an invisible QWindow with a QWebView as its
main widget and on every frame we render the QWebView's main QWebPage
onto a QImage with image data coming from glReadPixels or its Direct3D
equivalent. We then push the resulting pixels back into
OpenGL/Direct3D so we get the HTML on screen. We also create synthetic
QMouseEvent objects and push them into the QWebPage so Javascript
click handlers also work. What's important to understand is that our
application is in charge of the mainloop, retrieving events etc. Qt
just requests HTML from the web server, renders it and runs
Javascript.

To make things more complicated, our application is actually a browser
plugin so we're not in complete control of the event loop either, the
browser pushes events into our wndproc. We allocate a QApplication
whenever the browser tells us "initialize your plugin" because we
visit a page with the correct <object> tag and delete it every time
the browser tells us "destroy your plugin" because the user navigates
away from our page.

Is it supported to create and delete QApplications like this multiple
times within the lifetime of a process? Should we do more than
deleting the QApplication and the other QObjects we allocate to
cleanup Qt's internal state? I'm asking because we see some strange
issues when navigating away and then coming back: sometimes Javascript
timers don't run, sometimes the loadFinished signal never comes (the
request to the web server gets done but Qt never reports that it got
the page).

Because we have our own event loop we don't want to block in
QApplication::exec() so instead we tried calling
QApplication::processEvents() every frame. With this Qt itself works
well but when running our plugin inside IE, Windows messages that IE
passes into our plugin seem to get lost inside Qt: we click on IE's
close button and IE doesn't close it just makes a sound (the "click
not accepted sound", the same one as when clicking a button in an
application which has a modal dialog open and therefore the click is
rejected). We think this is because when calling
QApplication::processEvents, Qt calls PeekMessage with PM_REMOVE in
qeventdispatcher_win.cpp and therefore eats the close message.

We looked at ActiveQt's sources and got some inspiration from
qaxserverbase.cpp which calls processEvents() once with the comment:
// If we created QApplication instance, ensure native event loop
starts properly by calling processEvents.
and calls sendPostedEvents() repeatedly in a message hook.

We tried to imitate this: call processEvents() once when initializing
and call sendPostedEvents() every frame. With this change we avoid the
PeekMessage call, IE closes correctly, and things seem to work, except
when we run a non browser client (used mostly for testing): timers
don't get triggered (neither Javascript setTimeout functions nor
regular QTimer C++ objects) unless we move the window; it seems that
by replacing processEvents() with sendPostedEvents() we crippled Qt's
event loop so now it loses WM_TIMER messages and only happens to get
them if we send some more messages by moving the window.

I tried to follow the mainloop's code in qeventdispatcher_win.cpp but
got lost as it's quite complicated. How should we integrate Qt's main
loop into ours? processEvents() makes IE not close, sendPostedEvents()
doesn't seem to be enough for running the whole event loop and getting
all messages.

Congratulations if you've read so far and huge thanks in advance for
any ideas you'll share!

Catalin



More information about the Interest mailing list