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>bb10
parent
3cda2ab03a
commit
9b4fbe85d2
|
|
@ -439,7 +439,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)
|
||||
{
|
||||
|
|
@ -449,6 +449,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();
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ public:
|
|||
|
||||
protected:
|
||||
void screenAdded(QPlatformScreen *screen);
|
||||
void destroyScreen(QPlatformScreen *screen);
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ QKmsIntegration::~QKmsIntegration()
|
|||
delete device;
|
||||
}
|
||||
foreach (QPlatformScreen *screen, m_screens) {
|
||||
delete screen;
|
||||
destroyScreen(screen);
|
||||
}
|
||||
delete m_fontDatabase;
|
||||
delete m_vtHandler;
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ QLinuxFbIntegration::QLinuxFbIntegration(const QStringList ¶mList)
|
|||
|
||||
QLinuxFbIntegration::~QLinuxFbIntegration()
|
||||
{
|
||||
delete m_primaryScreen;
|
||||
destroyScreen(m_primaryScreen);
|
||||
}
|
||||
|
||||
void QLinuxFbIntegration::initialize()
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ QMinimalEglIntegration::QMinimalEglIntegration()
|
|||
|
||||
QMinimalEglIntegration::~QMinimalEglIntegration()
|
||||
{
|
||||
delete mScreen;
|
||||
destroyScreen(mScreen);
|
||||
}
|
||||
|
||||
bool QMinimalEglIntegration::hasCapability(QPlatformIntegration::Capability cap) const
|
||||
|
|
|
|||
|
|
@ -133,3 +133,8 @@ void QOpenWFDIntegration::addScreen(QOpenWFDScreen *screen)
|
|||
{
|
||||
screenAdded(screen);
|
||||
}
|
||||
|
||||
void QOpenWFDIntegration::destroyScreen(QOpenWFDScreen *screen)
|
||||
{
|
||||
QPlatformIntegration::destroyScreen(screen);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ public:
|
|||
QPlatformPrinterSupport *printerSupport() const;
|
||||
|
||||
void addScreen(QOpenWFDScreen *screen);
|
||||
void destroyScreen(QOpenWFDScreen *screen);
|
||||
private:
|
||||
QList<QPlatformScreen *> mScreens;
|
||||
QList<QOpenWFDDevice *>mDevices;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -240,11 +240,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);
|
||||
}
|
||||
}
|
||||
|
|
@ -261,7 +262,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)
|
||||
|
|
@ -400,9 +401,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_XLIB
|
||||
XCloseDisplay((Display *)m_xlib_display);
|
||||
|
|
|
|||
Loading…
Reference in New Issue