xcb: Don't connect() to event-dispatcher until we are sure we have one

QCoreApplication sets up the event dispatcher in the constructor, through
createEventDispatcher(), which is overridden in QGuiApplication to take
the platform-integration into account. The problem is that the platform
integration is created before the event dispatcher, so when we create the
QXcbConnection we are not guaranteed to have an event dispatcher yet.

This is not an issue when using xcb_poll_for_queued_event() in a thread,
but for the fallback case we connect to the event-dispatcher's awake()
and aboutToBlock() signals. To ensure that we do this only when we have
an event dispatcher we post a queued method invocation, that will be
processed as one of the first events once there is an event-dispatcher.

Change-Id: I623011af447b585884b84c7559737f134aab83e8
Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@digia.com>
Reviewed-by: Uli Schlachter <psychon@znc.in>
Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
This commit is contained in:
Tor Arne Vestbø 2013-09-30 10:45:28 +02:00 committed by The Qt Project
parent 99b3e68f20
commit 1256ed05b2
2 changed files with 23 additions and 14 deletions

View File

@ -290,16 +290,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
qFatal("QXcbConnection: Could not connect to display %s", m_displayName.constData());
m_reader = new QXcbEventReader(this);
connect(m_reader, SIGNAL(eventPending()), this, SLOT(processXcbEvents()), Qt::QueuedConnection);
connect(m_reader, SIGNAL(finished()), this, SLOT(processXcbEvents()));
if (!m_reader->startThread()) {
QSocketNotifier *notifier = new QSocketNotifier(xcb_get_file_descriptor(xcb_connection()), QSocketNotifier::Read, this);
connect(notifier, SIGNAL(activated(int)), this, SLOT(processXcbEvents()));
QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher;
connect(dispatcher, SIGNAL(aboutToBlock()), this, SLOT(processXcbEvents()));
connect(dispatcher, SIGNAL(awake()), this, SLOT(processXcbEvents()));
}
m_reader->start();
xcb_extension_t *extensions[] = {
&xcb_shm_id, &xcb_xfixes_id, &xcb_randr_id, &xcb_shape_id, &xcb_sync_id,
@ -977,14 +968,27 @@ QXcbEventReader::QXcbEventReader(QXcbConnection *connection)
#endif
}
bool QXcbEventReader::startThread()
void QXcbEventReader::start()
{
if (m_xcb_poll_for_queued_event) {
connect(this, SIGNAL(eventPending()), m_connection, SLOT(processXcbEvents()), Qt::QueuedConnection);
connect(this, SIGNAL(finished()), m_connection, SLOT(processXcbEvents()));
QThread::start();
return true;
} else {
// Must be done after we have an event-dispatcher. By posting a method invocation
// we are sure that by the time the method is called we have an event-dispatcher.
QMetaObject::invokeMethod(this, "registerForEvents", Qt::QueuedConnection);
}
}
return false;
void QXcbEventReader::registerForEvents()
{
QSocketNotifier *notifier = new QSocketNotifier(xcb_get_file_descriptor(m_connection->xcb_connection()), QSocketNotifier::Read, this);
connect(notifier, SIGNAL(activated(int)), m_connection, SLOT(processXcbEvents()));
QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher;
connect(dispatcher, SIGNAL(aboutToBlock()), m_connection, SLOT(processXcbEvents()));
connect(dispatcher, SIGNAL(awake()), m_connection, SLOT(processXcbEvents()));
}
void QXcbEventReader::run()

View File

@ -298,11 +298,14 @@ public:
QXcbEventArray *lock();
void unlock();
bool startThread();
void start();
signals:
void eventPending();
private slots:
void registerForEvents();
private:
void addEvent(xcb_generic_event_t *event);
@ -574,6 +577,8 @@ private:
QByteArray m_startupId;
QXcbSystemTrayTracker *m_systemTrayTracker;
friend class QXcbEventReader;
};
#define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display()))