Notify when the primary screen changes

Makes it possible to notify that the QGuiApplication::primaryScreen has
changed.
XCB backend adopts the new API, as it was accessing QGuiApplication private
API directly.

Change-Id: Icde05c44138265f865fa42d2cd6974c552fdc5e2
Task-number: QTBUG-38404
Task-number: QTBUG-40659
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@theqtcompany.com>
Reviewed-by: Shawn Rutledge <shawn.rutledge@theqtcompany.com>
This commit is contained in:
Aleix Pol 2015-09-04 16:52:04 +02:00 committed by Aleix Pol Gonzalez
parent fd2067b67b
commit 8cbaea441a
9 changed files with 76 additions and 8 deletions

View File

@ -921,6 +921,18 @@ QList<QScreen *> QGuiApplication::screens()
\since 5.4
*/
/*!
\fn void QGuiApplication::primaryScreenChanged(QScreen *screen)
This signal is emitted whenever the primary \a screen changes. This way
applications can keep track of the primaryScreen and react if there is a
new primary screen.
\sa primaryScreen
\since 5.6
*/
/*!
Returns the highest screen device pixel ratio found on

View File

@ -70,6 +70,7 @@ class Q_GUI_EXPORT QGuiApplication : public QCoreApplication
Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged)
Q_PROPERTY(QString platformName READ platformName STORED false)
Q_PROPERTY(bool quitOnLastWindowClosed READ quitOnLastWindowClosed WRITE setQuitOnLastWindowClosed)
Q_PROPERTY(QScreen *primaryScreen READ primaryScreen NOTIFY primaryScreenChanged STORED false)
public:
#ifdef Q_QDOC
@ -158,6 +159,7 @@ Q_SIGNALS:
void fontDatabaseChanged();
void screenAdded(QScreen *screen);
void screenRemoved(QScreen *screen);
void primaryScreenChanged(QScreen *screen);
void lastWindowClosed();
void focusObjectChanged(QObject *focusObject);
void focusWindowChanged(QWindow *focusWindow);

View File

@ -456,6 +456,24 @@ void QPlatformIntegration::screenAdded(QPlatformScreen *ps, bool isPrimary)
QGuiApplicationPrivate::screen_list.append(screen);
}
emit qGuiApp->screenAdded(screen);
if (isPrimary)
emit qGuiApp->primaryScreenChanged(screen);
}
/*!
Just removes the screen, call destroyScreen instead.
\sa destroyScreen()
*/
void QPlatformIntegration::removeScreen(QScreen *screen)
{
const bool wasPrimary = (!QGuiApplicationPrivate::screen_list.isEmpty() && QGuiApplicationPrivate::screen_list[0] == screen);
QGuiApplicationPrivate::screen_list.removeOne(screen);
if (wasPrimary && qGuiApp && !QGuiApplicationPrivate::screen_list.isEmpty())
emit qGuiApp->primaryScreenChanged(QGuiApplicationPrivate::screen_list[0]);
}
/*!
@ -469,11 +487,30 @@ void QPlatformIntegration::screenAdded(QPlatformScreen *ps, bool isPrimary)
void QPlatformIntegration::destroyScreen(QPlatformScreen *screen)
{
QScreen *qScreen = screen->screen();
QGuiApplicationPrivate::screen_list.removeOne(qScreen);
removeScreen(qScreen);
delete qScreen;
delete screen;
}
/*!
Should be called whenever the primary screen changes.
When the screen specified as primary changes, this method will notify
QGuiApplication and emit the QGuiApplication::primaryScreenChanged signal.
*/
void QPlatformIntegration::setPrimaryScreen(QPlatformScreen *newPrimary)
{
QScreen* newPrimaryScreen = newPrimary->screen();
int idx = QGuiApplicationPrivate::screen_list.indexOf(newPrimaryScreen);
Q_ASSERT(idx >= 0);
if (idx == 0)
return;
QGuiApplicationPrivate::screen_list.swap(0, idx);
emit qGuiApp->primaryScreenChanged(newPrimaryScreen);
}
QStringList QPlatformIntegration::themeNames() const
{
return QStringList();

View File

@ -172,9 +172,13 @@ public:
virtual QOpenGLContext::OpenGLModuleType openGLModuleType();
#endif
virtual void setApplicationIcon(const QIcon &icon) const;
void removeScreen(QScreen *screen);
protected:
void screenAdded(QPlatformScreen *screen, bool isPrimary = false);
void destroyScreen(QPlatformScreen *screen);
void setPrimaryScreen(QPlatformScreen *newPrimary);
};
QT_END_NAMESPACE

View File

@ -56,7 +56,7 @@ QPlatformScreen::~QPlatformScreen()
Q_D(QPlatformScreen);
if (d->screen) {
qWarning("Manually deleting a QPlatformScreen. Call QPlatformIntegration::destroyScreen instead.");
QGuiApplicationPrivate::screen_list.removeOne(d->screen);
QGuiApplicationPrivate::platformIntegration()->removeScreen(d->screen);
delete d->screen;
}
}

View File

@ -305,13 +305,10 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event)
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);
const int idx = m_screens.indexOf(screen);
m_screens.swap(0, idx);
QXcbIntegration::instance()->setPrimaryScreen(screen);
}
qCDebug(lcQpaScreen) << "output has changed" << screen;
}

View File

@ -134,6 +134,7 @@ QDesktopWidget::QDesktopWidget()
setObjectName(QLatin1String("desktop"));
d->_q_updateScreens();
connect(qApp, SIGNAL(screenAdded(QScreen*)), this, SLOT(_q_updateScreens()));
connect(qApp, SIGNAL(primaryScreenChanged(QScreen*)), this, SIGNAL(primaryScreenChanged()));
}
QDesktopWidget::~QDesktopWidget()

View File

@ -77,6 +77,7 @@ Q_SIGNALS:
void resized(int);
void workAreaResized(int);
void screenCountChanged(int);
void primaryScreenChanged();
protected:
void resizeEvent(QResizeEvent *e) Q_DECL_OVERRIDE;

View File

@ -271,3 +271,17 @@
\sa screenCount
*/
/*!
\fn void QDesktopWidget::primaryScreenChanged()
\since 5.6
\brief This signal is emitted whenever the primary screen changes.
\note This doesn't mean the QDesktopWidget::primaryScreen index will
necessarily be different, but now it will refer to the new primary screen.
\sa primaryScreen, screenGeometry()
*/