diff options
-rw-r--r-- | examples/quick/window/AllScreens.qml | 75 | ||||
-rw-r--r-- | examples/quick/window/CurrentScreen.qml (renamed from examples/quick/window/ScreenInfo.qml) | 3 | ||||
-rw-r--r-- | examples/quick/window/doc/src/window.qdoc | 2 | ||||
-rw-r--r-- | examples/quick/window/window.qml | 15 | ||||
-rw-r--r-- | examples/quick/window/window.qrc | 3 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 14 | ||||
-rw-r--r-- | src/quick/items/qquickscreen.cpp | 195 | ||||
-rw-r--r-- | src/quick/items/qquickscreen_p.h | 48 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 22 | ||||
-rw-r--r-- | src/quick/items/qquickwindowmodule.cpp | 25 | ||||
-rw-r--r-- | src/quick/items/qquickwindowmodule_p.h | 5 | ||||
-rw-r--r-- | src/quick/util/qquickapplication.cpp | 34 | ||||
-rw-r--r-- | src/quick/util/qquickapplication_p.h | 9 | ||||
-rw-r--r-- | tests/auto/quick/qquickscreen/data/screen.qml | 14 | ||||
-rw-r--r-- | tests/auto/quick/qquickscreen/tst_qquickscreen.cpp | 40 | ||||
-rw-r--r-- | tests/auto/quick/qquickwindow/data/windowWithScreen.qml | 10 | ||||
-rw-r--r-- | tests/auto/quick/qquickwindow/tst_qquickwindow.cpp | 19 |
17 files changed, 433 insertions, 100 deletions
diff --git a/examples/quick/window/AllScreens.qml b/examples/quick/window/AllScreens.qml new file mode 100644 index 0000000000..83a6c5f958 --- /dev/null +++ b/examples/quick/window/AllScreens.qml @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.3 +import QtQuick.Window 2.3 +import "../shared" as Shared + +Column { + id: root + spacing: 8 + + Shared.Label { + text: "Total number of screens: " + screenInfo.count + font.bold: true + } + + Flow { + spacing: 12 + width: parent.width + + Repeater { + id: screenInfo + model: Qt.application.screens + Shared.Label { + lineHeight: 1.5 + text: name + "\n" + virtualX + ", " + virtualY + " " + modelData.width + "x" + modelData.height + } + } + } + + Component.onCompleted: { + var screens = Qt.application.screens; + for (var i = 0; i < screens.length; ++i) + console.log("screen " + screens[i].name + " has geometry " + + screens[i].virtualX + ", " + screens[i].virtualY + " " + + screens[i].width + "x" + screens[i].height) + } +} diff --git a/examples/quick/window/ScreenInfo.qml b/examples/quick/window/CurrentScreen.qml index 7d7cd946c5..c65baab1f4 100644 --- a/examples/quick/window/ScreenInfo.qml +++ b/examples/quick/window/CurrentScreen.qml @@ -92,6 +92,9 @@ Item { Shared.Label { text: "available virtual desktop" } Shared.Label { text: Screen.desktopAvailableWidth + "x" + Screen.desktopAvailableHeight } + Shared.Label { text: "position in virtual desktop" } + Shared.Label { text: Screen.virtualX + ", " + Screen.virtualY } + Shared.Label { text: "orientation" } Shared.Label { text: orientationToString(Screen.orientation) + " (" + Screen.orientation + ")" } diff --git a/examples/quick/window/doc/src/window.qdoc b/examples/quick/window/doc/src/window.qdoc index 5cd51beceb..2028b31383 100644 --- a/examples/quick/window/doc/src/window.qdoc +++ b/examples/quick/window/doc/src/window.qdoc @@ -73,7 +73,7 @@ \l Screen has several properties which are generally useful to applications which need to rotate some content when the screen orientation changes, to position windows on the screen or to convert real units to - logical pixel units. ScreenInfo.qml (which is displayed inline in + logical pixel units. CurrentScreen.qml (which is displayed inline in window.qml, or can be run by itself with qmlscene) simply displays the property values, while the splash screen uses them to center the window on the screen. diff --git a/examples/quick/window/window.qml b/examples/quick/window/window.qml index f3052a7d62..d27ab3d0a3 100644 --- a/examples/quick/window/window.qml +++ b/examples/quick/window/window.qml @@ -39,7 +39,7 @@ ****************************************************************************/ import QtQuick 2.0 -import QtQuick.Window 2.1 +import QtQuick.Window 2.3 import "../shared" as Shared QtObject { @@ -47,7 +47,7 @@ QtObject { property SystemPalette palette: SystemPalette { } property var controlWindow: Window { - width: visibilityLabel.implicitWidth * 1.2 + width: col.implicitWidth + defaultSpacing * 2 height: col.implicitHeight + defaultSpacing * 2 color: palette.window title: "Control Window" @@ -127,12 +127,17 @@ QtObject { " and has visibility " + parent.visibilityToString(testWindow.visibility) } Rectangle { - id: horizontalRule - color: "black" + color: palette.text width: parent.width height: 1 } - ScreenInfo { } + CurrentScreen { } + Rectangle { + color: palette.text + width: parent.width + height: 1 + } + AllScreens { width: parent.width } } } diff --git a/examples/quick/window/window.qrc b/examples/quick/window/window.qrc index dc211bdaaf..89d1de1b1f 100644 --- a/examples/quick/window/window.qrc +++ b/examples/quick/window/window.qrc @@ -2,6 +2,7 @@ <qresource prefix="/window"> <file>window.qml</file> <file>Splash.qml</file> - <file>ScreenInfo.qml</file> + <file>CurrentScreen.qml</file> + <file>AllScreens.qml</file> </qresource> </RCC> diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 01f1f93b81..daa12fae26 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -554,6 +554,18 @@ The following functions are also on the Qt object. \li This read-only property can be used to determine whether or not the platform supports multiple windows. Some embedded platforms do not support multiple windows, for example. + + \row + \li \c application.screens + \li An array containing the descriptions of all connected screens. The + elements of the array are objects with the same properties as the + \l{Screen} attached object. In practice the array corresponds to the screen + list returned by QGuiApplication::screens(). In addition to examining + properties like name, width, height, etc., the array elements can also be + assigned to the targetScreen property of Window items, thus serving as an + alternative to the C++ side's QWindow::setScreen(). This property has been + added in Qt 5.9. + \endtable The object also has one signal, aboutToQuit(), which is the same as \l QCoreApplication::aboutToQuit(). @@ -570,6 +582,8 @@ The following functions are also on the Qt object. \li application.layoutDirection \li application.font \endlist + + \sa Screen, Window, Window.targetScreen */ /*! diff --git a/src/quick/items/qquickscreen.cpp b/src/quick/items/qquickscreen.cpp index 5d01a2af9d..9347b55c70 100644 --- a/src/quick/items/qquickscreen.cpp +++ b/src/quick/items/qquickscreen.cpp @@ -207,100 +207,181 @@ QT_BEGIN_NAMESPACE By default it is set to the value of the QScreen that the window uses. */ -QQuickScreenAttached::QQuickScreenAttached(QObject* attachee) - : QObject(attachee) - , m_screen(NULL) - , m_window(NULL) - , m_updateMask(0) - , m_updateMaskSet(false) +QQuickScreenInfo::QQuickScreenInfo(QObject *parent) + : QObject(parent), + m_screen(nullptr) { - m_attachee = qobject_cast<QQuickItem*>(attachee); - - if (m_attachee) { - QQuickItemPrivate::get(m_attachee)->extra.value().screenAttached = this; - - if (m_attachee->window()) //It might not be assigned to a window yet - windowChanged(m_attachee->window()); - } else { - QQuickWindow *window = qobject_cast<QQuickWindow*>(attachee); - if (window) - windowChanged(window); - } - - if (!m_screen) - screenChanged(QGuiApplication::primaryScreen()); } -QString QQuickScreenAttached::name() const +QString QQuickScreenInfo::name() const { if (!m_screen) return QString(); return m_screen->name(); } -int QQuickScreenAttached::width() const +int QQuickScreenInfo::width() const { if (!m_screen) return 0; return m_screen->size().width(); } -int QQuickScreenAttached::height() const +int QQuickScreenInfo::height() const { if (!m_screen) return 0; return m_screen->size().height(); } -int QQuickScreenAttached::desktopAvailableWidth() const +int QQuickScreenInfo::desktopAvailableWidth() const { if (!m_screen) return 0; return m_screen->availableVirtualSize().width(); } -int QQuickScreenAttached::desktopAvailableHeight() const +int QQuickScreenInfo::desktopAvailableHeight() const { if (!m_screen) return 0; return m_screen->availableVirtualSize().height(); } -qreal QQuickScreenAttached::logicalPixelDensity() const +qreal QQuickScreenInfo::logicalPixelDensity() const { if (!m_screen) return 0.0; return m_screen->logicalDotsPerInch() / 25.4; } -qreal QQuickScreenAttached::pixelDensity() const +qreal QQuickScreenInfo::pixelDensity() const { if (!m_screen) return 0.0; return m_screen->physicalDotsPerInch() / 25.4; } -qreal QQuickScreenAttached::devicePixelRatio() const +qreal QQuickScreenInfo::devicePixelRatio() const { if (!m_screen) return 1.0; return m_screen->devicePixelRatio(); } -Qt::ScreenOrientation QQuickScreenAttached::primaryOrientation() const +Qt::ScreenOrientation QQuickScreenInfo::primaryOrientation() const { if (!m_screen) return Qt::PrimaryOrientation; return m_screen->primaryOrientation(); } -Qt::ScreenOrientation QQuickScreenAttached::orientation() const +Qt::ScreenOrientation QQuickScreenInfo::orientation() const { if (!m_screen) return Qt::PrimaryOrientation; return m_screen->orientation(); } +int QQuickScreenInfo::virtualX() const +{ + if (!m_screen) + return 0; + return m_screen->geometry().topLeft().x(); +} + +int QQuickScreenInfo::virtualY() const +{ + if (!m_screen) + return 0; + return m_screen->geometry().topLeft().y(); +} + +void QQuickScreenInfo::setWrappedScreen(QScreen *screen) +{ + if (screen == m_screen) + return; + + QScreen *oldScreen = m_screen; + m_screen = screen; + + if (oldScreen) + oldScreen->disconnect(this); + + if (!screen) //Don't bother emitting signals, because the new values are garbage anyways + return; + + if (!oldScreen || screen->geometry() != oldScreen->geometry()) { + emit virtualXChanged(); + emit virtualYChanged(); + } + if (!oldScreen || screen->size() != oldScreen->size()) { + emit widthChanged(); + emit heightChanged(); + } + if (!oldScreen || screen->name() != oldScreen->name()) + emit nameChanged(); + if (!oldScreen || screen->orientation() != oldScreen->orientation()) + emit orientationChanged(); + if (!oldScreen || screen->primaryOrientation() != oldScreen->primaryOrientation()) + emit primaryOrientationChanged(); + if (!oldScreen || screen->availableVirtualGeometry() != oldScreen->availableVirtualGeometry()) + emit desktopGeometryChanged(); + if (!oldScreen || screen->logicalDotsPerInch() != oldScreen->logicalDotsPerInch()) + emit logicalPixelDensityChanged(); + if (!oldScreen || screen->physicalDotsPerInch() != oldScreen->physicalDotsPerInch()) + emit pixelDensityChanged(); + if (!oldScreen || screen->devicePixelRatio() != oldScreen->devicePixelRatio()) + emit devicePixelRatioChanged(); + + connect(screen, SIGNAL(geometryChanged(QRect)), + this, SIGNAL(widthChanged())); + connect(screen, SIGNAL(geometryChanged(QRect)), + this, SIGNAL(heightChanged())); + connect(screen, SIGNAL(geometryChanged(QRect)), + this, SIGNAL(virtualXChanged())); + connect(screen, SIGNAL(geometryChanged(QRect)), + this, SIGNAL(virtualYChanged())); + connect(screen, SIGNAL(orientationChanged(Qt::ScreenOrientation)), + this, SIGNAL(orientationChanged())); + connect(screen, SIGNAL(primaryOrientationChanged(Qt::ScreenOrientation)), + this, SIGNAL(primaryOrientationChanged())); + connect(screen, SIGNAL(virtualGeometryChanged(QRect)), + this, SIGNAL(desktopGeometryChanged())); + connect(screen, SIGNAL(logicalDotsPerInchChanged(qreal)), + this, SIGNAL(logicalPixelDensityChanged())); + connect(screen, SIGNAL(physicalDotsPerInchChanged(qreal)), + this, SIGNAL(pixelDensityChanged())); +} + +QScreen *QQuickScreenInfo::wrappedScreen() const +{ + return m_screen; +} + +QQuickScreenAttached::QQuickScreenAttached(QObject* attachee) + : QQuickScreenInfo(attachee) + , m_window(NULL) + , m_updateMask(0) + , m_updateMaskSet(false) +{ + m_attachee = qobject_cast<QQuickItem*>(attachee); + + if (m_attachee) { + QQuickItemPrivate::get(m_attachee)->extra.value().screenAttached = this; + + if (m_attachee->window()) //It might not be assigned to a window yet + windowChanged(m_attachee->window()); + } else { + QQuickWindow *window = qobject_cast<QQuickWindow*>(attachee); + if (window) + windowChanged(window); + } + + if (!m_screen) + screenChanged(QGuiApplication::primaryScreen()); +} + Qt::ScreenOrientations QQuickScreenAttached::orientationUpdateMask() const { return m_updateMask; @@ -341,55 +422,15 @@ void QQuickScreenAttached::screenChanged(QScreen *screen) { //qDebug() << "QQuickScreenAttached::screenChanged" << (screen ? screen->name() : QString::fromLatin1("null")); if (screen != m_screen) { - QScreen* oldScreen = m_screen; - m_screen = screen; - - if (oldScreen) - oldScreen->disconnect(this); - - if (!screen) - return; //Don't bother emitting signals, because the new values are garbage anyways - + setWrappedScreen(screen); + if (!m_screen) + return; if (m_updateMaskSet) { - screen->setOrientationUpdateMask(m_updateMask); - } else if (m_updateMask != screen->orientationUpdateMask()) { - m_updateMask = screen->orientationUpdateMask(); + m_screen->setOrientationUpdateMask(m_updateMask); + } else if (m_updateMask != m_screen->orientationUpdateMask()) { + m_updateMask = m_screen->orientationUpdateMask(); emit orientationUpdateMaskChanged(); } - - if (!oldScreen || screen->size() != oldScreen->size()) { - emit widthChanged(); - emit heightChanged(); - } - if (!oldScreen || screen->name() != oldScreen->name()) - emit nameChanged(); - if (!oldScreen || screen->orientation() != oldScreen->orientation()) - emit orientationChanged(); - if (!oldScreen || screen->primaryOrientation() != oldScreen->primaryOrientation()) - emit primaryOrientationChanged(); - if (!oldScreen || screen->availableVirtualGeometry() != oldScreen->availableVirtualGeometry()) - emit desktopGeometryChanged(); - if (!oldScreen || screen->logicalDotsPerInch() != oldScreen->logicalDotsPerInch()) - emit logicalPixelDensityChanged(); - if (!oldScreen || screen->physicalDotsPerInch() != oldScreen->physicalDotsPerInch()) - emit pixelDensityChanged(); - if (!oldScreen || screen->devicePixelRatio() != oldScreen->devicePixelRatio()) - emit devicePixelRatioChanged(); - - connect(screen, SIGNAL(geometryChanged(QRect)), - this, SIGNAL(widthChanged())); - connect(screen, SIGNAL(geometryChanged(QRect)), - this, SIGNAL(heightChanged())); - connect(screen, SIGNAL(orientationChanged(Qt::ScreenOrientation)), - this, SIGNAL(orientationChanged())); - connect(screen, SIGNAL(primaryOrientationChanged(Qt::ScreenOrientation)), - this, SIGNAL(primaryOrientationChanged())); - connect(screen, SIGNAL(virtualGeometryChanged(QRect)), - this, SIGNAL(desktopGeometryChanged())); - connect(screen, SIGNAL(logicalDotsPerInchChanged(qreal)), - this, SIGNAL(logicalPixelDensityChanged())); - connect(screen, SIGNAL(physicalDotsPerInchChanged(qreal)), - this, SIGNAL(pixelDensityChanged())); } } diff --git a/src/quick/items/qquickscreen_p.h b/src/quick/items/qquickscreen_p.h index 06d9a06070..06efb3ab45 100644 --- a/src/quick/items/qquickscreen_p.h +++ b/src/quick/items/qquickscreen_p.h @@ -63,10 +63,10 @@ class QQuickItem; class QQuickWindow; class QScreen; -class Q_AUTOTEST_EXPORT QQuickScreenAttached : public QObject + +class Q_AUTOTEST_EXPORT QQuickScreenInfo : public QObject { Q_OBJECT - Q_PROPERTY(QString name READ name NOTIFY nameChanged) Q_PROPERTY(int width READ width NOTIFY widthChanged) Q_PROPERTY(int height READ height NOTIFY heightChanged) @@ -79,11 +79,12 @@ class Q_AUTOTEST_EXPORT QQuickScreenAttached : public QObject Q_PROPERTY(Qt::ScreenOrientation primaryOrientation READ primaryOrientation NOTIFY primaryOrientationChanged) // TODO Qt 6 Remove this orientation -> incomplete device orientation -> better use OrientationSensor Q_PROPERTY(Qt::ScreenOrientation orientation READ orientation NOTIFY orientationChanged) - Q_PROPERTY(Qt::ScreenOrientations orientationUpdateMask READ orientationUpdateMask - WRITE setOrientationUpdateMask NOTIFY orientationUpdateMaskChanged) + + Q_PROPERTY(int virtualX READ virtualX NOTIFY virtualXChanged REVISION 1) + Q_PROPERTY(int virtualY READ virtualY NOTIFY virtualYChanged REVISION 1) public: - QQuickScreenAttached(QObject* attachee); + QQuickScreenInfo(QObject *parent = nullptr); QString name() const; int width() const; @@ -95,13 +96,11 @@ public: qreal devicePixelRatio() const; Qt::ScreenOrientation primaryOrientation() const; Qt::ScreenOrientation orientation() const; - Qt::ScreenOrientations orientationUpdateMask() const; - void setOrientationUpdateMask(Qt::ScreenOrientations mask); + int virtualX() const; + int virtualY() const; - //Treats int as Qt::ScreenOrientation, due to QTBUG-20639 - Q_INVOKABLE int angleBetween(int a, int b); - - void windowChanged(QQuickWindow*); + void setWrappedScreen(QScreen *screen); + QScreen *wrappedScreen() const; Q_SIGNALS: void nameChanged(); @@ -113,13 +112,37 @@ Q_SIGNALS: void devicePixelRatioChanged(); void primaryOrientationChanged(); void orientationChanged(); + Q_REVISION(1) void virtualXChanged(); + Q_REVISION(1) void virtualYChanged(); + +protected: + QPointer<QScreen> m_screen; +}; + +class Q_AUTOTEST_EXPORT QQuickScreenAttached : public QQuickScreenInfo +{ + Q_OBJECT + Q_PROPERTY(Qt::ScreenOrientations orientationUpdateMask READ orientationUpdateMask + WRITE setOrientationUpdateMask NOTIFY orientationUpdateMaskChanged) + +public: + QQuickScreenAttached(QObject* attachee); + + Qt::ScreenOrientations orientationUpdateMask() const; + void setOrientationUpdateMask(Qt::ScreenOrientations mask); + + //Treats int as Qt::ScreenOrientation, due to QTBUG-20639 + Q_INVOKABLE int angleBetween(int a, int b); + + void windowChanged(QQuickWindow*); + +Q_SIGNALS: void orientationUpdateMaskChanged(); protected Q_SLOTS: void screenChanged(QScreen*); private: - QPointer<QScreen> m_screen; QQuickWindow* m_window; QQuickItem* m_attachee; Qt::ScreenOrientations m_updateMask; @@ -136,5 +159,6 @@ public: QT_END_NAMESPACE QML_DECLARE_TYPEINFO(QQuickScreen, QML_HAS_ATTACHED_PROPERTIES) +QML_DECLARE_TYPE(QQuickScreenInfo) #endif diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 45341643be..dc0bd51a9a 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -4146,6 +4146,28 @@ void QQuickWindow::resetOpenGLState() */ /*! + \qmlproperty variant Window::targetScreen + + Specifies the screen the window should be placed on. Equivalent to + QWindow::setScreen(). + + The value must be an element from the Qt.application.screens array. + + By default the value is null which leads to using the primary screen. + + \note To ensure that the window is associated with the desired screen right + upon the underlying native window's initial creation, make sure this + property is set as early as possible and that the setting of its value is + not deferred. This can be particularly important on embedded platforms + without a windowing system, where only one window per screen is allowed at a + time. + + \since 5.9 + + \sa QWindow::setScreen(), QScreen, Qt.application + */ + +/*! \qmlproperty Item Window::activeFocusItem \since 5.1 diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp index c624d162a9..8ab2cee96f 100644 --- a/src/quick/items/qquickwindowmodule.cpp +++ b/src/quick/items/qquickwindowmodule.cpp @@ -58,6 +58,7 @@ public: : complete(false) , visible(false) , visibility(QQuickWindow::AutomaticVisibility) + , targetScreen(nullptr) { } @@ -65,6 +66,7 @@ public: bool visible; QQuickWindow::Visibility visibility; QV4::PersistentValue rootItemMarker; + QObject *targetScreen; }; QQuickWindowQmlImpl::QQuickWindowQmlImpl(QWindow *parent) @@ -170,6 +172,26 @@ void QQuickWindowQmlImpl::setWindowVisibility() } } +QObject *QQuickWindowQmlImpl::targetScreen() const +{ + Q_D(const QQuickWindowQmlImpl); + return d->targetScreen; +} + +void QQuickWindowQmlImpl::setTargetScreen(QObject *screen) +{ + Q_D(QQuickWindowQmlImpl); + if (d->targetScreen != screen) { + d->targetScreen = screen; + emit targetScreenChanged(); + QQuickScreenInfo *screenWrapper = qobject_cast<QQuickScreenInfo *>(screen); + if (screenWrapper) + setScreen(screenWrapper->wrappedScreen()); + else + setScreen(nullptr); + } +} + void QQuickWindowModule::defineModule() { const char uri[] = "QtQuick.Window"; @@ -181,7 +203,10 @@ void QQuickWindowModule::defineModule() qmlRegisterRevision<QQuickWindow,2>(uri, 2, 2); qmlRegisterType<QQuickWindowQmlImpl>(uri, 2, 1, "Window"); qmlRegisterType<QQuickWindowQmlImpl,1>(uri, 2, 2, "Window"); + qmlRegisterType<QQuickWindowQmlImpl,2>(uri, 2, 3, "Window"); qmlRegisterUncreatableType<QQuickScreen>(uri, 2, 0, "Screen", QStringLiteral("Screen can only be used via the attached property.")); + qmlRegisterUncreatableType<QQuickScreen,1>(uri, 2, 3, "Screen", QStringLiteral("Screen can only be used via the attached property.")); + qmlRegisterUncreatableType<QQuickScreenInfo,2>(uri, 2, 3, "ScreenInfo", QStringLiteral("ScreenInfo can only be used via the attached property.")); } QT_END_NAMESPACE diff --git a/src/quick/items/qquickwindowmodule_p.h b/src/quick/items/qquickwindowmodule_p.h index 8a6bbac412..7ca29880ea 100644 --- a/src/quick/items/qquickwindowmodule_p.h +++ b/src/quick/items/qquickwindowmodule_p.h @@ -67,6 +67,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickWindowQmlImpl : public QQuickWindow, public Q Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged) Q_PROPERTY(Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged) + Q_PROPERTY(QObject *targetScreen READ targetScreen WRITE setTargetScreen NOTIFY targetScreenChanged REVISION 2) public: QQuickWindowQmlImpl(QWindow *parent = Q_NULLPTR); @@ -74,11 +75,15 @@ public: void setVisible(bool visible); void setVisibility(Visibility visibility); + QObject *targetScreen() const; + void setTargetScreen(QObject *screen); + static QQuickWindowAttached *qmlAttachedProperties(QObject *object); Q_SIGNALS: void visibleChanged(bool arg); void visibilityChanged(QWindow::Visibility visibility); + Q_REVISION(2) void targetScreenChanged(); protected: void classBegin() Q_DECL_OVERRIDE; diff --git a/src/quick/util/qquickapplication.cpp b/src/quick/util/qquickapplication.cpp index 5c26b23ff7..ca4a5bfb56 100644 --- a/src/quick/util/qquickapplication.cpp +++ b/src/quick/util/qquickapplication.cpp @@ -38,7 +38,7 @@ ****************************************************************************/ #include "qquickapplication_p.h" - +#include <private/qquickscreen_p.h> #include <private/qobject_p.h> #include <private/qguiapplication_p.h> #include <qpa/qplatformintegration.h> @@ -63,6 +63,10 @@ QQuickApplication::QQuickApplication(QObject *parent) this, SIGNAL(stateChanged(Qt::ApplicationState))); connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)), this, SIGNAL(activeChanged())); + + connect(qApp, &QGuiApplication::screenAdded, this, &QQuickApplication::updateScreens); + connect(qApp, &QGuiApplication::screenRemoved, this, &QQuickApplication::updateScreens); + updateScreens(); } } @@ -95,4 +99,32 @@ QFont QQuickApplication::font() const return QGuiApplication::font(); } +int screens_count(QQmlListProperty<QQuickScreenInfo> *prop) +{ + return static_cast<QVector<QQuickScreenInfo *> *>(prop->data)->count(); +} + +QQuickScreenInfo *screens_at(QQmlListProperty<QQuickScreenInfo> *prop, int idx) +{ + return static_cast<QVector<QQuickScreenInfo *> *>(prop->data)->at(idx); +} + +QQmlListProperty<QQuickScreenInfo> QQuickApplication::screens() +{ + return QQmlListProperty<QQuickScreenInfo>(this, + const_cast<QVector<QQuickScreenInfo *> *>(&m_screens), &screens_count, &screens_at); +} + +void QQuickApplication::updateScreens() +{ + const QList<QScreen *> screenList = QGuiApplication::screens(); + m_screens.resize(screenList.count()); + for (int i = 0; i < screenList.count(); ++i) { + if (!m_screens[i]) + m_screens[i] = new QQuickScreenInfo(this); + m_screens[i]->setWrappedScreen(screenList[i]); + } + emit screensChanged(); +} + QT_END_NAMESPACE diff --git a/src/quick/util/qquickapplication_p.h b/src/quick/util/qquickapplication_p.h index 091cb094ed..70381553b4 100644 --- a/src/quick/util/qquickapplication_p.h +++ b/src/quick/util/qquickapplication_p.h @@ -56,10 +56,10 @@ #include <qqml.h> #include <QtQml/private/qqmlglobal_p.h> #include <private/qtquickglobal_p.h> +#include "../items/qquickscreen_p.h" QT_BEGIN_NAMESPACE - class Q_AUTOTEST_EXPORT QQuickApplication : public QQmlApplication { Q_OBJECT @@ -68,6 +68,7 @@ class Q_AUTOTEST_EXPORT QQuickApplication : public QQmlApplication Q_PROPERTY(bool supportsMultipleWindows READ supportsMultipleWindows CONSTANT) Q_PROPERTY(Qt::ApplicationState state READ state NOTIFY stateChanged) Q_PROPERTY(QFont font READ font CONSTANT) + Q_PROPERTY(QQmlListProperty<QQuickScreenInfo> screens READ screens NOTIFY screensChanged) public: explicit QQuickApplication(QObject *parent = 0); @@ -77,14 +78,20 @@ public: bool supportsMultipleWindows() const; Qt::ApplicationState state() const; QFont font() const; + QQmlListProperty<QQuickScreenInfo> screens(); Q_SIGNALS: void activeChanged(); void layoutDirectionChanged(); void stateChanged(Qt::ApplicationState state); + void screensChanged(); + +private Q_SLOTS: + void updateScreens(); private: Q_DISABLE_COPY(QQuickApplication) + QVector<QQuickScreenInfo *> m_screens; }; QT_END_NAMESPACE diff --git a/tests/auto/quick/qquickscreen/data/screen.qml b/tests/auto/quick/qquickscreen/data/screen.qml index c246b3cd83..cf60d0ae40 100644 --- a/tests/auto/quick/qquickscreen/data/screen.qml +++ b/tests/auto/quick/qquickscreen/data/screen.qml @@ -1,5 +1,5 @@ import QtQuick 2.0 -import QtQuick.Window 2.0 as Window +import QtQuick.Window 2.3 as Window Item { width: 100 @@ -10,6 +10,18 @@ Item { property int priOrientation: Window.Screen.primaryOrientation property int updateMask: Window.Screen.orientationUpdateMask property real devicePixelRatio: Window.Screen.devicePixelRatio + property int vx: Window.Screen.virtualX + property int vy: Window.Screen.virtualY Window.Screen.orientationUpdateMask: Qt.LandscapeOrientation | Qt.InvertedLandscapeOrientation + + property int screenCount: Qt.application.screens.length + + property variant allScreens + Component.onCompleted: { + allScreens = []; + var s = Qt.application.screens; + for (var i = 0; i < s.length; ++i) + allScreens.push(s[i]); + } } diff --git a/tests/auto/quick/qquickscreen/tst_qquickscreen.cpp b/tests/auto/quick/qquickscreen/tst_qquickscreen.cpp index 92afdf6864..26b687a4a6 100644 --- a/tests/auto/quick/qquickscreen/tst_qquickscreen.cpp +++ b/tests/auto/quick/qquickscreen/tst_qquickscreen.cpp @@ -33,13 +33,15 @@ #include <QtQuick/QQuickView> #include <QtGui/QScreen> #include "../../shared/util.h" - +#include <QtQuick/private/qquickscreen_p.h> +#include <QDebug> class tst_qquickscreen : public QQmlDataTest { Q_OBJECT private slots: void basicProperties(); void screenOnStartup(); + void fullScreenList(); }; void tst_qquickscreen::basicProperties() @@ -62,6 +64,10 @@ void tst_qquickscreen::basicProperties() QCOMPARE(int(screen->orientationUpdateMask()), root->property("updateMask").toInt()); QCOMPARE(screen->devicePixelRatio(), root->property("devicePixelRatio").toReal()); QVERIFY(screen->devicePixelRatio() >= 1.0); + QCOMPARE(screen->geometry().x(), root->property("vx").toInt()); + QCOMPARE(screen->geometry().y(), root->property("vy").toInt()); + + QVERIFY(root->property("screenCount").toInt() == QGuiApplication::screens().count()); } void tst_qquickscreen::screenOnStartup() @@ -83,6 +89,38 @@ void tst_qquickscreen::screenOnStartup() QCOMPARE(int(screen->orientationUpdateMask()), root->property("updateMask").toInt()); QCOMPARE(screen->devicePixelRatio(), root->property("devicePixelRatio").toReal()); QVERIFY(screen->devicePixelRatio() >= 1.0); + QCOMPARE(screen->geometry().x(), root->property("vx").toInt()); + QCOMPARE(screen->geometry().y(), root->property("vy").toInt()); +} + +void tst_qquickscreen::fullScreenList() +{ + QQuickView view; + view.setSource(testFileUrl("screen.qml")); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QQuickItem* root = view.rootObject(); + QVERIFY(root); + + QJSValue screensArray = root->property("allScreens").value<QJSValue>(); + QVERIFY(screensArray.isArray()); + int length = screensArray.property("length").toInt(); + const QList<QScreen *> screenList = QGuiApplication::screens(); + QVERIFY(length == screenList.count()); + + for (int i = 0; i < length; ++i) { + QQuickScreenInfo *info = qobject_cast<QQuickScreenInfo *>(screensArray.property(i).toQObject()); + QVERIFY(info != nullptr); + QCOMPARE(screenList[i]->name(), info->name()); + QCOMPARE(screenList[i]->size().width(), info->width()); + QCOMPARE(screenList[i]->size().height(), info->height()); + QCOMPARE(screenList[i]->availableVirtualGeometry().width(), info->desktopAvailableWidth()); + QCOMPARE(screenList[i]->availableVirtualGeometry().height(), info->desktopAvailableHeight()); + QCOMPARE(screenList[i]->devicePixelRatio(), info->devicePixelRatio()); + QCOMPARE(screenList[i]->geometry().x(), info->virtualX()); + QCOMPARE(screenList[i]->geometry().y(), info->virtualY()); + } } QTEST_MAIN(tst_qquickscreen) diff --git a/tests/auto/quick/qquickwindow/data/windowWithScreen.qml b/tests/auto/quick/qquickwindow/data/windowWithScreen.qml new file mode 100644 index 0000000000..fdc0be3388 --- /dev/null +++ b/tests/auto/quick/qquickwindow/data/windowWithScreen.qml @@ -0,0 +1,10 @@ +import QtQuick 2.0 +import QtQuick.Window 2.3 as Window + +Window.Window { + color: "#00FF00" + targetScreen: Qt.application.screens[0] + Item { + objectName: "item" + } +} diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index acccac8eca..bfffa6f7f5 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -311,6 +311,7 @@ private slots: void clearWindow(); void qmlCreation(); + void qmlCreationWithScreen(); void clearColor(); void defaultState(); @@ -1122,6 +1123,24 @@ void tst_qquickwindow::qmlCreation() QCOMPARE(item->window(), window); } +void tst_qquickwindow::qmlCreationWithScreen() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("windowWithScreen.qml")); + QObject *created = component.create(); + QScopedPointer<QObject> cleanup(created); + QVERIFY(created); + + QQuickWindow *window = qobject_cast<QQuickWindow*>(created); + QVERIFY(window); + QCOMPARE(window->color(), QColor(Qt::green)); + + QQuickItem *item = window->findChild<QQuickItem*>("item"); + QVERIFY(item); + QCOMPARE(item->window(), window); +} + void tst_qquickwindow::clearColor() { //::grab examines rendering to make sure it works visually |