Skip to content

Commit

Permalink
Add a function for QPA plugins to explicitly destroy QScreens
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Shawn Rutledge <[email protected]>
  • Loading branch information
giucam committed Dec 23, 2014
1 parent 3cda2ab commit 9b4fbe8
Show file tree
Hide file tree
Showing 16 changed files with 52 additions and 21 deletions.
18 changes: 17 additions & 1 deletion src/gui/kernel/qplatformintegration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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();
Expand Down
1 change: 1 addition & 0 deletions src/gui/kernel/qplatformintegration.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ class Q_GUI_EXPORT QPlatformIntegration

protected:
void screenAdded(QPlatformScreen *screen);
void destroyScreen(QPlatformScreen *screen);
};

QT_END_NAMESPACE
Expand Down
8 changes: 5 additions & 3 deletions src/gui/kernel/qplatformscreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

/*!
Expand Down
4 changes: 2 additions & 2 deletions src/plugins/platforms/cocoa/qcocoaintegration.mm
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ static void initResources()

// Delete screens in reverse order to avoid crash in case of multiple screens
while (!mScreens.isEmpty()) {
delete mScreens.takeLast();
destroyScreen(mScreens.takeLast());
}

clearToolbars();
Expand Down Expand Up @@ -397,7 +397,7 @@ static void initResources()
// 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)
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/platforms/ios/qiosintegration.mm
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@
m_inputContext = 0;

foreach (QScreen *screen, QGuiApplication::screens())
delete screen->handle();
destroyScreen(screen->handle());

delete m_platformServices;
m_platformServices = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/platforms/kms/qkmsintegration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ QKmsIntegration::~QKmsIntegration()
delete device;
}
foreach (QPlatformScreen *screen, m_screens) {
delete screen;
destroyScreen(screen);
}
delete m_fontDatabase;
delete m_vtHandler;
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ QLinuxFbIntegration::QLinuxFbIntegration(const QStringList &paramList)

QLinuxFbIntegration::~QLinuxFbIntegration()
{
delete m_primaryScreen;
destroyScreen(m_primaryScreen);
}

void QLinuxFbIntegration::initialize()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ QMinimalEglIntegration::QMinimalEglIntegration()

QMinimalEglIntegration::~QMinimalEglIntegration()
{
delete mScreen;
destroyScreen(mScreen);
}

bool QMinimalEglIntegration::hasCapability(QPlatformIntegration::Capability cap) const
Expand Down
5 changes: 5 additions & 0 deletions src/plugins/platforms/openwfd/qopenwfdintegration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,8 @@ void QOpenWFDIntegration::addScreen(QOpenWFDScreen *screen)
{
screenAdded(screen);
}

void QOpenWFDIntegration::destroyScreen(QOpenWFDScreen *screen)
{
QPlatformIntegration::destroyScreen(screen);
}
1 change: 1 addition & 0 deletions src/plugins/platforms/openwfd/qopenwfdintegration.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class QOpenWFDIntegration : public QPlatformIntegration
QPlatformPrinterSupport *printerSupport() const;

void addScreen(QOpenWFDScreen *screen);
void destroyScreen(QOpenWFDScreen *screen);
private:
QList<QPlatformScreen *> mScreens;
QList<QOpenWFDDevice *>mDevices;
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/platforms/openwfd/qopenwfdport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/platforms/qnx/qqnxintegration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
1 change: 1 addition & 0 deletions src/plugins/platforms/windows/qwindowsintegration.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class QWindowsIntegration : public QPlatformIntegration
static QWindowsIntegration *instance();

inline void emitScreenAdded(QPlatformScreen *s) { screenAdded(s); }
inline void emitDestroyScreen(QPlatformScreen *s) { destroyScreen(s); }

unsigned options() const;

Expand Down
9 changes: 8 additions & 1 deletion src/plugins/platforms/windows/qwindowsscreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

/*!
Expand Down Expand Up @@ -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
6 changes: 1 addition & 5 deletions src/plugins/platforms/windows/qwindowsscreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,7 @@ class QWindowsScreenManager

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);
Expand Down
8 changes: 5 additions & 3 deletions src/plugins/platforms/xcb/qxcbconnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 9b4fbe8

Please sign in to comment.