Pull in set of upstream Qt 5.5 fixes and improvements for XCB screen handling rebased to 5.4

This commit is contained in:
Dan Vrátil 2015-03-25 22:36:11 +01:00
parent 4aed2cfe1e
commit bcc8b147be
10 changed files with 1912 additions and 606 deletions

View File

@ -0,0 +1,313 @@
commit 9b4fbe85d2e00c625c3d4abd975faf555000f685
Author: Giulio Camuffo <giuliocamuffo@gmail.com>
Date: Sun Aug 31 16:16:53 2014 +0300
Add a function for QPA plugins to explicitly destroy QScreens
Previously QPlatformScreen was automatically deleting its QScreen
in ~QPlatformScreen(). That means that we cannot use QScreen's
methods when the screen is being removed, because doing so would
call virtual methods of QPlatformScreen. By that point the
QPlatformScreen subclass object does not exist anymore, and we
call the default implementation instead of the subclassed one, or
get a crash for the pure virtual methods. This happens for example
when removing a screen which contains a QWindow with some QML item
using QQuickScreenAttached.
This patch adds a QPlatformIntegration::destroyScreen() function,
which deletes the QScreen and later the QPlatformScreen.
~QPlatformScreen will still delete the QScreen if it was not deleted
with destroyScreen(), so code not ported to the new approach
will continue to work as before, with only a warning added.
Task-number: QTBUG-41141
Change-Id: Ie4a03dee08ceb4c3e94a81875411f6f723273fe1
Reviewed-by: Jørgen Lind <jorgen.lind@theqtcompany.com>
Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp
index 39b031e..93b1359 100644
--- a/src/gui/kernel/qplatformintegration.cpp
+++ b/src/gui/kernel/qplatformintegration.cpp
@@ -429,7 +429,7 @@ QList<int> QPlatformIntegration::possibleKeys(const QKeyEvent *) const
This adds the screen to QGuiApplication::screens(), and emits the
QGuiApplication::screenAdded() signal.
- The screen is automatically removed when the QPlatformScreen is destroyed.
+ The screen should be deleted by calling QPlatformIntegration::destroyScreen().
*/
void QPlatformIntegration::screenAdded(QPlatformScreen *ps)
{
@@ -439,6 +439,22 @@ void QPlatformIntegration::screenAdded(QPlatformScreen *ps)
emit qGuiApp->screenAdded(screen);
}
+/*!
+ Should be called by the implementation whenever a screen is removed.
+
+ This removes the screen from QGuiApplication::screens(), and deletes it.
+
+ Failing to call this and manually deleting the QPlatformScreen instead may
+ lead to a crash due to a pure virtual call.
+*/
+void QPlatformIntegration::destroyScreen(QPlatformScreen *screen)
+{
+ QGuiApplicationPrivate::screen_list.removeOne(screen->d_func()->screen);
+ delete screen->d_func()->screen;
+ screen->d_func()->screen = Q_NULLPTR;
+ delete screen;
+}
+
QStringList QPlatformIntegration::themeNames() const
{
return QStringList();
diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h
index d510240..9b7e2df 100644
--- a/src/gui/kernel/qplatformintegration.h
+++ b/src/gui/kernel/qplatformintegration.h
@@ -170,6 +170,7 @@ public:
protected:
void screenAdded(QPlatformScreen *screen);
+ void destroyScreen(QPlatformScreen *screen);
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformscreen.cpp b/src/gui/kernel/qplatformscreen.cpp
index 71710d1..fa6d785 100644
--- a/src/gui/kernel/qplatformscreen.cpp
+++ b/src/gui/kernel/qplatformscreen.cpp
@@ -52,9 +52,11 @@ QPlatformScreen::QPlatformScreen()
QPlatformScreen::~QPlatformScreen()
{
Q_D(QPlatformScreen);
-
- QGuiApplicationPrivate::screen_list.removeOne(d->screen);
- delete d->screen;
+ if (d->screen) {
+ qWarning("Manually deleting a QPlatformScreen. Call QPlatformIntegration::destroyScreen instead.");
+ QGuiApplicationPrivate::screen_list.removeOne(d->screen);
+ delete d->screen;
+ }
}
/*!
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index 72bd096..180cb23 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -337,7 +337,7 @@ QCocoaIntegration::~QCocoaIntegration()
// Delete screens in reverse order to avoid crash in case of multiple screens
while (!mScreens.isEmpty()) {
- delete mScreens.takeLast();
+ destroyScreen(mScreens.takeLast());
}
clearToolbars();
@@ -397,7 +397,7 @@ void QCocoaIntegration::updateScreens()
// Now the leftovers in remainingScreens are no longer current, so we can delete them.
foreach (QCocoaScreen* screen, remainingScreens) {
mScreens.removeOne(screen);
- delete screen;
+ destroyScreen(screen);
}
// All screens in mScreens are siblings, because we ignored the mirrors.
foreach (QCocoaScreen* screen, mScreens)
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index 461f160..ff4b753 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -120,7 +120,7 @@ QIOSIntegration::~QIOSIntegration()
m_inputContext = 0;
foreach (QScreen *screen, QGuiApplication::screens())
- delete screen->handle();
+ destroyScreen(screen->handle());
delete m_platformServices;
m_platformServices = 0;
diff --git a/src/plugins/platforms/kms/qkmsintegration.cpp b/src/plugins/platforms/kms/qkmsintegration.cpp
index d94d7d9..5ad58ba 100644
--- a/src/plugins/platforms/kms/qkmsintegration.cpp
+++ b/src/plugins/platforms/kms/qkmsintegration.cpp
@@ -74,7 +74,7 @@ QKmsIntegration::~QKmsIntegration()
delete device;
}
foreach (QPlatformScreen *screen, m_screens) {
- delete screen;
+ destroyScreen(screen);
}
delete m_fontDatabase;
delete m_vtHandler;
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
index 777da98..4e83656 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
+++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
@@ -57,7 +57,7 @@ QLinuxFbIntegration::QLinuxFbIntegration(const QStringList &paramList)
QLinuxFbIntegration::~QLinuxFbIntegration()
{
- delete m_primaryScreen;
+ destroyScreen(m_primaryScreen);
}
void QLinuxFbIntegration::initialize()
diff --git a/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp b/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp
index 0b12e62..3fbed1e 100644
--- a/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp
+++ b/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp
@@ -60,7 +60,7 @@ QMinimalEglIntegration::QMinimalEglIntegration()
QMinimalEglIntegration::~QMinimalEglIntegration()
{
- delete mScreen;
+ destroyScreen(mScreen);
}
bool QMinimalEglIntegration::hasCapability(QPlatformIntegration::Capability cap) const
diff --git a/src/plugins/platforms/openwfd/qopenwfdintegration.cpp b/src/plugins/platforms/openwfd/qopenwfdintegration.cpp
index 1e29fcc..26bdd14 100644
--- a/src/plugins/platforms/openwfd/qopenwfdintegration.cpp
+++ b/src/plugins/platforms/openwfd/qopenwfdintegration.cpp
@@ -133,3 +133,8 @@ void QOpenWFDIntegration::addScreen(QOpenWFDScreen *screen)
{
screenAdded(screen);
}
+
+void QOpenWFDIntegration::destroyScreen(QOpenWFDScreen *screen)
+{
+ QPlatformIntegration::destroyScreen(screen);
+}
diff --git a/src/plugins/platforms/openwfd/qopenwfdintegration.h b/src/plugins/platforms/openwfd/qopenwfdintegration.h
index 6c086b7..9243205 100644
--- a/src/plugins/platforms/openwfd/qopenwfdintegration.h
+++ b/src/plugins/platforms/openwfd/qopenwfdintegration.h
@@ -63,6 +63,7 @@ public:
QPlatformPrinterSupport *printerSupport() const;
void addScreen(QOpenWFDScreen *screen);
+ void destroyScreen(QOpenWFDScreen *screen);
private:
QList<QPlatformScreen *> mScreens;
QList<QOpenWFDDevice *>mDevices;
diff --git a/src/plugins/platforms/openwfd/qopenwfdport.cpp b/src/plugins/platforms/openwfd/qopenwfdport.cpp
index 0bdc6b2..b643644 100644
--- a/src/plugins/platforms/openwfd/qopenwfdport.cpp
+++ b/src/plugins/platforms/openwfd/qopenwfdport.cpp
@@ -140,7 +140,7 @@ void QOpenWFDPort::detach()
mAttached = false;
mOn = false;
- delete mScreen;
+ mDevice->integration()->destroyScreen(mScreen);
wfdDestroyPipeline(mDevice->handle(),mPipeline);
mPipelineId = WFD_INVALID_PIPELINE_ID;
diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp
index 34b79b6..d47da01 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.cpp
+++ b/src/plugins/platforms/qnx/qqnxintegration.cpp
@@ -554,7 +554,7 @@ void QQnxIntegration::removeDisplay(QQnxScreen *screen)
Q_CHECK_PTR(screen);
Q_ASSERT(m_screens.contains(screen));
m_screens.removeAll(screen);
- screen->deleteLater();
+ destroyScreen(screen);
}
void QQnxIntegration::destroyDisplays()
diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h
index d1617ea..7fb37bc 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.h
+++ b/src/plugins/platforms/windows/qwindowsintegration.h
@@ -94,6 +94,7 @@ public:
static QWindowsIntegration *instance();
inline void emitScreenAdded(QPlatformScreen *s) { screenAdded(s); }
+ inline void emitDestroyScreen(QPlatformScreen *s) { destroyScreen(s); }
unsigned options() const;
diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp
index fd57d9e..79219e3 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.cpp
+++ b/src/plugins/platforms/windows/qwindowsscreen.cpp
@@ -462,7 +462,7 @@ void QWindowsScreenManager::removeScreen(int index)
if (movedWindowCount)
QWindowSystemInterface::flushWindowSystemEvents();
}
- delete m_screens.takeAt(index);
+ QWindowsIntegration::instance()->emitDestroyScreen(m_screens.takeAt(index));
}
/*!
@@ -497,4 +497,11 @@ bool QWindowsScreenManager::handleScreenChanges()
return true;
}
+void QWindowsScreenManager::clearScreens()
+{
+ // Delete screens in reverse order to avoid crash in case of multiple screens
+ while (!m_screens.isEmpty())
+ QWindowsIntegration::instance()->emitDestroyScreen(m_screens.takeLast());
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h
index aa14083..924912d 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.h
+++ b/src/plugins/platforms/windows/qwindowsscreen.h
@@ -127,11 +127,7 @@ public:
QWindowsScreenManager();
- inline void clearScreens() {
- // Delete screens in reverse order to avoid crash in case of multiple screens
- while (!m_screens.isEmpty())
- delete m_screens.takeLast();
- }
+ void clearScreens();
bool handleScreenChanges();
bool handleDisplayChange(WPARAM wParam, LPARAM lParam);
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 5510c3b..ae59de5 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -279,11 +279,12 @@ void QXcbConnection::updateScreens()
++xcbScreenNumber;
} // for each xcb screen
+ QXcbIntegration *integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration());
// Now activeScreens is the complete set of screens which are active at this time.
// Delete any existing screens which are not in activeScreens
for (int i = m_screens.count() - 1; i >= 0; --i) {
if (!activeScreens.contains(m_screens[i])) {
- delete m_screens[i];
+ integration->destroyScreen(m_screens.at(i));
m_screens.removeAt(i);
}
}
@@ -300,7 +301,7 @@ void QXcbConnection::updateScreens()
// Now that they are in the right order, emit the added signals for new screens only
foreach (QXcbScreen* screen, m_screens)
if (newScreens.contains(screen))
- ((QXcbIntegration*)QGuiApplicationPrivate::platformIntegration())->screenAdded(screen);
+ integration->screenAdded(screen);
}
QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, const char *displayName)
@@ -431,9 +432,10 @@ QXcbConnection::~QXcbConnection()
delete m_reader;
+ QXcbIntegration *integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration());
// Delete screens in reverse order to avoid crash in case of multiple screens
while (!m_screens.isEmpty())
- delete m_screens.takeLast();
+ integration->destroyScreen(m_screens.takeLast());
#ifdef XCB_USE_EGL
if (m_has_egl)

View File

@ -0,0 +1,201 @@
commit df39295f23c7d9ead8481a95b9c78caaff1e8bc8
Author: Sandro Mani <manisandro@gmail.com>
Date: Mon Feb 16 10:22:14 2015 +0100
Have XCB/Windows platform integration classes keep their own instance pointer
Through the chain of code called by QPlatformIntegrationFactory::create, there
are cases where QGuiApplicationPrivate::platform_integration is accessed
(typically through QGuiApplicationPrivate::platformIntegration()) before the call
to QPlatformIntegrationFactory::create has returned.
Change-Id: I7805b72be5b56aed5cb8ce30cb908743c9b1f91b
Task-number: QTBUG-44388
Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@theqtcompany.com>
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index 58d6758..d06f605 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -235,9 +235,12 @@ QWindowsIntegrationPrivate::~QWindowsIntegrationPrivate()
delete m_fontDatabase;
}
+QWindowsIntegration *QWindowsIntegration::m_instance = Q_NULLPTR;
+
QWindowsIntegration::QWindowsIntegration(const QStringList &paramList) :
d(new QWindowsIntegrationPrivate(paramList))
{
+ m_instance = this;
#ifndef QT_NO_CLIPBOARD
d->m_clipboard.registerViewer();
#endif
@@ -246,6 +249,7 @@ QWindowsIntegration::QWindowsIntegration(const QStringList &paramList) :
QWindowsIntegration::~QWindowsIntegration()
{
+ m_instance = Q_NULLPTR;
}
void QWindowsIntegration::initialize()
@@ -540,11 +544,6 @@ QPlatformAccessibility *QWindowsIntegration::accessibility() const
}
#endif
-QWindowsIntegration *QWindowsIntegration::instance()
-{
- return static_cast<QWindowsIntegration *>(QGuiApplicationPrivate::platformIntegration());
-}
-
unsigned QWindowsIntegration::options() const
{
return d->m_options;
diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h
index 7fb37bc..ff26342 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.h
+++ b/src/plugins/platforms/windows/qwindowsintegration.h
@@ -91,7 +91,7 @@ public:
Qt::KeyboardModifiers queryKeyboardModifiers() const Q_DECL_OVERRIDE;
QList<int> possibleKeys(const QKeyEvent *e) const Q_DECL_OVERRIDE;
- static QWindowsIntegration *instance();
+ static QWindowsIntegration *instance() { return m_instance; }
inline void emitScreenAdded(QPlatformScreen *s) { screenAdded(s); }
inline void emitDestroyScreen(QPlatformScreen *s) { destroyScreen(s); }
@@ -104,6 +104,8 @@ public:
private:
QScopedPointer<QWindowsIntegrationPrivate> d;
+
+ static QWindowsIntegration *m_instance;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index ae59de5..0091736 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -279,7 +279,7 @@ void QXcbConnection::updateScreens()
++xcbScreenNumber;
} // for each xcb screen
- QXcbIntegration *integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ QXcbIntegration *integration = QXcbIntegration::instance();
// Now activeScreens is the complete set of screens which are active at this time.
// Delete any existing screens which are not in activeScreens
for (int i = m_screens.count() - 1; i >= 0; --i) {
@@ -432,7 +432,7 @@ QXcbConnection::~QXcbConnection()
delete m_reader;
- QXcbIntegration *integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ QXcbIntegration *integration = QXcbIntegration::instance();
// Delete screens in reverse order to avoid crash in case of multiple screens
while (!m_screens.isEmpty())
integration->destroyScreen(m_screens.takeLast());
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index f0c4a7f..050a9be 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -118,11 +118,15 @@ static bool runningUnderDebugger()
#endif
}
+QXcbIntegration *QXcbIntegration::m_instance = Q_NULLPTR;
+
QXcbIntegration::QXcbIntegration(const QStringList &parameters, int &argc, char **argv)
: m_services(new QGenericUnixServices)
, m_instanceName(0)
, m_canGrab(true)
{
+ m_instance = this;
+
qRegisterMetaType<QXcbWindow*>();
#ifdef XCB_USE_XLIB
XInitThreads();
@@ -187,6 +191,7 @@ QXcbIntegration::QXcbIntegration(const QStringList &parameters, int &argc, char
QXcbIntegration::~QXcbIntegration()
{
qDeleteAll(m_connections);
+ m_instance = Q_NULLPTR;
}
QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const
diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h
index db6ad54..ffe49e7 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.h
+++ b/src/plugins/platforms/xcb/qxcbintegration.h
@@ -99,6 +99,9 @@ public:
#endif
void sync();
+
+ static QXcbIntegration *instance() { return m_instance; }
+
private:
QList<QXcbConnection *> m_connections;
@@ -118,6 +121,8 @@ private:
mutable QByteArray m_wmClass;
const char *m_instanceName;
bool m_canGrab;
+
+ static QXcbIntegration *m_instance;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
index 31dedd4..c9aaada 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
@@ -359,7 +359,7 @@ void *QXcbNativeInterface::getTimestamp(const QXcbScreen *screen)
void *QXcbNativeInterface::startupId()
{
- QXcbIntegration* integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ QXcbIntegration* integration = QXcbIntegration::instance();
QXcbConnection *defaultConnection = integration->defaultConnection();
if (defaultConnection)
return reinterpret_cast<void *>(const_cast<char *>(defaultConnection->startupId().constData()));
@@ -368,7 +368,7 @@ void *QXcbNativeInterface::startupId()
void *QXcbNativeInterface::x11Screen()
{
- QXcbIntegration *integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ QXcbIntegration *integration = QXcbIntegration::instance();
QXcbConnection *defaultConnection = integration->defaultConnection();
if (defaultConnection)
return reinterpret_cast<void *>(defaultConnection->primaryScreenNumber());
@@ -377,7 +377,7 @@ void *QXcbNativeInterface::x11Screen()
void *QXcbNativeInterface::rootWindow()
{
- QXcbIntegration *integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ QXcbIntegration *integration = QXcbIntegration::instance();
QXcbConnection *defaultConnection = integration->defaultConnection();
if (defaultConnection)
return reinterpret_cast<void *>(defaultConnection->rootWindow());
@@ -397,7 +397,7 @@ void QXcbNativeInterface::setAppUserTime(QScreen* screen, xcb_timestamp_t time)
void QXcbNativeInterface::setStartupId(const char *data)
{
QByteArray startupId(data);
- QXcbIntegration *integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ QXcbIntegration *integration = QXcbIntegration::instance();
QXcbConnection *defaultConnection = integration->defaultConnection();
if (defaultConnection)
defaultConnection->setStartupId(startupId);
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 0094278..7e85600 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -489,7 +489,7 @@ void QXcbWindow::create()
m_syncValue.hi = 0;
m_syncValue.lo = 0;
- const QByteArray wmClass = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration())->wmClass();
+ const QByteArray wmClass = QXcbIntegration::instance()->wmClass();
if (!wmClass.isEmpty()) {
Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE,
m_window, atom(QXcbAtom::WM_CLASS),

View File

@ -0,0 +1,190 @@
commit 52f5e50f11a3ba82e32dc2efc656e4021a3fa4f5
Author: Sandro Mani <manisandro@gmail.com>
Date: Mon Feb 2 17:14:40 2015 +0100
Ensure QGuiApplicationPrivate::screen_list is correctly populated
Ensure QGuiApplicationPrivate::screen_list always contains at least one
screen, and that the first item (returned by QGuiApplication::primaryScreen)
is always the current primary screen
Task-number: QTBUG-42985
Change-Id: I08b880b3e94387f28230ed5fc738bceea943bad3
Reviewed-by: Jørgen Lind <jorgen.lind@theqtcompany.com>
diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp
index 93b1359..13f2880 100644
--- a/src/gui/kernel/qplatformintegration.cpp
+++ b/src/gui/kernel/qplatformintegration.cpp
@@ -431,11 +431,15 @@ QList<int> QPlatformIntegration::possibleKeys(const QKeyEvent *) const
The screen should be deleted by calling QPlatformIntegration::destroyScreen().
*/
-void QPlatformIntegration::screenAdded(QPlatformScreen *ps)
+void QPlatformIntegration::screenAdded(QPlatformScreen *ps, bool isPrimary)
{
QScreen *screen = new QScreen(ps);
ps->d_func()->screen = screen;
- QGuiApplicationPrivate::screen_list << screen;
+ if (isPrimary) {
+ QGuiApplicationPrivate::screen_list.prepend(screen);
+ } else {
+ QGuiApplicationPrivate::screen_list.append(screen);
+ }
emit qGuiApp->screenAdded(screen);
}
diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h
index 9b7e2df..067d8d9 100644
--- a/src/gui/kernel/qplatformintegration.h
+++ b/src/gui/kernel/qplatformintegration.h
@@ -169,7 +169,7 @@ public:
#endif
protected:
- void screenAdded(QPlatformScreen *screen);
+ void screenAdded(QPlatformScreen *screen, bool isPrimary = false);
void destroyScreen(QPlatformScreen *screen);
};
diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h
index ff26342..bfde2bd 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.h
+++ b/src/plugins/platforms/windows/qwindowsintegration.h
@@ -93,7 +93,7 @@ public:
static QWindowsIntegration *instance() { return m_instance; }
- inline void emitScreenAdded(QPlatformScreen *s) { screenAdded(s); }
+ inline void emitScreenAdded(QPlatformScreen *s, bool isPrimary = false) { screenAdded(s, isPrimary); }
inline void emitDestroyScreen(QPlatformScreen *s) { destroyScreen(s); }
unsigned options() const;
diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp
index 79219e3..a401175 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.cpp
+++ b/src/plugins/platforms/windows/qwindowsscreen.cpp
@@ -482,7 +482,8 @@ bool QWindowsScreenManager::handleScreenChanges()
} else {
QWindowsScreen *newScreen = new QWindowsScreen(newData);
m_screens.push_back(newScreen);
- QWindowsIntegration::instance()->emitScreenAdded(newScreen);
+ QWindowsIntegration::instance()->emitScreenAdded(newScreen,
+ newData.flags & QWindowsScreenData::PrimaryScreen);
qCDebug(lcQpaWindows) << "New Monitor: " << newData;
} // exists
} // for new screens.
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 0091736..e416865 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -182,9 +182,8 @@ QXcbScreen* QXcbConnection::findOrCreateScreen(QList<QXcbScreen *>& newScreens,
void QXcbConnection::updateScreens()
{
xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup);
- int screenNumber = 0; // index of this QScreen in QGuiApplication::screens()
int xcbScreenNumber = 0; // screen number in the xcb sense
- QSet<QXcbScreen *> activeScreens;
+ QList<QXcbScreen *> activeScreens;
QList<QXcbScreen *> newScreens;
QXcbScreen* primaryScreen = NULL;
while (it.rem) {
@@ -195,6 +194,7 @@ void QXcbConnection::updateScreens()
xcb_screen_t *xcbScreen = it.data;
QList<QPlatformScreen *> siblings;
int outputCount = 0;
+ int connectedOutputCount = 0;
if (has_randr_extension) {
xcb_generic_error_t *error = NULL;
xcb_randr_get_output_primary_cookie_t primaryCookie =
@@ -239,7 +239,7 @@ void QXcbConnection::updateScreens()
QXcbScreen *screen = findOrCreateScreen(newScreens, xcbScreenNumber, xcbScreen, output);
siblings << screen;
activeScreens << screen;
- ++screenNumber;
+ ++connectedOutputCount;
// There can be multiple outputs per screen, use either
// the first or an exact match. An exact match isn't
// always available if primary->output is XCB_NONE
@@ -262,7 +262,7 @@ void QXcbConnection::updateScreens()
}
// If there's no randr extension, or there was some error above, or the screen
// doesn't have outputs for some other reason (e.g. on VNC or ssh -X), just assume there is one screen.
- if (outputCount == 0) {
+ if (connectedOutputCount == 0) {
#ifdef Q_XCB_DEBUG
qDebug("Found a screen with zero outputs");
#endif
@@ -271,7 +271,6 @@ void QXcbConnection::updateScreens()
activeScreens << screen;
if (!primaryScreen)
primaryScreen = screen;
- ++screenNumber;
}
foreach (QPlatformScreen* s, siblings)
((QXcbScreen*)s)->setVirtualSiblings(siblings);
@@ -280,28 +279,50 @@ void QXcbConnection::updateScreens()
} // for each xcb screen
QXcbIntegration *integration = QXcbIntegration::instance();
- // Now activeScreens is the complete set of screens which are active at this time.
- // Delete any existing screens which are not in activeScreens
+
+ // Rebuild screen list, ensuring primary screen is always in front,
+ // both in the QXcbConnection::m_screens list as well as in the
+ // QGuiApplicationPrivate::screen_list list, which gets updated via
+ // - screen added: integration->screenAdded()
+ // - screen removed: integration->destroyScreen
+
+ // Gather screens to delete
+ QList<QXcbScreen*> screensToDelete;
for (int i = m_screens.count() - 1; i >= 0; --i) {
if (!activeScreens.contains(m_screens[i])) {
- integration->destroyScreen(m_screens.at(i));
- m_screens.removeAt(i);
+ screensToDelete.append(m_screens.takeAt(i));
}
}
- // Add any new screens, and make sure the primary screen comes first
- // since it is used by QGuiApplication::primaryScreen()
+ // If there is a new primary screen, add that one first
+ if (newScreens.contains(primaryScreen)) {
+ newScreens.removeOne(primaryScreen);
+ m_screens.prepend(primaryScreen);
+ integration->screenAdded(primaryScreen, true);
+ }
+
+ // Add the remaining new screens
foreach (QXcbScreen* screen, newScreens) {
- if (screen == primaryScreen)
- m_screens.prepend(screen);
- else
- m_screens.append(screen);
+ m_screens.append(screen);
+ integration->screenAdded(screen);
}
- // Now that they are in the right order, emit the added signals for new screens only
- foreach (QXcbScreen* screen, m_screens)
- if (newScreens.contains(screen))
- integration->screenAdded(screen);
+ // Delete the old screens, now that the new ones were added
+ // and we are sure that there is at least one screen available
+ foreach (QXcbScreen* screen, screensToDelete) {
+ integration->destroyScreen(screen);
+ }
+
+ // Ensure that the primary screen is first in m_screens too
+ // (in case the assignment of primary was the only change,
+ // without adding or removing screens)
+ if (primaryScreen) {
+ Q_ASSERT(!m_screens.isEmpty());
+ if (m_screens.first() != primaryScreen) {
+ m_screens.removeOne(primaryScreen);
+ m_screens.prepend(primaryScreen);
+ }
+ }
}
QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, const char *displayName)

View File

@ -0,0 +1,250 @@
commit bbdef3ca98ba78a829dc725ba67fe6d466e20f9c
Author: Shawn Rutledge <shawn.rutledge@digia.com>
Date: Mon Feb 23 10:30:26 2015 +0100
xcb: add qt.qpa.screen logging category
Some existing debug output required recompiling with Q_XCB_DEBUG.
Being able to enable this debugging in the field will help with
troubleshooting any remaining screen management issues.
Change-Id: Ie67b0009d4b00b0d39fde0fb4d8d54fcf89d6693
Reviewed-by: Sandro Mani <manisandro@gmail.com>
Reviewed-by: Laszlo Agocs <laszlo.agocs@theqtcompany.com>
Reviewed-by: Jørgen Lind <jorgen.lind@theqtcompany.com>
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index e416865..a8c1943 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -86,6 +86,7 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQpaXInput, "qt.qpa.input")
Q_LOGGING_CATEGORY(lcQpaXInputDevices, "qt.qpa.input.devices")
+Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen")
#ifdef XCB_USE_XLIB
static const char * const xcbConnectionErrors[] = {
@@ -224,15 +225,11 @@ void QXcbConnection::updateScreens()
if (output == NULL)
continue;
-#ifdef Q_XCB_DEBUG
- QString outputName = QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output),
- xcb_randr_get_output_info_name_length(output));
-#endif
if (output->crtc == XCB_NONE) {
-#ifdef Q_XCB_DEBUG
- qDebug("Screen output %s is not connected", qPrintable(outputName));
-#endif
+ qCDebug(lcQpaScreen, "output %s is not connected", qPrintable(
+ QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output),
+ xcb_randr_get_output_info_name_length(output))));
continue;
}
@@ -248,9 +245,6 @@ void QXcbConnection::updateScreens()
if (!primaryScreen || (primary && outputs[i] == primary->output)) {
primaryScreen = screen;
siblings.prepend(siblings.takeLast());
-#ifdef Q_XCB_DEBUG
- qDebug("Primary output is %d: %s", primary->output, qPrintable(outputName));
-#endif
}
}
free(output);
@@ -263,9 +257,7 @@ void QXcbConnection::updateScreens()
// If there's no randr extension, or there was some error above, or the screen
// doesn't have outputs for some other reason (e.g. on VNC or ssh -X), just assume there is one screen.
if (connectedOutputCount == 0) {
-#ifdef Q_XCB_DEBUG
- qDebug("Found a screen with zero outputs");
-#endif
+ qCDebug(lcQpaScreen, "found a screen with zero outputs");
QXcbScreen *screen = findOrCreateScreen(newScreens, xcbScreenNumber, xcbScreen);
siblings << screen;
activeScreens << screen;
@@ -298,18 +290,21 @@ void QXcbConnection::updateScreens()
if (newScreens.contains(primaryScreen)) {
newScreens.removeOne(primaryScreen);
m_screens.prepend(primaryScreen);
+ qCDebug(lcQpaScreen) << "adding as primary" << primaryScreen;
integration->screenAdded(primaryScreen, true);
}
// Add the remaining new screens
foreach (QXcbScreen* screen, newScreens) {
m_screens.append(screen);
+ qCDebug(lcQpaScreen) << "adding" << screen;
integration->screenAdded(screen);
}
// Delete the old screens, now that the new ones were added
// and we are sure that there is at least one screen available
foreach (QXcbScreen* screen, screensToDelete) {
+ qCDebug(lcQpaScreen) << "removing" << screen;
integration->destroyScreen(screen);
}
@@ -323,6 +318,9 @@ void QXcbConnection::updateScreens()
m_screens.prepend(primaryScreen);
}
}
+
+ if (!m_screens.isEmpty())
+ qCDebug(lcQpaScreen) << "primary output is" << m_screens.first()->name();
}
QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, const char *displayName)
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 7286b6b..6e7e87d 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -76,6 +76,7 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcQpaXInput)
Q_DECLARE_LOGGING_CATEGORY(lcQpaXInputDevices)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen)
class QXcbScreen;
class QXcbWindow;
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index 050a9be..0b9fbbe 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -178,9 +178,7 @@ QXcbIntegration::QXcbIntegration(const QStringList &parameters, int &argc, char
m_connections << new QXcbConnection(m_nativeInterface.data(), m_canGrab, displayName);
for (int i = 0; i < parameters.size() - 1; i += 2) {
-#ifdef Q_XCB_DEBUG
- qDebug() << "QXcbIntegration: Connecting to additional display: " << parameters.at(i) << parameters.at(i+1);
-#endif
+ qCDebug(lcQpaScreen) << "connecting to additional display: " << parameters.at(i) << parameters.at(i+1);
QString display = parameters.at(i) + ':' + parameters.at(i+1);
m_connections << new QXcbConnection(m_nativeInterface.data(), display.toLatin1().constData());
}
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 7136455..2aebb84 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -93,25 +93,6 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr,
if (dpr_scaling_enabled)
m_noFontHinting = true;
-#ifdef Q_XCB_DEBUG
- qDebug();
- qDebug("Screen output %s of xcb screen %d:", m_outputName.toUtf8().constData(), m_number);
- qDebug(" width..........: %lf", m_sizeMillimeters.width());
- qDebug(" height.........: %lf", m_sizeMillimeters.height());
- qDebug(" geometry.......: %d x %d +%d +%d", m_geometry.width(), m_geometry.height(), m_geometry.x(), m_geometry.y());
- qDebug(" virtual width..: %lf", m_virtualSizeMillimeters.width());
- qDebug(" virtual height.: %lf", m_virtualSizeMillimeters.height());
- qDebug(" virtual geom...: %d x %d", m_virtualSize.width(), m_virtualSize.height());
- qDebug(" avail virt geom: %d x %d +%d +%d", m_availableGeometry.width(), m_availableGeometry.height(), m_availableGeometry.x(), m_availableGeometry.y());
- qDebug(" orientation....: %d", m_orientation);
- qDebug(" pixel ratio....: %d", m_devicePixelRatio);
- qDebug(" depth..........: %d", screen()->root_depth);
- qDebug(" white pixel....: %x", screen()->white_pixel);
- qDebug(" black pixel....: %x", screen()->black_pixel);
- qDebug(" refresh rate...: %d", m_refreshRate);
- qDebug(" root ID........: %x", screen()->root);
-#endif
-
QScopedPointer<xcb_get_window_attributes_reply_t, QScopedPointerPodDeleter> rootAttribs(
xcb_get_window_attributes_reply(xcb_connection(),
xcb_get_window_attributes_unchecked(xcb_connection(), screen()->root), NULL));
@@ -146,10 +127,6 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr,
atom(QXcbAtom::UTF8_STRING), 0, 1024), NULL);
if (windowManagerReply && windowManagerReply->format == 8 && windowManagerReply->type == atom(QXcbAtom::UTF8_STRING)) {
m_windowManagerName = QString::fromUtf8((const char *)xcb_get_property_value(windowManagerReply), xcb_get_property_value_length(windowManagerReply));
-#ifdef Q_XCB_DEBUG
- qDebug(" window manager.: %s", qPrintable(m_windowManagerName));
- qDebug();
-#endif
}
free(windowManagerReply);
@@ -702,4 +679,48 @@ QXcbXSettings *QXcbScreen::xSettings() const
}
return m_xSettings;
}
+
+static inline void formatRect(QDebug &debug, const QRect r)
+{
+ debug << r.width() << 'x' << r.height()
+ << forcesign << r.x() << r.y() << noforcesign;
+}
+
+static inline void formatSizeF(QDebug &debug, const QSizeF s)
+{
+ debug << s.width() << 'x' << s.height() << "mm";
+}
+
+QDebug operator<<(QDebug debug, const QXcbScreen *screen)
+{
+ const QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug << "QXcbScreen(" << (void *)screen;
+ if (screen) {
+ debug << fixed << qSetRealNumberPrecision(1);
+ debug << ", name=" << screen->name();
+ debug << ", geometry=";
+ formatRect(debug, screen->geometry());
+ debug << ", availableGeometry=";
+ formatRect(debug, screen->availableGeometry());
+ debug << ", devicePixelRatio=" << screen->devicePixelRatio();
+ debug << ", logicalDpi=" << screen->logicalDpi();
+ debug << ", physicalSize=";
+ formatSizeF(debug, screen->physicalSize());
+ // TODO 5.6 if (debug.verbosity() > 2) {
+ debug << ", screenNumber=" << screen->screenNumber();
+ debug << ", virtualSize=" << screen->virtualSize().width() << "x" << screen->virtualSize().height() << " (";
+ formatSizeF(debug, screen->virtualSize());
+ debug << "), nativeGeometry=";
+ formatRect(debug, screen->nativeGeometry());
+ debug << ", orientation=" << screen->orientation();
+ debug << ", depth=" << screen->depth();
+ debug << ", refreshRate=" << screen->refreshRate();
+ debug << ", root=" << hex << screen->root();
+ debug << ", windowManagerName=" << screen->windowManagerName();
+ }
+ debug << ')';
+ return debug;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h
index e9ab2ed..81c3445 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.h
+++ b/src/plugins/platforms/xcb/qxcbscreen.h
@@ -49,6 +49,9 @@ QT_BEGIN_NAMESPACE
class QXcbConnection;
class QXcbCursor;
class QXcbXSettings;
+#ifndef QT_NO_DEBUG_STREAM
+class QDebug;
+#endif
class QXcbScreen : public QXcbObject, public QPlatformScreen
{
@@ -67,6 +70,8 @@ public:
int depth() const { return m_screen->root_depth; }
QImage::Format format() const;
QSizeF physicalSize() const { return m_sizeMillimeters; }
+ QSize virtualSize() const { return m_virtualSize; }
+ QSizeF physicalVirtualSize() const { return m_virtualSizeMillimeters; }
QDpi logicalDpi() const;
qreal devicePixelRatio() const;
QPlatformCursor *cursor() const;
@@ -139,6 +144,10 @@ private:
QXcbXSettings *m_xSettings;
};
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug, const QXcbScreen *);
+#endif
+
QT_END_NAMESPACE
#endif

View File

@ -0,0 +1,89 @@
commit 51ada7734ad780178ecced11e0dff454dfc2e5f2
Author: Shawn Rutledge <shawn.rutledge@digia.com>
Date: Mon Mar 2 10:48:21 2015 +0100
xcb: do not create a dummy QScreen when there are no outputs
Whenever a QWindow is associated with a QScreen, the screen is expected
to be a real working one, so that rendering continues to be possible.
This partially reverts 52f5e50f11a3ba82e32dc2efc656e4021a3fa4f5
[ChangeLog][QPA][Xcb] If all QScreens (xcb outputs) are disconnected
while an application is running, QGuiApplication::primaryScreen() will
return null until a screen is connected again.
Task-number: QTBUG-40174
Task-number: QTBUG-42985
Change-Id: Id1b29dd70eaf3f2e7fd477516ce7e2bf24e095f6
Reviewed-by: Laszlo Agocs <laszlo.agocs@theqtcompany.com>
Reviewed-by: Jørgen Lind <jorgen.lind@theqtcompany.com>
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index dc5501e..7f2bf16 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -872,9 +872,14 @@ QWindowList QGuiApplication::topLevelWindows()
}
/*!
- Returns the primary (or default) screen of the application.
+ Returns the primary (or default) screen of the application, or null if there is none
This will be the screen where QWindows are initially shown, unless otherwise specified.
+
+ On some platforms, it may be null when there are actually no screens connected.
+ It is not possible to start a new QGuiApplication while there are no screens.
+ Applications which were running at the time the primary screen was removed
+ will stop rendering graphics until one or more screens are restored.
*/
QScreen *QGuiApplication::primaryScreen()
{
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index a8c1943..6efb876 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -254,16 +254,6 @@ void QXcbConnection::updateScreens()
}
free(primary);
}
- // If there's no randr extension, or there was some error above, or the screen
- // doesn't have outputs for some other reason (e.g. on VNC or ssh -X), just assume there is one screen.
- if (connectedOutputCount == 0) {
- qCDebug(lcQpaScreen, "found a screen with zero outputs");
- QXcbScreen *screen = findOrCreateScreen(newScreens, xcbScreenNumber, xcbScreen);
- siblings << screen;
- activeScreens << screen;
- if (!primaryScreen)
- primaryScreen = screen;
- }
foreach (QPlatformScreen* s, siblings)
((QXcbScreen*)s)->setVirtualSiblings(siblings);
xcb_screen_next(&it);
@@ -321,6 +311,11 @@ void QXcbConnection::updateScreens()
if (!m_screens.isEmpty())
qCDebug(lcQpaScreen) << "primary output is" << m_screens.first()->name();
+ else
+ // QTBUG-40174, QTBUG-42985: If there are no outputs, then there must be
+ // no QScreen instances; a Qt application can survive this situation, and
+ // start rendering again later when there is a screen again.
+ qCDebug(lcQpaScreen) << "xcb connection has no outputs";
}
QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, const char *displayName)
diff --git a/src/widgets/kernel/qdesktopwidget.qdoc b/src/widgets/kernel/qdesktopwidget.qdoc
index e8bda3c..f46a629 100644
--- a/src/widgets/kernel/qdesktopwidget.qdoc
+++ b/src/widgets/kernel/qdesktopwidget.qdoc
@@ -238,6 +238,11 @@
\property QDesktopWidget::screenCount
\brief the number of screens currently available on the system.
+ Note that on some platforms, screenCount will be zero if there are actually
+ no screens connected. Applications which were running at the time the
+ screenCount went to zero will stop rendering graphics until one or more
+ screens are restored.
+
\since 4.6
*/

View File

@ -0,0 +1,713 @@
commit 3b30a8215e98f6164a1650ce7c7e2a42a3d8746f
Author: Daniel Vrátil <dvratil@redhat.com>
Date: Mon Feb 23 20:27:37 2015 +0100
Improve handling of XRandR events in XCB backend
Querying X server for data can be very expensive, especially when there
are multiple processes querying it at the same time (which is exactly what
happens when screen configuration changes and all Qt applications receive
XRandR change notifications). This patch is aiming to reduce the number of
queries to X server as much as possible by making use of detailed information
available in the RRCrtcChangeNotify and RROutputChangeNotify events.
Firstly, the backend now does not rebuild all QXcbScreens on any change (which
involved the very expensive xcb_randr_get_screen_resources() call), but only
builds the full set of QXcbScreens once in initializeScreens(), and then just
incrementally updates it.
Secondly, it avoids querying X server for all screens geometry as much as
possible, and only does so when CRTC/Output change notification for a particular
screen is delivered.
As a result, handling of all XRandR events on screen change is reduced from tens
of seconds to less then a seconds and applications are better responsive after
that, because we don't block the event loop for long. The X server is also more
responsive after the screen change, since we are not overloading it with requests.
Change-Id: I9b8308341cada71dfc9590030909b1e68a335a1f
Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 6efb876..0db7603 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -49,6 +49,7 @@
#include <QAbstractEventDispatcher>
#include <QTimer>
#include <QByteArray>
+#include <QScopedPointer>
#include <algorithm>
@@ -155,8 +156,29 @@ typedef struct {
} QGLXBufferSwapComplete;
#endif
-QXcbScreen* QXcbConnection::findOrCreateScreen(QList<QXcbScreen *>& newScreens,
- int screenNumber, xcb_screen_t* xcbScreen, xcb_randr_get_output_info_reply_t *output)
+QXcbScreen* QXcbConnection::findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc)
+{
+ foreach (QXcbScreen *screen, m_screens) {
+ if (screen->root() == rootWindow && screen->crtc() == crtc)
+ return screen;
+ }
+
+ return 0;
+}
+
+QXcbScreen* QXcbConnection::findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output)
+{
+ foreach (QXcbScreen *screen, m_screens) {
+ if (screen->root() == rootWindow && screen->output() == output)
+ return screen;
+ }
+
+ return 0;
+}
+
+QXcbScreen* QXcbConnection::createScreen(int screenNumber, xcb_screen_t* xcbScreen,
+ xcb_randr_output_t outputId,
+ xcb_randr_get_output_info_reply_t *output)
{
QString name;
if (output)
@@ -169,23 +191,147 @@ QXcbScreen* QXcbConnection::findOrCreateScreen(QList<QXcbScreen *>& newScreens,
displayName.truncate(dotPos);
name = displayName + QLatin1Char('.') + QString::number(screenNumber);
}
- foreach (QXcbScreen* scr, m_screens)
- if (scr->name() == name && scr->root() == xcbScreen->root)
- return scr;
- QXcbScreen *ret = new QXcbScreen(this, xcbScreen, output, name, screenNumber);
- newScreens << ret;
- return ret;
+
+ return new QXcbScreen(this, xcbScreen, outputId, output, name, screenNumber);
+}
+
+bool QXcbConnection::checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output)
+{
+ xcb_generic_error_t *error = 0;
+ xcb_randr_get_output_primary_cookie_t primaryCookie =
+ xcb_randr_get_output_primary(xcb_connection(), rootWindow);
+ QScopedPointer<xcb_randr_get_output_primary_reply_t, QScopedPointerPodDeleter> primary (
+ xcb_randr_get_output_primary_reply(xcb_connection(), primaryCookie, &error));
+ if (!primary || error) {
+ qWarning("failed to get the primary output of the screen");
+ free(error);
+ error = NULL;
+ }
+ const bool isPrimary = primary ? (primary->output == output) : false;
+
+ return isPrimary;
+}
+
+xcb_screen_t* QXcbConnection::xcbScreenForRootWindow(xcb_window_t rootWindow, int *xcbScreenNumber)
+{
+ xcb_screen_iterator_t xcbScreenIter = xcb_setup_roots_iterator(m_setup);
+ for (; xcbScreenIter.rem; xcb_screen_next(&xcbScreenIter)) {
+ if (xcbScreenIter.data->root == rootWindow) {
+ if (xcbScreenNumber)
+ *xcbScreenNumber = xcb_setup_roots_length(m_setup) - xcbScreenIter.rem;
+ return xcbScreenIter.data;
+ }
+ }
+
+ return 0;
}
/*!
\brief Synchronizes the screen list, adds new screens, removes deleted ones
*/
-void QXcbConnection::updateScreens()
+void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event)
+{
+ if (event->subCode == XCB_RANDR_NOTIFY_CRTC_CHANGE) {
+ xcb_randr_crtc_change_t crtc = event->u.cc;
+ xcb_screen_t *xcbScreen = xcbScreenForRootWindow(crtc.window);
+ if (!xcbScreen)
+ // Not for us
+ return;
+
+ qCDebug(lcQpaScreen) << "QXcbConnection: XCB_RANDR_NOTIFY_CRTC_CHANGE:" << crtc.crtc;
+ QXcbScreen *screen = findScreenForCrtc(crtc.window, crtc.crtc);
+ // Only update geometry when there's a valid mode on the CRTC
+ // CRTC with node mode could mean that output has been disabled, and we'll
+ // get RRNotifyOutputChange notification for that.
+ if (screen && crtc.mode) {
+ screen->updateGeometry(QRect(crtc.x, crtc.y, crtc.width, crtc.height), crtc.rotation);
+ if (screen->mode() != crtc.mode)
+ screen->updateRefreshRate(crtc.mode);
+ }
+
+ } else if (event->subCode == XCB_RANDR_NOTIFY_OUTPUT_CHANGE) {
+ xcb_randr_output_change_t output = event->u.oc;
+ int xcbScreenNumber = 0;
+ xcb_screen_t *xcbScreen = xcbScreenForRootWindow(output.window, &xcbScreenNumber);
+ if (!xcbScreen)
+ // Not for us
+ return;
+
+ QXcbScreen *screen = findScreenForOutput(output.window, output.output);
+ qCDebug(lcQpaScreen) << "QXcbConnection: XCB_RANDR_NOTIFY_OUTPUT_CHANGE:" << output.output;
+
+ if (screen && output.connection == XCB_RANDR_CONNECTION_DISCONNECTED) {
+ qCDebug(lcQpaScreen) << "screen" << screen->name() << "has been disconnected";
+
+ // Known screen removed -> delete it
+ m_screens.removeOne(screen);
+ foreach (QXcbScreen *otherScreen, m_screens)
+ otherScreen->removeVirtualSibling((QPlatformScreen *) screen);
+
+ QXcbIntegration::instance()->destroyScreen(screen);
+
+ // QTBUG-40174, QTBUG-42985: If there are no outputs, then there must be
+ // no QScreen instances; a Qt application can survive this situation, and
+ // start rendering again later when there is a screen again.
+
+ } else if (!screen && output.connection == XCB_RANDR_CONNECTION_CONNECTED) {
+ // New XRandR output is available and it's enabled
+ if (output.crtc != XCB_NONE && output.mode != XCB_NONE) {
+ xcb_randr_get_output_info_cookie_t outputInfoCookie =
+ xcb_randr_get_output_info(xcb_connection(), output.output, output.config_timestamp);
+ QScopedPointer<xcb_randr_get_output_info_reply_t, QScopedPointerPodDeleter> outputInfo(
+ xcb_randr_get_output_info_reply(xcb_connection(), outputInfoCookie, NULL));
+
+ screen = createScreen(xcbScreenNumber, xcbScreen, output.output, outputInfo.data());
+ qCDebug(lcQpaScreen) << "output" << screen->name() << "is connected and enabled";
+
+ screen->setPrimary(checkOutputIsPrimary(output.window, output.output));
+ foreach (QXcbScreen *otherScreen, m_screens)
+ if (otherScreen->root() == output.window)
+ otherScreen->addVirtualSibling(screen);
+ m_screens << screen;
+ QXcbIntegration::instance()->screenAdded(screen, screen->isPrimary());
+ }
+ // else ignore disabled screens
+ } else if (screen) {
+ // Screen has been disabled -> remove
+ if (output.crtc == XCB_NONE && output.mode == XCB_NONE) {
+ qCDebug(lcQpaScreen) << "output" << screen->name() << "has been disabled";
+ m_screens.removeOne(screen);
+ foreach (QXcbScreen *otherScreen, m_screens)
+ otherScreen->removeVirtualSibling((QPlatformScreen *) screen);
+ QXcbIntegration::instance()->destroyScreen(screen);
+ } else {
+ // Just update existing screen
+ screen->updateGeometry(output.config_timestamp);
+ const bool wasPrimary = screen->isPrimary();
+ screen->setPrimary(checkOutputIsPrimary(output.window, output.output));
+ if (screen->mode() != output.mode)
+ screen->updateRefreshRate(output.mode);
+
+ // If the screen became primary, reshuffle the order in QGuiApplicationPrivate
+ // TODO: add a proper mechanism for updating primary screen
+ if (!wasPrimary && screen->isPrimary()) {
+ QScreen *realScreen = static_cast<QPlatformScreen*>(screen)->screen();
+ QGuiApplicationPrivate::screen_list.removeOne(realScreen);
+ QGuiApplicationPrivate::screen_list.prepend(realScreen);
+ m_screens.removeOne(screen);
+ m_screens.prepend(screen);
+ }
+ qCDebug(lcQpaScreen) << "output has changed" << screen;
+ }
+ }
+ if (!m_screens.isEmpty())
+ qCDebug(lcQpaScreen) << "primary output is" << m_screens.first()->name();
+ else
+ qCDebug(lcQpaScreen) << "no outputs";
+ }
+}
+
+void QXcbConnection::initializeScreens()
{
xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup);
int xcbScreenNumber = 0; // screen number in the xcb sense
- QList<QXcbScreen *> activeScreens;
- QList<QXcbScreen *> newScreens;
QXcbScreen* primaryScreen = NULL;
while (it.rem) {
// Each "screen" in xcb terminology is a virtual desktop,
@@ -200,59 +346,73 @@ void QXcbConnection::updateScreens()
xcb_generic_error_t *error = NULL;
xcb_randr_get_output_primary_cookie_t primaryCookie =
xcb_randr_get_output_primary(xcb_connection(), xcbScreen->root);
+ // TODO: RRGetScreenResources has to be called on each X display at least once before
+ // RRGetScreenResourcesCurrent can be used - we can't know if we are the first application
+ // to do so or not, so we always call the slower version here. Ideally we should share some
+ // global flag (an atom on root window maybe) that at least other Qt apps would understand
+ // and could call RRGetScreenResourcesCurrent here, speeding up start.
xcb_randr_get_screen_resources_cookie_t resourcesCookie =
xcb_randr_get_screen_resources(xcb_connection(), xcbScreen->root);
- xcb_randr_get_output_primary_reply_t *primary =
- xcb_randr_get_output_primary_reply(xcb_connection(), primaryCookie, &error);
+ QScopedPointer<xcb_randr_get_output_primary_reply_t, QScopedPointerPodDeleter> primary(
+ xcb_randr_get_output_primary_reply(xcb_connection(), primaryCookie, &error));
if (!primary || error) {
- qWarning("QXcbConnection: Failed to get the primary output of the screen");
+ qWarning("failed to get the primary output of the screen");
free(error);
} else {
- xcb_randr_get_screen_resources_reply_t *resources =
- xcb_randr_get_screen_resources_reply(xcb_connection(), resourcesCookie, &error);
+ QScopedPointer<xcb_randr_get_screen_resources_reply_t, QScopedPointerPodDeleter> resources(
+ xcb_randr_get_screen_resources_reply(xcb_connection(), resourcesCookie, &error));
if (!resources || error) {
- qWarning("QXcbConnection: Failed to get the screen resources");
+ qWarning("failed to get the screen resources");
free(error);
} else {
xcb_timestamp_t timestamp = resources->config_timestamp;
- outputCount = xcb_randr_get_screen_resources_outputs_length(resources);
- xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_outputs(resources);
+ outputCount = xcb_randr_get_screen_resources_outputs_length(resources.data());
+ xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_outputs(resources.data());
for (int i = 0; i < outputCount; i++) {
- xcb_randr_get_output_info_reply_t *output =
+ QScopedPointer<xcb_randr_get_output_info_reply_t, QScopedPointerPodDeleter> output(
xcb_randr_get_output_info_reply(xcb_connection(),
- xcb_randr_get_output_info_unchecked(xcb_connection(), outputs[i], timestamp), NULL);
+ xcb_randr_get_output_info_unchecked(xcb_connection(), outputs[i], timestamp), NULL));
+
+ // Invalid, disconnected or disabled output
if (output == NULL)
continue;
+ if (output->connection != XCB_RANDR_CONNECTION_CONNECTED) {
+ qCDebug(lcQpaScreen, "Output %s is not connected", qPrintable(
+ QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output.data()),
+ xcb_randr_get_output_info_name_length(output.data()))));
+ continue;
+ }
if (output->crtc == XCB_NONE) {
- qCDebug(lcQpaScreen, "output %s is not connected", qPrintable(
- QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output),
- xcb_randr_get_output_info_name_length(output))));
+ qCDebug(lcQpaScreen, "Output %s is not enabled", qPrintable(
+ QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output.data()),
+ xcb_randr_get_output_info_name_length(output.data()))));
continue;
}
- QXcbScreen *screen = findOrCreateScreen(newScreens, xcbScreenNumber, xcbScreen, output);
+ QXcbScreen *screen = createScreen(xcbScreenNumber, xcbScreen, outputs[i], output.data());
siblings << screen;
- activeScreens << screen;
++connectedOutputCount;
+ m_screens << screen;
+
// There can be multiple outputs per screen, use either
// the first or an exact match. An exact match isn't
// always available if primary->output is XCB_NONE
// or currently disconnected output.
if (m_primaryScreenNumber == xcbScreenNumber) {
if (!primaryScreen || (primary && outputs[i] == primary->output)) {
+ if (primaryScreen)
+ primaryScreen->setPrimary(false);
primaryScreen = screen;
+ primaryScreen->setPrimary(true);
siblings.prepend(siblings.takeLast());
}
}
- free(output);
}
}
- free(resources);
}
- free(primary);
}
foreach (QPlatformScreen* s, siblings)
((QXcbScreen*)s)->setVirtualSiblings(siblings);
@@ -260,47 +420,7 @@ void QXcbConnection::updateScreens()
++xcbScreenNumber;
} // for each xcb screen
- QXcbIntegration *integration = QXcbIntegration::instance();
-
- // Rebuild screen list, ensuring primary screen is always in front,
- // both in the QXcbConnection::m_screens list as well as in the
- // QGuiApplicationPrivate::screen_list list, which gets updated via
- // - screen added: integration->screenAdded()
- // - screen removed: integration->destroyScreen
-
- // Gather screens to delete
- QList<QXcbScreen*> screensToDelete;
- for (int i = m_screens.count() - 1; i >= 0; --i) {
- if (!activeScreens.contains(m_screens[i])) {
- screensToDelete.append(m_screens.takeAt(i));
- }
- }
-
- // If there is a new primary screen, add that one first
- if (newScreens.contains(primaryScreen)) {
- newScreens.removeOne(primaryScreen);
- m_screens.prepend(primaryScreen);
- qCDebug(lcQpaScreen) << "adding as primary" << primaryScreen;
- integration->screenAdded(primaryScreen, true);
- }
-
- // Add the remaining new screens
- foreach (QXcbScreen* screen, newScreens) {
- m_screens.append(screen);
- qCDebug(lcQpaScreen) << "adding" << screen;
- integration->screenAdded(screen);
- }
-
- // Delete the old screens, now that the new ones were added
- // and we are sure that there is at least one screen available
- foreach (QXcbScreen* screen, screensToDelete) {
- qCDebug(lcQpaScreen) << "removing" << screen;
- integration->destroyScreen(screen);
- }
-
- // Ensure that the primary screen is first in m_screens too
- // (in case the assignment of primary was the only change,
- // without adding or removing screens)
+ // Ensure the primary screen is first in the list
if (primaryScreen) {
Q_ASSERT(!m_screens.isEmpty());
if (m_screens.first() != primaryScreen) {
@@ -309,13 +429,15 @@ void QXcbConnection::updateScreens()
}
}
+ // Push the screens to QApplication
+ QXcbIntegration *integration = QXcbIntegration::instance();
+ foreach (QXcbScreen* screen, m_screens) {
+ qCDebug(lcQpaScreen) << "adding" << screen << "(Primary:" << screen->isPrimary() << ")";
+ integration->screenAdded(screen, screen->isPrimary());
+ }
+
if (!m_screens.isEmpty())
qCDebug(lcQpaScreen) << "primary output is" << m_screens.first()->name();
- else
- // QTBUG-40174, QTBUG-42985: If there are no outputs, then there must be
- // no QScreen instances; a Qt application can survive this situation, and
- // start rendering again later when there is a screen again.
- qCDebug(lcQpaScreen) << "xcb connection has no outputs";
}
QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, const char *displayName)
@@ -395,7 +517,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
m_netWmUserTime = XCB_CURRENT_TIME;
initializeXRandr();
- updateScreens();
+ initializeScreens();
initializeGLX();
initializeXFixes();
@@ -967,14 +1089,14 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
m_clipboard->handleXFixesSelectionRequest((xcb_xfixes_selection_notify_event_t *)event);
#endif
handled = true;
+ } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_NOTIFY) {
+ updateScreens((xcb_randr_notify_event_t *)event);
+ handled = true;
} else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
- updateScreens();
xcb_randr_screen_change_notify_event_t *change_event = (xcb_randr_screen_change_notify_event_t *)event;
foreach (QXcbScreen *s, m_screens) {
- if (s->root() == change_event->root ) {
+ if (s->root() == change_event->root )
s->handleScreenChange(change_event);
- s->updateRefreshRate();
- }
}
handled = true;
#ifndef QT_NO_XKB
@@ -1741,6 +1863,17 @@ void QXcbConnection::initializeXRandr()
has_randr_extension = false;
}
free(xrandr_query);
+
+ xcb_screen_iterator_t rootIter = xcb_setup_roots_iterator(m_setup);
+ for (; rootIter.rem; xcb_screen_next(&rootIter)) {
+ xcb_randr_select_input(xcb_connection(),
+ rootIter.data->root,
+ XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE |
+ XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE |
+ XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE |
+ XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY
+ );
+ }
}
void QXcbConnection::initializeXShape()
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 6e7e87d..9c190d7 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -35,6 +35,7 @@
#define QXCBCONNECTION_H
#include <xcb/xcb.h>
+#include <xcb/randr.h>
#include <QHash>
#include <QList>
@@ -492,9 +493,15 @@ private:
void initializeXShape();
void initializeXKB();
void handleClientMessageEvent(const xcb_client_message_event_t *event);
- QXcbScreen* findOrCreateScreen(QList<QXcbScreen *>& newScreens, int screenNumber,
- xcb_screen_t* xcbScreen, xcb_randr_get_output_info_reply_t *output = NULL);
- void updateScreens();
+ QXcbScreen* createScreen(int screenNumber, xcb_screen_t* xcbScreen,
+ xcb_randr_output_t outputId = XCB_NONE,
+ xcb_randr_get_output_info_reply_t *output = 0);
+ QXcbScreen* findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc);
+ QXcbScreen* findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output);
+ xcb_screen_t* xcbScreenForRootWindow(xcb_window_t rootWindow, int *xcbScreenNumber = 0);
+ bool checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output);
+ void initializeScreens();
+ void updateScreens(const xcb_randr_notify_event_t *event);
void handleButtonPress(xcb_generic_event_t *event);
void handleButtonRelease(xcb_generic_event_t *event);
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 2aebb84..d89bdbb 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -48,10 +48,15 @@
QT_BEGIN_NAMESPACE
QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr,
- xcb_randr_get_output_info_reply_t *output, QString outputName, int number)
+ xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output,
+ QString outputName, int number)
: QXcbObject(connection)
, m_screen(scr)
+ , m_output(outputId)
, m_crtc(output ? output->crtc : 0)
+ , m_mode(XCB_NONE)
+ , m_primary(false)
+ , m_rotation(XCB_RANDR_ROTATION_ROTATE_0)
, m_outputName(outputName)
, m_outputSizeMillimeters(output ? QSize(output->mm_width, output->mm_height) : QSize())
, m_virtualSize(scr->width_in_pixels, scr->height_in_pixels)
@@ -67,11 +72,20 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr,
, m_antialiasingEnabled(-1)
, m_xSettings(0)
{
- if (connection->hasXRandr())
+ if (connection->hasXRandr()) {
xcb_randr_select_input(xcb_connection(), screen()->root, true);
-
- updateGeometry(output ? output->timestamp : 0);
- updateRefreshRate();
+ xcb_randr_get_crtc_info_cookie_t crtcCookie =
+ xcb_randr_get_crtc_info_unchecked(xcb_connection(), m_crtc, output ? output->timestamp : 0);
+ xcb_randr_get_crtc_info_reply_t *crtc =
+ xcb_randr_get_crtc_info_reply(xcb_connection(), crtcCookie, NULL);
+ if (crtc) {
+ updateGeometry(QRect(crtc->x, crtc->y, crtc->width, crtc->height), crtc->rotation);
+ updateRefreshRate(crtc->mode);
+ free(crtc);
+ }
+ } else {
+ updateGeometry(output ? output->timestamp : 0);
+ }
const int dpr = int(devicePixelRatio());
// On VNC, it can be that physical size is unknown while
@@ -352,9 +366,15 @@ QPlatformCursor *QXcbScreen::cursor() const
*/
void QXcbScreen::handleScreenChange(xcb_randr_screen_change_notify_event_t *change_event)
{
- updateGeometry(change_event->config_timestamp);
+ // No need to do anything when screen rotation did not change - if any
+ // xcb output geometry has changed, we will get RRCrtcChangeNotify and
+ // RROutputChangeNotify events next
+ if (change_event->rotation == m_rotation)
+ return;
- switch (change_event->rotation) {
+ m_rotation = change_event->rotation;
+ updateGeometry(change_event->timestamp);
+ switch (m_rotation) {
case XCB_RANDR_ROTATION_ROTATE_0: // xrandr --rotate normal
m_orientation = Qt::LandscapeOrientation;
m_virtualSize.setWidth(change_event->width);
@@ -398,35 +418,37 @@ void QXcbScreen::handleScreenChange(xcb_randr_screen_change_notify_event_t *chan
void QXcbScreen::updateGeometry(xcb_timestamp_t timestamp)
{
- QRect xGeometry;
- QRect xAvailableGeometry;
+ xcb_randr_get_crtc_info_cookie_t crtcCookie =
+ xcb_randr_get_crtc_info_unchecked(xcb_connection(), m_crtc, timestamp);
+ xcb_randr_get_crtc_info_reply_t *crtc =
+ xcb_randr_get_crtc_info_reply(xcb_connection(), crtcCookie, NULL);
+ if (crtc) {
+ updateGeometry(QRect(crtc->x, crtc->y, crtc->width, crtc->height), crtc->rotation);
+ free(crtc);
+ }
+}
- if (connection()->hasXRandr()) {
- xcb_randr_get_crtc_info_reply_t *crtc = xcb_randr_get_crtc_info_reply(xcb_connection(),
- xcb_randr_get_crtc_info_unchecked(xcb_connection(), m_crtc, timestamp), NULL);
- if (crtc) {
- xGeometry = QRect(crtc->x, crtc->y, crtc->width, crtc->height);
- xAvailableGeometry = xGeometry;
- switch (crtc->rotation) {
- case XCB_RANDR_ROTATION_ROTATE_0: // xrandr --rotate normal
- m_orientation = Qt::LandscapeOrientation;
- m_sizeMillimeters = m_outputSizeMillimeters;
- break;
- case XCB_RANDR_ROTATION_ROTATE_90: // xrandr --rotate left
- m_orientation = Qt::PortraitOrientation;
- m_sizeMillimeters = m_outputSizeMillimeters.transposed();
- break;
- case XCB_RANDR_ROTATION_ROTATE_180: // xrandr --rotate inverted
- m_orientation = Qt::InvertedLandscapeOrientation;
- m_sizeMillimeters = m_outputSizeMillimeters;
- break;
- case XCB_RANDR_ROTATION_ROTATE_270: // xrandr --rotate right
- m_orientation = Qt::InvertedPortraitOrientation;
- m_sizeMillimeters = m_outputSizeMillimeters.transposed();
- break;
- }
- free(crtc);
- }
+void QXcbScreen::updateGeometry(const QRect &geom, uint8_t rotation)
+{
+ QRect xGeometry = geom;
+ QRect xAvailableGeometry = xGeometry;
+ switch (rotation) {
+ case XCB_RANDR_ROTATION_ROTATE_0: // xrandr --rotate normal
+ m_orientation = Qt::LandscapeOrientation;
+ m_sizeMillimeters = m_outputSizeMillimeters;
+ break;
+ case XCB_RANDR_ROTATION_ROTATE_90: // xrandr --rotate left
+ m_orientation = Qt::PortraitOrientation;
+ m_sizeMillimeters = m_outputSizeMillimeters.transposed();
+ break;
+ case XCB_RANDR_ROTATION_ROTATE_180: // xrandr --rotate inverted
+ m_orientation = Qt::InvertedLandscapeOrientation;
+ m_sizeMillimeters = m_outputSizeMillimeters;
+ break;
+ case XCB_RANDR_ROTATION_ROTATE_270: // xrandr --rotate right
+ m_orientation = Qt::InvertedPortraitOrientation;
+ m_sizeMillimeters = m_outputSizeMillimeters.transposed();
+ break;
}
xcb_get_property_reply_t * workArea =
@@ -455,31 +477,38 @@ void QXcbScreen::updateGeometry(xcb_timestamp_t timestamp)
m_geometry = QRect(xGeometry.topLeft()/dpr, xGeometry.size()/dpr);
m_nativeGeometry = QRect(xGeometry.topLeft(), xGeometry.size());
m_availableGeometry = QRect(xAvailableGeometry.topLeft()/dpr, xAvailableGeometry.size()/dpr);
-
QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry);
}
-void QXcbScreen::updateRefreshRate()
+void QXcbScreen::updateRefreshRate(xcb_randr_mode_t mode)
{
if (!connection()->hasXRandr())
return;
- int rate = m_refreshRate;
-
- xcb_randr_get_screen_info_reply_t *screenInfoReply =
- xcb_randr_get_screen_info_reply(xcb_connection(), xcb_randr_get_screen_info_unchecked(xcb_connection(), m_screen->root), 0);
-
- if (screenInfoReply) {
- rate = screenInfoReply->rate;
- free(screenInfoReply);
- }
-
- if (rate == m_refreshRate)
+ if (m_mode == mode)
return;
- m_refreshRate = rate;
+ // we can safely use get_screen_resources_current here, because in order to
+ // get here, we must have called get_screen_resources before
+ xcb_randr_get_screen_resources_current_cookie_t resourcesCookie =
+ xcb_randr_get_screen_resources_current_unchecked(xcb_connection(), m_screen->root);
+ xcb_randr_get_screen_resources_current_reply_t *resources =
+ xcb_randr_get_screen_resources_current_reply(xcb_connection(), resourcesCookie, NULL);
+ if (resources) {
+ xcb_randr_mode_info_iterator_t modesIter =
+ xcb_randr_get_screen_resources_current_modes_iterator(resources);
+ for (; modesIter.rem; xcb_randr_mode_info_next(&modesIter)) {
+ xcb_randr_mode_info_t *modeInfo = modesIter.data;
+ if (modeInfo->id == mode) {
+ m_refreshRate = modeInfo->dot_clock / (modeInfo->htotal * modeInfo->vtotal);
+ m_mode = mode;
+ break;
+ }
+ }
- QWindowSystemInterface::handleScreenRefreshRateChange(QPlatformScreen::screen(), rate);
+ free(resources);
+ QWindowSystemInterface::handleScreenRefreshRateChange(QPlatformScreen::screen(), m_refreshRate);
+ }
}
QPixmap QXcbScreen::grabWindow(WId window, int x, int y, int width, int height) const
diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h
index 81c3445..a654a3e 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.h
+++ b/src/plugins/platforms/xcb/qxcbscreen.h
@@ -57,7 +57,8 @@ class QXcbScreen : public QXcbObject, public QPlatformScreen
{
public:
QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen,
- xcb_randr_get_output_info_reply_t *output, QString outputName, int number);
+ xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output,
+ QString outputName, int number);
~QXcbScreen();
QPixmap grabWindow(WId window, int x, int y, int width, int height) const;
@@ -79,11 +80,19 @@ public:
Qt::ScreenOrientation orientation() const { return m_orientation; }
QList<QPlatformScreen *> virtualSiblings() const { return m_siblings; }
void setVirtualSiblings(QList<QPlatformScreen *> sl) { m_siblings = sl; }
+ void removeVirtualSibling(QPlatformScreen *s) { m_siblings.removeOne(s); }
+ void addVirtualSibling(QPlatformScreen *s) { ((QXcbScreen *) s)->isPrimary() ? m_siblings.prepend(s) : m_siblings.append(s); }
+
+ void setPrimary(bool primary) { m_primary = primary; }
+ bool isPrimary() const { return m_primary; }
int screenNumber() const { return m_number; }
xcb_screen_t *screen() const { return m_screen; }
xcb_window_t root() const { return m_screen->root; }
+ xcb_randr_output_t output() const { return m_output; }
+ xcb_randr_crtc_t crtc() const { return m_crtc; }
+ xcb_randr_mode_t mode() const { return m_mode; }
xcb_window_t clientLeader() const { return m_clientLeader; }
@@ -97,8 +106,9 @@ public:
QString name() const { return m_outputName; }
void handleScreenChange(xcb_randr_screen_change_notify_event_t *change_event);
- void updateGeometry(xcb_timestamp_t timestamp);
- void updateRefreshRate();
+ void updateGeometry(const QRect &geom, uint8_t rotation);
+ void updateGeometry(xcb_timestamp_t timestamp = XCB_TIME_CURRENT_TIME);
+ void updateRefreshRate(xcb_randr_mode_t mode);
void readXResources();
@@ -116,7 +126,12 @@ private:
void sendStartupMessage(const QByteArray &message) const;
xcb_screen_t *m_screen;
+ xcb_randr_output_t m_output;
xcb_randr_crtc_t m_crtc;
+ xcb_randr_mode_t m_mode;
+ bool m_primary;
+ uint8_t m_rotation;
+
QString m_outputName;
QSizeF m_outputSizeMillimeters;
QSizeF m_sizeMillimeters;

View File

@ -0,0 +1,43 @@
commit 4c022338aa787c216c3afa217987e4125bd15b41
Author: Jan Kundrát <jkt@kde.org>
Date: Wed Mar 11 16:42:10 2015 +0100
Fix segfault when requesting root window and there are no screens
This was easy to hit with KDE Plasma 5.2.1; KWindowSystem called
QX11Info::appRootWindow() which in turn tried to dereference a nullptr
returned from QXcbConnection::primaryScreen().
#0 QXcbConnection::rootWindow (this=<optimized out>)
at qtgui-5.5.9999/src/plugins/platforms/xcb/qxcbconnection.cpp:1303
#1 0x00007fc26da096d7 in QXcbNativeInterface::rootWindow (this=this@entry=0x7fc27d1734d0)
at qtgui-5.5.9999/work/qtgui-5.5.9999/src/plugins/platforms/xcb/qxcbnativeinterface.cpp:425
#2 0x00007fc26da0ab21 in QXcbNativeInterface::nativeResourceForIntegration (this=0x7fc27d1734d0, resourceString=...)
at qtgui-5.5.9999/work/qtgui-5.5.9999/src/plugins/platforms/xcb/qxcbnativeinterface.cpp:223
#3 0x00007fc27c563148 in QX11Info::appRootWindow (screen=screen@entry=-1)
at qtx11extras-5.5.9999/work/qtx11extras-5.5.9999/src/x11extras/qx11info_x11.cpp:158
#4 0x00007fc27a98c444 in NETEventFilter::nativeEventFilter (this=0x7fc27d425b60, ev=0x7fc264004ad0)
at kwindowsystem-5.7.0/work/kwindowsystem-5.7.0/src/kwindowsystem_x11.cpp:192
#5 0x00007fc2795d0a8a in QAbstractEventDispatcher::filterNativeEvent (this=<optimized out>,
eventType=..., message=message@entry=0x7fc264004ad0, result=result@entry=0x7ffc96ecf348)
at qtcore-5.5.9999/work/qtcore-5.5.9999/src/corelib/kernel/qabstracteventdispatcher.cpp:460
#6 0x00007fc26d9ea941 in QXcbConnection::handleXcbEvent (this=this@entry=0x7fc27d173580, event=event@entry=0x7fc264004ad0)
at qtgui-5.5.9999/src/plugins/platforms/xcb/qxcbconnection.cpp:971
Change-Id: I98a5d767cd7e143f00666f6fc78e9dc10893513d
Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 0db7603..523ae79 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -1367,7 +1367,8 @@ xcb_timestamp_t QXcbConnection::getTimestamp()
xcb_window_t QXcbConnection::rootWindow()
{
- return primaryScreen()->root();
+ QXcbScreen *s = primaryScreen();
+ return s ? s->root() : 0;
}
void QXcbConnection::processXcbEvents()

View File

@ -0,0 +1,86 @@
commit ebdf9916600f0b0cd4d25b538d1fd0fef6e89077
Author: Shawn Rutledge <shawn.rutledge@digia.com>
Date: Tue Mar 10 17:09:31 2015 +0100
xcb: create a screen if dimensions are known but outputs are not
This partially reverts 51ada7734ad780178ecced11e0dff454dfc2e5f2
because it's necessary to keep some scenarios with vnc and
remote X servers working. When an application is starting,
if we don't find the xrandr outputs but we know the dimensions
of the screen, we should still be able to put windows onto that
screen; but when we already had known xrandr outputs and then they
were removed, that's the case where we want to stop rendering
(and have no screen instances) until the screen(s) are reattached.
Task-number: QTBUG-31389
Task-number: QTBUG-40174
Task-number: QTBUG-42985
Change-Id: I13d0996ba6ece78c4ebcd2c3a59f1617c1c7f0fa
Reviewed-by: Uli Schlachter <psychon@znc.in>
Reviewed-by: Gatis Paeglis <gatis.paeglis@digia.com>
Reviewed-by: Laszlo Agocs <laszlo.agocs@theqtcompany.com>
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 523ae79..89a0083 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -270,9 +270,8 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event)
QXcbIntegration::instance()->destroyScreen(screen);
- // QTBUG-40174, QTBUG-42985: If there are no outputs, then there must be
- // no QScreen instances; a Qt application can survive this situation, and
- // start rendering again later when there is a screen again.
+ // QTBUG-40174, QTBUG-42985: If all screens are removed, wait
+ // and start rendering again later if a screen becomes available.
} else if (!screen && output.connection == XCB_RANDR_CONNECTION_CONNECTED) {
// New XRandR output is available and it's enabled
@@ -332,13 +331,15 @@ void QXcbConnection::initializeScreens()
{
xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup);
int xcbScreenNumber = 0; // screen number in the xcb sense
- QXcbScreen* primaryScreen = NULL;
+ QXcbScreen* primaryScreen = Q_NULLPTR;
+ xcb_screen_t *xcbScreen = Q_NULLPTR;
+ bool hasOutputs = false;
while (it.rem) {
// Each "screen" in xcb terminology is a virtual desktop,
// potentially a collection of separate juxtaposed monitors.
// But we want a separate QScreen for each output (e.g. DVI-I-1, VGA-1, etc.)
// which will become virtual siblings.
- xcb_screen_t *xcbScreen = it.data;
+ xcbScreen = it.data;
QList<QPlatformScreen *> siblings;
int outputCount = 0;
int connectedOutputCount = 0;
@@ -395,6 +396,7 @@ void QXcbConnection::initializeScreens()
QXcbScreen *screen = createScreen(xcbScreenNumber, xcbScreen, outputs[i], output.data());
siblings << screen;
++connectedOutputCount;
+ hasOutputs = true;
m_screens << screen;
// There can be multiple outputs per screen, use either
@@ -420,6 +422,20 @@ void QXcbConnection::initializeScreens()
++xcbScreenNumber;
} // for each xcb screen
+ // If there's no randr extension, or there was some error above, or we found a
+ // screen which doesn't have outputs for some other reason (e.g. on VNC or ssh -X),
+ // but the dimensions are known anyway, and we don't already have any lingering
+ // (possibly disconnected) screens, then showing windows should be possible,
+ // so create one screen. (QTBUG-31389)
+ if (xcbScreen && !hasOutputs && xcbScreen->width_in_pixels > 0 && xcbScreen->height_in_pixels > 0 && m_screens.isEmpty()) {
+ QXcbScreen *screen = createScreen(0, xcbScreen, 0, Q_NULLPTR);
+ screen->setVirtualSiblings(QList<QPlatformScreen *>() << screen);
+ m_screens << screen;
+ primaryScreen = screen;
+ primaryScreen->setPrimary(true);
+ qCDebug(lcQpaScreen) << "found a screen with zero outputs" << screen;
+ }
+
// Ensure the primary screen is first in the list
if (primaryScreen) {
Q_ASSERT(!m_screens.isEmpty());

View File

@ -37,7 +37,7 @@
Summary: Qt5 - QtBase components
Name: qt5-qtbase
Version: 5.4.1
Release: 3%{?dist}
Release: 4%{?dist}
# See LGPL_EXCEPTIONS.txt, for exception details
License: LGPLv2 with exceptions or GPLv3 with exceptions
@ -82,15 +82,25 @@ Patch12: qtbase-opensource-src-5.2.0-enable_ft_lcdfilter.patch
# NEEDS REBASE
Patch50: qt5-poll.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1083664
# https://bugreports.qt.io/browse/QTBUG-42985
Patch51: qtbase-opensource-src-5.4.0-QTBUG-42985.patch
## upstream patches
# workaround https://bugreports.qt-project.org/browse/QTBUG-43057
# 'make docs' crash on el6, use qSort instead of std::sort
Patch100: qtbase-opensource-src-5.4.0-QTBUG-43057.patch
# Qt 5.5 patches rebased on Qt 5.4.1 for better XCB screen integration
# fixes screen-handling related crashes and massive performance improvement
# QTBUG-31389, QTBUG-38326, QTBUG-32973, QTBUG-40174, QTBUG-42985, QTBUG-42985, QTBUG-44388
# https://bugzilla.redhat.com/show_bug.cgi?id=1083664
Patch200: qt5-qtbase-5.5-0000-add-function-for-qpa-plugins-to-explictly-destroy-qscreens.patch
Patch201: qt5-qtbase-5.5-0001-have-xcb-windows-platform-integration-classes-keep-their-own-instance-pointer.patch
Patch202: qt5-qtbase-5.5-0002-ensure-qguiapplicationprivate-screen_list-is-correctly-populated.patch
Patch203: qt5-qtbase-5.5-0003-xcb-add-qt-qpa-screen-logging-category.patch
Patch204: qt5-qtbase-5.5-0004-xcb-do-not-create-dummy-qscreen-when-there-are-no-outputs.patch
Patch205: qt5-qtbase-5.5-0005-improve-handling-of-xrandr-events-in-xcb-backend.patch
Patch206: qt5-qtbase-5.5-0006-fix-segfault-when-requesting-root-window-and-there-are-no-screens.patch
Patch207: qt5-qtbase-5.5-0007-xcb-create-a-screen-if-dimensions-are-known-but-outputs-are-not.patch
Patch272: 0072-CMake-Fix-QObject-connect-failing-on-ARM.patch
Patch294: 0094-Fix-Meta-.-shortcuts-on-XCB.patch
Patch332: 0132-Call-ofono-nm-Registered-delayed-in-constructor-othe.patch
@ -336,12 +346,20 @@ rm -fv mkspecs/linux-g++*/qmake.conf.multilib-optflags
%patch12 -p1 -b .enable_ft_lcdfilter
#patch50 -p1 -b .poll
%patch51 -p1 -b .QTBUG-42985
%if 0%{?rhel} == 6
%patch100 -p1 -b .QTBUG-43057
%endif
%patch200 -p1 -b .xcb0000
%patch201 -p1 -b .xcb0001
%patch202 -p1 -b .xcb0002
%patch203 -p1 -b .xcb0003
%patch204 -p1 -b .xcb0004
%patch205 -p1 -b .xcb0005
%patch206 -p1 -b .xcb0006
%patch207 -p1 -b .xcb0007
%patch272 -p1 -b .0072
%patch294 -p1 -b .0094
%patch332 -p1 -b .0132
@ -857,6 +875,9 @@ fi
%changelog
* Wed Mar 25 2015 Daniel Vrátil <dvratil@redhat.com> - 5.4.1-4
- pull in set of upstream Qt 5.5 fixes and improvements for XCB screen handling rebased to 5.4
* Fri Feb 27 2015 Rex Dieter <rdieter@fedoraproject.org> - 5.4.1-3
- pull in handful of upstream fixes, particularly...
- Fix a division by zero when processing malformed BMP files (QTBUG-44547, CVE-2015-0295)

View File

@ -1,600 +0,0 @@
diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp
index 39b031e..7f808da 100644
--- a/src/gui/kernel/qplatformintegration.cpp
+++ b/src/gui/kernel/qplatformintegration.cpp
@@ -429,16 +429,40 @@ QList<int> QPlatformIntegration::possibleKeys(const QKeyEvent *) const
This adds the screen to QGuiApplication::screens(), and emits the
QGuiApplication::screenAdded() signal.
+ If the added screen is a primary screen (isPrimary = true), it is prepended
+ to the QGuiApplicationPrivate::screen_list, since
+ QGuiApplication::primaryScreen always returns the first screen in the list.
+
The screen is automatically removed when the QPlatformScreen is destroyed.
*/
-void QPlatformIntegration::screenAdded(QPlatformScreen *ps)
+void QPlatformIntegration::screenAdded(QPlatformScreen *ps, bool isPrimary)
{
QScreen *screen = new QScreen(ps);
ps->d_func()->screen = screen;
- QGuiApplicationPrivate::screen_list << screen;
+ if (isPrimary) {
+ QGuiApplicationPrivate::screen_list.prepend(screen);
+ } else {
+ QGuiApplicationPrivate::screen_list.append(screen);
+ }
emit qGuiApp->screenAdded(screen);
}
+/*!
+ Should be called by the implementation whenever a screen is removed.
+
+ The implementation should ensure that the screen removed is not the
+ primary screen.
+*/
+void QPlatformIntegration::screenRemoved(QPlatformScreen *ps)
+{
+ if (ps->screen() == QGuiApplicationPrivate::screen_list.first()) {
+ qWarning("Primary screen removed, expect trouble");
+ }
+ if (QGuiApplicationPrivate::screen_list.removeOne(ps->screen()) && qApp) {
+ Q_EMIT qApp->screenRemoved(ps->screen());
+ }
+}
+
QStringList QPlatformIntegration::themeNames() const
{
return QStringList();
diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h
index d510240..5ec7896 100644
--- a/src/gui/kernel/qplatformintegration.h
+++ b/src/gui/kernel/qplatformintegration.h
@@ -169,7 +169,8 @@ public:
#endif
protected:
- void screenAdded(QPlatformScreen *screen);
+ void screenAdded(QPlatformScreen *screen, bool isPrimary = false);
+ void screenRemoved(QPlatformScreen *screen);
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformscreen.cpp b/src/gui/kernel/qplatformscreen.cpp
index 71710d1..4fb7114 100644
--- a/src/gui/kernel/qplatformscreen.cpp
+++ b/src/gui/kernel/qplatformscreen.cpp
@@ -52,8 +52,6 @@ QPlatformScreen::QPlatformScreen()
QPlatformScreen::~QPlatformScreen()
{
Q_D(QPlatformScreen);
-
- QGuiApplicationPrivate::screen_list.removeOne(d->screen);
delete d->screen;
}
diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp
index ed6e8dd..8909eed 100644
--- a/src/gui/kernel/qscreen.cpp
+++ b/src/gui/kernel/qscreen.cpp
@@ -66,16 +66,6 @@ QScreen::QScreen(QPlatformScreen *screen)
{
}
-
-/*!
- Destroys the screen.
- */
-QScreen::~QScreen()
-{
- if (qApp)
- Q_EMIT qApp->screenRemoved(this);
-}
-
/*!
Get the platform screen handle.
*/
diff --git a/src/gui/kernel/qscreen.h b/src/gui/kernel/qscreen.h
index 766b3d8..144730a 100644
--- a/src/gui/kernel/qscreen.h
+++ b/src/gui/kernel/qscreen.h
@@ -81,7 +81,6 @@ class Q_GUI_EXPORT QScreen : public QObject
Q_PROPERTY(qreal refreshRate READ refreshRate NOTIFY refreshRateChanged)
public:
- ~QScreen();
QPlatformScreen *handle() const;
QString name() const;
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp
index f56a29d..0dca2da 100644
--- a/src/plugins/platforms/xcb/qxcbclipboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp
@@ -276,7 +276,7 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c)
m_timestamp[QClipboard::Clipboard] = XCB_CURRENT_TIME;
m_timestamp[QClipboard::Selection] = XCB_CURRENT_TIME;
- m_screen = connection()->primaryScreen();
+ QXcbScreen * screen = connection()->primaryScreen();
int x = 0, y = 0, w = 3, h = 3;
@@ -284,11 +284,11 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c)
Q_XCB_CALL(xcb_create_window(xcb_connection(),
XCB_COPY_FROM_PARENT, // depth -- same as root
m_owner, // window id
- m_screen->screen()->root, // parent window id
+ screen->screen()->root, // parent window id
x, y, w, h,
0, // border width
XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class
- m_screen->screen()->root_visual, // visual
+ screen->screen()->root_visual, // visual
0, // value mask
0)); // value list
#ifndef QT_NO_DEBUG
@@ -462,8 +462,15 @@ bool QXcbClipboard::ownsMode(QClipboard::Mode mode) const
return m_timestamp[mode] != XCB_CURRENT_TIME;
}
+QXcbScreen *QXcbClipboard::screen() const
+{
+ return connection()->primaryScreen();
+}
+
xcb_window_t QXcbClipboard::requestor() const
{
+ QXcbScreen * screen = connection()->primaryScreen();
+
if (!m_requestor) {
const int x = 0, y = 0, w = 3, h = 3;
QXcbClipboard *that = const_cast<QXcbClipboard *>(this);
@@ -472,11 +479,11 @@ xcb_window_t QXcbClipboard::requestor() const
Q_XCB_CALL(xcb_create_window(xcb_connection(),
XCB_COPY_FROM_PARENT, // depth -- same as root
window, // window id
- m_screen->screen()->root, // parent window id
+ screen->screen()->root, // parent window id
x, y, w, h,
0, // border width
XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class
- m_screen->screen()->root_visual, // visual
+ screen->screen()->root_visual, // visual
0, // value mask
0)); // value list
#ifndef QT_NO_DEBUG
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.h b/src/plugins/platforms/xcb/qxcbclipboard.h
index e76d502..b6cbda4 100644
--- a/src/plugins/platforms/xcb/qxcbclipboard.h
+++ b/src/plugins/platforms/xcb/qxcbclipboard.h
@@ -59,7 +59,7 @@ public:
bool supportsMode(QClipboard::Mode mode) const;
bool ownsMode(QClipboard::Mode mode) const;
- QXcbScreen *screen() const { return m_screen; }
+ QXcbScreen *screen() const;
xcb_window_t requestor() const;
void setRequestor(xcb_window_t window);
@@ -91,8 +91,6 @@ private:
xcb_atom_t atomForMode(QClipboard::Mode mode) const;
QClipboard::Mode modeForAtom(xcb_atom_t atom) const;
- QXcbScreen *m_screen;
-
// Selection and Clipboard
QXcbClipboardMime *m_xClipboard[2];
QMimeData *m_clientClipboard[2];
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 5510c3b..c9600f0 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -182,7 +182,6 @@ QXcbScreen* QXcbConnection::findOrCreateScreen(QList<QXcbScreen *>& newScreens,
void QXcbConnection::updateScreens()
{
xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup);
- int screenNumber = 0; // index of this QScreen in QGuiApplication::screens()
int xcbScreenNumber = 0; // screen number in the xcb sense
QSet<QXcbScreen *> activeScreens;
QList<QXcbScreen *> newScreens;
@@ -194,7 +193,7 @@ void QXcbConnection::updateScreens()
// which will become virtual siblings.
xcb_screen_t *xcbScreen = it.data;
QList<QPlatformScreen *> siblings;
- int outputCount = 0;
+ int outputCount = 0, connectedOutputCount = 0;
if (has_randr_extension) {
xcb_generic_error_t *error = NULL;
xcb_randr_get_output_primary_cookie_t primaryCookie =
@@ -239,7 +238,7 @@ void QXcbConnection::updateScreens()
QXcbScreen *screen = findOrCreateScreen(newScreens, xcbScreenNumber, xcbScreen, output);
siblings << screen;
activeScreens << screen;
- ++screenNumber;
+ ++connectedOutputCount;
// There can be multiple outputs per screen, use either
// the first or an exact match. An exact match isn't
// always available if primary->output is XCB_NONE
@@ -262,7 +261,7 @@ void QXcbConnection::updateScreens()
}
// If there's no randr extension, or there was some error above, or the screen
// doesn't have outputs for some other reason (e.g. on VNC or ssh -X), just assume there is one screen.
- if (outputCount == 0) {
+ if (connectedOutputCount == 0) {
#ifdef Q_XCB_DEBUG
qDebug("Found a screen with zero outputs");
#endif
@@ -271,7 +270,6 @@ void QXcbConnection::updateScreens()
activeScreens << screen;
if (!primaryScreen)
primaryScreen = screen;
- ++screenNumber;
}
foreach (QPlatformScreen* s, siblings)
((QXcbScreen*)s)->setVirtualSiblings(siblings);
@@ -279,28 +277,39 @@ void QXcbConnection::updateScreens()
++xcbScreenNumber;
} // for each xcb screen
- // Now activeScreens is the complete set of screens which are active at this time.
- // Delete any existing screens which are not in activeScreens
+ // Rebuild screen list, ensuring primary screen is always in front,
+ // both in the QXcbConnection::m_screens list as well as in the
+ // QGuiApplicationPrivate::screen_list list, which gets updated via
+ // - screen added: ((QXcbIntegration*)QGuiApplicationPrivate::platformIntegration())->screenAdded();
+ // - screen removed: QPlatformScreen::~QPlatformScreen() via QXcbScreen::~QXcbScreen()
+
+ // Gather screens to delete
+ QList<QXcbScreen*> screensToDelete;
for (int i = m_screens.count() - 1; i >= 0; --i) {
if (!activeScreens.contains(m_screens[i])) {
- delete m_screens[i];
- m_screens.removeAt(i);
+ screensToDelete.append(m_screens.takeAt(i));
}
}
- // Add any new screens, and make sure the primary screen comes first
- // since it is used by QGuiApplication::primaryScreen()
+ // If there is a new primary screen, add that one first
+ if (newScreens.contains(primaryScreen)) {
+ newScreens.removeOne(primaryScreen);
+
+ m_screens.prepend(primaryScreen);
+ ((QXcbIntegration*)QGuiApplicationPrivate::platformIntegration())->screenAdded(primaryScreen, true);
+ }
+
+ // Add the remaining new screens
foreach (QXcbScreen* screen, newScreens) {
- if (screen == primaryScreen)
- m_screens.prepend(screen);
- else
- m_screens.append(screen);
+ m_screens.append(screen);
+ ((QXcbIntegration*)QGuiApplicationPrivate::platformIntegration())->screenAdded(screen);
}
- // Now that they are in the right order, emit the added signals for new screens only
- foreach (QXcbScreen* screen, m_screens)
- if (newScreens.contains(screen))
- ((QXcbIntegration*)QGuiApplicationPrivate::platformIntegration())->screenAdded(screen);
+ // And finally, delete the old screens, now that the new ones were added and we are sure that there is at least one screen available
+ foreach (QXcbScreen* screen, screensToDelete) {
+ ((QXcbIntegration*)QGuiApplicationPrivate::platformIntegration())->screenRemoved(screen);
+ delete screen;
+ }
}
QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, const char *displayName)
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 0094278..44d33e1 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -257,9 +257,7 @@ QXcbWindow::QXcbWindow(QWindow *window)
, m_syncState(NoSyncNeeded)
, m_pendingSyncRequest(0)
{
- m_screen = static_cast<QXcbScreen *>(window->screen()->handle());
-
- setConnection(m_screen->connection());
+ setConnection(xcbscreen()->connection());
if (window->type() != Qt::ForeignWindow)
create();
@@ -298,11 +296,13 @@ void QXcbWindow::create()
Qt::WindowType type = window()->type();
+ QXcbScreen* screen = this->xcbscreen();
+
if (type == Qt::Desktop) {
- m_window = m_screen->root();
- m_depth = m_screen->screen()->root_depth;
- m_visualId = m_screen->screen()->root_visual;
- const xcb_visualtype_t *visual = m_screen->visualForId(m_visualId);
+ m_window = screen->root();
+ m_depth = screen->screen()->root_depth;
+ m_visualId = screen->screen()->root_visual;
+ const xcb_visualtype_t *visual = screen->visualForId(m_visualId);
m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask);
connection()->addWindowEventListener(m_window, this);
return;
@@ -343,7 +343,7 @@ void QXcbWindow::create()
rect.setHeight(defaultWindowHeight);
}
- xcb_window_t xcb_parent_id = m_screen->root();
+ xcb_window_t xcb_parent_id = screen->root();
if (parent()) {
xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window();
m_embedded = parent()->window()->type() == Qt::ForeignWindow;
@@ -358,7 +358,7 @@ void QXcbWindow::create()
#if (defined(XCB_USE_GLX) || defined(XCB_USE_EGL)) && defined(XCB_USE_XLIB)
if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) {
#if defined(XCB_USE_GLX)
- XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen), m_screen->screenNumber(), &m_format);
+ XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(screen), screen->screenNumber(), &m_format);
#elif defined(XCB_USE_EGL)
EGLDisplay eglDisplay = connection()->egl_display();
EGLConfig eglConfig = q_configFromGLFormat(eglDisplay, m_format, true);
@@ -387,8 +387,8 @@ void QXcbWindow::create()
Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), xcb_parent_id, visualInfo->visual, AllocNone);
XSetWindowAttributes a;
- a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber());
- a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber());
+ a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(this), screen->screenNumber());
+ a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(this), screen->screenNumber());
a.colormap = cmap;
m_visualId = visualInfo->visualid;
@@ -407,14 +407,14 @@ void QXcbWindow::create()
#endif //defined(XCB_USE_GLX) || defined(XCB_USE_EGL)
{
m_window = xcb_generate_id(xcb_connection());
- m_visualId = m_screen->screen()->root_visual;
- m_depth = m_screen->screen()->root_depth;
+ m_visualId = screen->screen()->root_visual;
+ m_depth = screen->screen()->root_depth;
uint32_t mask = 0;
uint32_t values[3];
if (m_format.alphaBufferSize() == 8) {
- xcb_depth_iterator_t depthIter = xcb_screen_allowed_depths_iterator(m_screen->screen());
+ xcb_depth_iterator_t depthIter = xcb_screen_allowed_depths_iterator(screen->screen());
while (depthIter.rem) {
if (depthIter.data->depth == 32) {
xcb_visualtype_iterator_t visualIter = xcb_depth_visuals_iterator(depthIter.data);
@@ -425,8 +425,8 @@ void QXcbWindow::create()
xcb_create_colormap(xcb_connection(), XCB_COLORMAP_ALLOC_NONE, colormap,
xcb_parent_id, m_visualId);
mask |= XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP;
- values[0] = m_screen->screen()->white_pixel;
- values[1] = m_screen->screen()->black_pixel;
+ values[0] = screen->screen()->white_pixel;
+ values[1] = screen->screen()->black_pixel;
values[2] = colormap;
break;
}
@@ -435,7 +435,7 @@ void QXcbWindow::create()
}
}
- const xcb_visualtype_t *visual = m_screen->visualForId(m_visualId);
+ const xcb_visualtype_t *visual = screen->visualForId(m_visualId);
m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask);
Q_XCB_CALL(xcb_create_window(xcb_connection(),
@@ -465,7 +465,7 @@ void QXcbWindow::create()
properties[propertyCount++] = atom(QXcbAtom::WM_TAKE_FOCUS);
properties[propertyCount++] = atom(QXcbAtom::_NET_WM_PING);
- m_usingSyncProtocol = m_screen->syncRequestSupported();
+ m_usingSyncProtocol = screen->syncRequestSupported();
#if !defined(XCB_USE_GLX)
// synced resize only implemented on GLX
if (window()->supportsOpenGL())
@@ -524,7 +524,7 @@ void QXcbWindow::create()
xcb_set_wm_hints(xcb_connection(), m_window, &hints);
- xcb_window_t leader = m_screen->clientLeader();
+ xcb_window_t leader = screen->clientLeader();
Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
atom(QXcbAtom::WM_CLIENT_LEADER), XCB_ATOM_WINDOW, 32,
1, &leader));
@@ -550,7 +550,7 @@ void QXcbWindow::create()
#ifdef XCB_USE_XLIB
// force sync to read outstanding requests - see QTBUG-29106
- XSync(DISPLAY_FROM_XCB(m_screen), false);
+ XSync(DISPLAY_FROM_XCB(screen), false);
#endif
#ifndef QT_NO_DRAGANDDROP
@@ -744,7 +744,7 @@ void QXcbWindow::show()
// Default to client leader if there is no transient parent, else modal dialogs can
// be hidden by their parents.
if (!transientXcbParent)
- transientXcbParent = static_cast<QXcbScreen *>(screen())->clientLeader();
+ transientXcbParent = static_cast<QXcbScreen *>(xcbscreen())->clientLeader();
if (transientXcbParent) { // ICCCM 4.1.2.6
Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32,
@@ -772,7 +772,7 @@ void QXcbWindow::show()
if (QGuiApplication::modalWindow() == window())
requestActivateWindow();
- m_screen->windowShown(this);
+ xcbscreen()->windowShown(this);
connection()->sync();
}
@@ -784,10 +784,10 @@ void QXcbWindow::hide()
// send synthetic UnmapNotify event according to icccm 4.1.4
xcb_unmap_notify_event_t event;
event.response_type = XCB_UNMAP_NOTIFY;
- event.event = m_screen->root();
+ event.event = xcbscreen()->root();
event.window = m_window;
event.from_configure = false;
- Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_screen->root(),
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xcbscreen()->root(),
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
xcb_flush(xcb_connection());
@@ -1107,7 +1107,7 @@ void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two)
event.data.data32[3] = 0;
event.data.data32[4] = 0;
- Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, xcbscreen()->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
}
void QXcbWindow::setWindowState(Qt::WindowState state)
@@ -1148,7 +1148,7 @@ void QXcbWindow::setWindowState(Qt::WindowState state)
event.data.data32[3] = 0;
event.data.data32[4] = 0;
- Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, xcbscreen()->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
}
break;
case Qt::WindowMaximized:
@@ -1391,7 +1391,7 @@ void QXcbWindow::setParent(const QPlatformWindow *parent)
xcb_parent_id = qXcbParent->xcb_window();
m_embedded = qXcbParent->window()->type() == Qt::ForeignWindow;
} else {
- xcb_parent_id = m_screen->root();
+ xcb_parent_id = xcbscreen()->root();
m_embedded = false;
}
Q_XCB_CALL(xcb_reparent_window(xcb_connection(), xcb_window(), xcb_parent_id, topLeft.x(), topLeft.y()));
@@ -1559,7 +1559,7 @@ void QXcbWindow::requestActivateWindow()
event.data.data32[3] = 0;
event.data.data32[4] = 0;
- Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, xcbscreen()->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
} else {
Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, connection()->time()));
}
@@ -1796,15 +1796,15 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
relayFocusToModalWindow();
return;
} else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_PING)) {
- if (event->window == m_screen->root())
+ if (event->window == xcbscreen()->root())
return;
xcb_client_message_event_t reply = *event;
reply.response_type = XCB_CLIENT_MESSAGE;
- reply.window = m_screen->root();
+ reply.window = xcbscreen()->root();
- xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&reply);
+ xcb_send_event(xcb_connection(), 0, xcbscreen()->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&reply);
xcb_flush(xcb_connection());
} else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_SYNC_REQUEST)) {
connection()->setTime(event->data.data32[1]);
@@ -1871,7 +1871,7 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
if (!parent() && !fromSendEvent) {
// Do not trust the position, query it instead.
xcb_translate_coordinates_cookie_t cookie = xcb_translate_coordinates(xcb_connection(), xcb_window(),
- m_screen->root(), 0, 0);
+ xcbscreen()->root(), 0, 0);
xcb_translate_coordinates_reply_t *reply = xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL);
if (reply) {
pos.setX(reply->dst_x);
@@ -1888,8 +1888,7 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
QWindowSystemInterface::handleGeometryChange(window(), rect);
QPlatformScreen *newScreen = screenForNativeGeometry(nativeRect);
- if (newScreen != m_screen) {
- m_screen = static_cast<QXcbScreen*>(newScreen);
+ if (newScreen != screen()) {
QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen());
int newDpr = devicePixelRatio();
if (newDpr != dpr) {
@@ -1933,7 +1932,7 @@ QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const
const int dpr = int(devicePixelRatio());
QPoint ret;
xcb_translate_coordinates_cookie_t cookie =
- xcb_translate_coordinates(xcb_connection(), xcb_window(), m_screen->root(),
+ xcb_translate_coordinates(xcb_connection(), xcb_window(), xcbscreen()->root(),
pos.x() * dpr, pos.y() * dpr);
xcb_translate_coordinates_reply_t *reply =
xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL);
@@ -1954,7 +1953,7 @@ QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const
const int dpr = int(devicePixelRatio());
QPoint ret;
xcb_translate_coordinates_cookie_t cookie =
- xcb_translate_coordinates(xcb_connection(), m_screen->root(), xcb_window(),
+ xcb_translate_coordinates(xcb_connection(), xcbscreen()->root(), xcb_window(),
pos.x() *dpr, pos.y() * dpr);
xcb_translate_coordinates_reply_t *reply =
xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL);
@@ -2178,8 +2177,8 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
m_windowState = newState;
}
return;
- } else if (event->atom == atom(QXcbAtom::_NET_WORKAREA) && event->window == m_screen->root()) {
- m_screen->updateGeometry(event->time);
+ } else if (event->atom == atom(QXcbAtom::_NET_WORKAREA) && event->window == xcbscreen()->root()) {
+ xcbscreen()->updateGeometry(event->time);
}
}
@@ -2308,7 +2307,7 @@ bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
xev.data.data32[3] = XCB_BUTTON_INDEX_1;
xev.data.data32[4] = 0;
xcb_ungrab_pointer(connection()->xcb_connection(), XCB_CURRENT_TIME);
- xcb_send_event(connection()->xcb_connection(), false, m_screen->root(),
+ xcb_send_event(connection()->xcb_connection(), false, xcbscreen()->root(),
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
(const char *)&xev);
return true;
@@ -2444,13 +2443,18 @@ void QXcbWindow::postSyncWindowRequest()
if (!m_pendingSyncRequest) {
QXcbSyncWindowRequest *e = new QXcbSyncWindowRequest(this);
m_pendingSyncRequest = e;
- QCoreApplication::postEvent(m_screen->connection(), e);
+ QCoreApplication::postEvent(xcbscreen()->connection(), e);
}
}
qreal QXcbWindow::devicePixelRatio() const
{
- return m_screen ? m_screen->devicePixelRatio() : 1.0;
+ return xcbscreen() ? xcbscreen()->devicePixelRatio() : 1.0;
+}
+
+QXcbScreen *QXcbWindow::xcbscreen() const
+{
+ return static_cast<QXcbScreen *>(screen());
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 254421e..966a834 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -152,6 +152,8 @@ public:
void postSyncWindowRequest();
void clearSyncWindowRequest() { m_pendingSyncRequest = 0; }
+ QXcbScreen *xcbscreen() const;
+
qreal devicePixelRatio() const;
QPlatformScreen *screenForNativeGeometry(const QRect &newGeometry) const;
@@ -188,8 +190,6 @@ private:
void doFocusIn();
void doFocusOut();
- QXcbScreen *m_screen;
-
xcb_window_t m_window;
uint m_depth;