diff options
author | Gatis Paeglis <gatis.paeglis@qt.io> | 2017-08-03 09:24:27 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2017-08-04 11:19:19 +0000 |
commit | 341bfcd1eaa9116c143e3b7d3219ef04c7b8a0cb (patch) | |
tree | ac81466643a74fe7b1a2de74099081d10d21143f /src/platformsupport | |
parent | b12fd1fa9d0b64e3cb66fa68c85392dbde8e175b (diff) |
glib dispatcher: ensure all window system events are flushed
... when QCoreApplication::processEvents() returns. This is the expected
behavior according to the documentation. Checked also the QUnixEventDispatcherQPA
dispatcher, which did work according to the documentation.
The sequence of events that causes the bad behavior:
1) XCB plugin sends a signals whenever there are new XCB events available
for processing. This signal is connected to QXcbConnection::processXcbEvents,
which will cause XCB events to be added to the QWindowSystemInterface (QWSI) event
queue.
2) When QCoreApplication::processEvents() is called, glib event dispatcher does
one iteration on all attached event sources. First it checks which sources are
ready, and after that starts dispatching events from each source that reported
to be ready.
3) In the case when there are no events in QWSI event queue, the source that handles
QWSI event dispatcing returns 'false'; If at the same iteration the source that
sends posted events (via QCoreApplication::sendPostedEvents()) has returned 'true'
and one of the posted events is to call QXcbConnection::processXcbEvents (due to
signal from step 1) then we get an assert in the following code:
QCoreApplication::processEvents();
Q_ASSERT(QWindowSystemInterface::windowSystemEventsQueued() == 0);
This happens because QXcbConnection::processXcbEvents has posted new events, but
they were not dispatched in this iteration. They would be dispatched in the next
iteration. Events being dispatched on subsequent iteration doesn't really matter
for Qt application, but is inconsistent from API point of view. If we were
populating QWSI queue from non-Gui thread, then it would be possible that
windowSystemEventsQueued() != 0, but that is not the case on XCB (don't know
about other platforms).
The issue could be fixed by always returning true from "check source" and then
simply dispatch 0 events at "dispatch" step if there isn't any in the queue. But
a better solution is to remove the event source all together. It is completely
unnecessary to have this indirection, when we can handle QWSI event dispatch
directly from Qt (like we do, for example, in QUnixEventDispatcherQPA and
QWinRTEventDispatcher). Not having Glib event source for QWSI events would have
also avoided issues that were fixed by fbb485d4f6985643b27da3cc6c5b5f960c32e74d.
Note, after this re-factoring QWindowSystemInterface::nonUserInputEventsQueued is
now unused, but I left it in as the API by itself is all right.
Task-number: QTBUG-62297
Change-Id: Ia245b835676bd87e63bf02b67036b42a3b1593cc
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/platformsupport')
-rw-r--r-- | src/platformsupport/eventdispatchers/qeventdispatcher_glib.cpp | 56 | ||||
-rw-r--r-- | src/platformsupport/eventdispatchers/qeventdispatcher_glib_p.h | 3 |
2 files changed, 2 insertions, 57 deletions
diff --git a/src/platformsupport/eventdispatchers/qeventdispatcher_glib.cpp b/src/platformsupport/eventdispatchers/qeventdispatcher_glib.cpp index dc4785071f..06f0aa6747 100644 --- a/src/platformsupport/eventdispatchers/qeventdispatcher_glib.cpp +++ b/src/platformsupport/eventdispatchers/qeventdispatcher_glib.cpp @@ -48,78 +48,26 @@ QT_BEGIN_NAMESPACE -struct GUserEventSource -{ - GSource source; - QPAEventDispatcherGlib *q; -}; - -static gboolean userEventSourcePrepare(GSource *source, gint *timeout) -{ - Q_UNUSED(timeout) - GUserEventSource *userEventSource = reinterpret_cast<GUserEventSource *>(source); - QPAEventDispatcherGlib *dispatcher = userEventSource->q; - if (dispatcher->m_flags & QEventLoop::ExcludeUserInputEvents) - return QWindowSystemInterface::nonUserInputEventsQueued(); - else - return QWindowSystemInterface::windowSystemEventsQueued() > 0; -} - -static gboolean userEventSourceCheck(GSource *source) -{ - return userEventSourcePrepare(source, 0); -} - -static gboolean userEventSourceDispatch(GSource *source, GSourceFunc, gpointer) -{ - GUserEventSource *userEventSource = reinterpret_cast<GUserEventSource *>(source); - QPAEventDispatcherGlib *dispatcher = userEventSource->q; - QWindowSystemInterface::sendWindowSystemEvents(dispatcher->m_flags); - return true; -} - -static GSourceFuncs userEventSourceFuncs = { - userEventSourcePrepare, - userEventSourceCheck, - userEventSourceDispatch, - NULL, - NULL, - NULL -}; - QPAEventDispatcherGlibPrivate::QPAEventDispatcherGlibPrivate(GMainContext *context) : QEventDispatcherGlibPrivate(context) { - Q_Q(QPAEventDispatcherGlib); - userEventSource = reinterpret_cast<GUserEventSource *>(g_source_new(&userEventSourceFuncs, - sizeof(GUserEventSource))); - userEventSource->q = q; - g_source_set_can_recurse(&userEventSource->source, true); - g_source_attach(&userEventSource->source, mainContext); } - QPAEventDispatcherGlib::QPAEventDispatcherGlib(QObject *parent) : QEventDispatcherGlib(*new QPAEventDispatcherGlibPrivate, parent) , m_flags(QEventLoop::AllEvents) { - Q_D(QPAEventDispatcherGlib); - d->userEventSource->q = this; } QPAEventDispatcherGlib::~QPAEventDispatcherGlib() { - Q_D(QPAEventDispatcherGlib); - - g_source_destroy(&d->userEventSource->source); - g_source_unref(&d->userEventSource->source); - d->userEventSource = 0; } bool QPAEventDispatcherGlib::processEvents(QEventLoop::ProcessEventsFlags flags) { m_flags = flags; - return QEventDispatcherGlib::processEvents(m_flags); + const bool didSendEvents = QEventDispatcherGlib::processEvents(m_flags); + return QWindowSystemInterface::sendWindowSystemEvents(m_flags) || didSendEvents; } QT_END_NAMESPACE diff --git a/src/platformsupport/eventdispatchers/qeventdispatcher_glib_p.h b/src/platformsupport/eventdispatchers/qeventdispatcher_glib_p.h index 6d148753bf..bed2532856 100644 --- a/src/platformsupport/eventdispatchers/qeventdispatcher_glib_p.h +++ b/src/platformsupport/eventdispatchers/qeventdispatcher_glib_p.h @@ -71,14 +71,11 @@ public: QEventLoop::ProcessEventsFlags m_flags; }; -struct GUserEventSource; - class QPAEventDispatcherGlibPrivate : public QEventDispatcherGlibPrivate { Q_DECLARE_PUBLIC(QPAEventDispatcherGlib) public: QPAEventDispatcherGlibPrivate(GMainContext *context = 0); - GUserEventSource *userEventSource; }; |