From f4c1ae672652bc908ea1e0a8e353557b392940d7 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 5 Sep 2012 14:22:31 +0200 Subject: [PATCH] Added manual test for QScreen properties MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Shows property values in fields which auto-update when the properties change. Change-Id: Ib97566a74cb8d0fff5f85bf97783e89dfb07481f Reviewed-by: Samuel Rødal --- tests/manual/manual.pro | 1 + tests/manual/qscreen/README | 41 ++++++++++++ tests/manual/qscreen/main.cpp | 105 +++++++++++++++++++++++++++++++ tests/manual/qscreen/propertyfield.cpp | 102 ++++++++++++++++++++++++++++++ tests/manual/qscreen/propertyfield.h | 76 ++++++++++++++++++++++ tests/manual/qscreen/propertywatcher.cpp | 86 +++++++++++++++++++++++++ tests/manual/qscreen/propertywatcher.h | 72 +++++++++++++++++++++ tests/manual/qscreen/qscreen.pro | 12 ++++ 8 files changed, 495 insertions(+) create mode 100644 tests/manual/qscreen/README create mode 100644 tests/manual/qscreen/main.cpp create mode 100644 tests/manual/qscreen/propertyfield.cpp create mode 100644 tests/manual/qscreen/propertyfield.h create mode 100644 tests/manual/qscreen/propertywatcher.cpp create mode 100644 tests/manual/qscreen/propertywatcher.h create mode 100644 tests/manual/qscreen/qscreen.pro diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro index 42f753a..6aff45a 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -18,6 +18,7 @@ qlocale \ qnetworkaccessmanager/qget \ qnetworkconfigurationmanager \ qnetworkreply \ +qscreen \ qssloptions \ qtabletevent \ qtbug-8933 \ diff --git a/tests/manual/qscreen/README b/tests/manual/qscreen/README new file mode 100644 index 0000000..5f5da17 --- /dev/null +++ b/tests/manual/qscreen/README @@ -0,0 +1,41 @@ +To test whether QScreen properties are updated properly when the screen +actually changes, you will need to run some kind of control panel to make +changes, and this test program at the same time. E.g. on Linux, you can use +xrandr with various parameters on the command line, but there is also a nice +GUI called arandr which will probably work on any distro. Real-world users +would probably use the Gnome or KDE control panels, so that's also a good way +to test. On OSX you can make changes in System Preferences | Displays, and you +can also configure it to put a "monitors" icon on the menubar with a drop-down +menu for convenience. On Windows you can right-click on the desktop to get +display settings. + +Note that on Linux, if you have one graphics card with two outputs, typically +the two monitors connected to the outputs are combined into a single virtual +"screen", but each screen has multiple outputs. In that case there will be a +unique QScreen for each output, and they will be virtual siblings. The virtual +geometry depends on how you arrange the monitors (second one is to the right, +or above the first one, for example). It should be about the same if you are +using two graphics cards but using Xinerama to combine them. This test app will +create two windows, and will center one each screen, by setting the geometry. + +Alternatively you can configure xorg.conf to create separate screens for each +graphics card; then the mouse cursor can move between the screens, but +application windows cannot: each app needs to be started up on the screen that +you want to run it on. In either case, ideally this test app ought to create +two windows, one on each screen; but in fact, it can do that only if the +screens are virtual siblings. If they are on different Displays, the second +Display is not accessible to the QXcbConnection instance which was createad on +the first Display. It can be considered a known bug that the API appears to +make this possible (you would think QWindow::setScreen might work) but it +isn't possible. + +The physical size of the screen is considered to be a constant. This can create +discrepancies in DPI when orientation is changed, or when the screen is +actually a VNC server and you change the resolution. So maybe +QScreen::physicalSize should also have a notifier, but that doesn't physically +make sense except when the screen is virtual. + +Another case is running two separate X servers on two graphics cards. In that +case they really do not know about each other, even at the xlib/xcb level, so +this test is irrelevant. You can run the test independently on each X server, +but you will just get one QScreen instance on each. diff --git a/tests/manual/qscreen/main.cpp b/tests/manual/qscreen/main.cpp new file mode 100644 index 0000000..2a95cbc --- /dev/null +++ b/tests/manual/qscreen/main.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "propertywatcher.h" +#include +#include +#include +#include +#include +#include + +int i = 0; + +void updateSiblings(PropertyWatcher* w) +{ + QLineEdit *siblingsField = w->findChild("siblings"); + QScreen* screen = (QScreen*)w->subject(); + QStringList siblingsList; + foreach (QScreen *sibling, screen->virtualSiblings()) + siblingsList << sibling->name(); + siblingsField->setText(siblingsList.join(", ")); +} + +void screenAdded(QScreen* screen) +{ + screen->setOrientationUpdateMask((Qt::ScreenOrientations)0x0F); + qDebug("\nscreenAdded %s siblings %d first %s", qPrintable(screen->name()), + screen->virtualSiblings().count(), qPrintable(screen->virtualSiblings().first()->name())); + PropertyWatcher *w = new PropertyWatcher(screen, QString::number(i++)); + QLineEdit *siblingsField = new QLineEdit(); + siblingsField->setObjectName("siblings"); + siblingsField->setReadOnly(true); + w->layout()->insertRow(0, "virtualSiblings", siblingsField); + updateSiblings(w); + + // This doesn't work. If the multiple screens are part of + // a virtual desktop (i.e. they are virtual siblings), then + // setScreen has no effect, and we need the code below to + // change the window geometry. If on the other hand the + // screens are really separate, so that windows are not + // portable between them, XCreateWindow needs to have not just + // a different root Window but also a different Display, in order to + // put the window on the other screen. That would require a + // different QXcbConnection. So this setScreen call doesn't seem useful. + //w->windowHandle()->setScreen(screen); + + // But this works as long as the screens are all virtual siblings + w->show(); + QRect geom = w->geometry(); + geom.moveCenter(screen->geometry().center()); + w->move(geom.topLeft()); + + // workaround for the fact that virtualSiblings is not a property, + // thus there is no change notification: + // allow the user to update the field manually + QObject::connect(w, &PropertyWatcher::updatedAllFields, &updateSiblings); +} + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + QList screens = QGuiApplication::screens(); + foreach (QScreen *screen, screens) + screenAdded(screen); + QObject::connect((const QGuiApplication*)QGuiApplication::instance(), &QGuiApplication::screenAdded, &screenAdded); + return a.exec(); +} diff --git a/tests/manual/qscreen/propertyfield.cpp b/tests/manual/qscreen/propertyfield.cpp new file mode 100644 index 0000000..a654946 --- /dev/null +++ b/tests/manual/qscreen/propertyfield.cpp @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "propertyfield.h" +#include + +PropertyField::PropertyField(QObject* subject, const QMetaProperty& prop, QWidget *parent) : + QLineEdit(parent), m_subject(subject), m_lastChangeTime(QTime::currentTime()), m_prop(prop) +{ + setReadOnly(true); + if (prop.hasNotifySignal()) { + QMetaMethod signal = prop.notifySignal(); + QMetaMethod updateSlot = metaObject()->method(metaObject()->indexOfSlot("propertyChanged()")); + connect(m_subject, signal, this, updateSlot); + } + propertyChanged(); +} + +QString PropertyField::valueToString(QVariant val) +{ + QString text = val.toString(); + if (val.type() == QVariant::Size) + text = QString("%1 x %2").arg(val.toSize().width()).arg(val.toSize().height()); + else if (val.type() == QVariant::SizeF) + text = QString("%1 x %2").arg(val.toSizeF().width()).arg(val.toSizeF().height()); + else if (val.type() == QVariant::Rect) + text = QString("%1 x %2 +%3 +%4").arg(val.toRect().width()) + .arg(val.toRect().height()).arg(val.toRect().x()).arg(val.toRect().y()); + return text; +} + +void PropertyField::propertyChanged() +{ + if (m_prop.isReadable()) { + QVariant val = m_prop.read(m_subject); + QString text = valueToString(val); + QPalette modPalette = palette(); + + // If we are seeing a value for the first time, + // pretend it was that way for a while already. + if (m_lastText.isEmpty()) { + m_lastText = text; + m_lastTextShowing = text; + m_lastChangeTime = QTime::currentTime().addSecs(-5); + } + + qDebug() << " " << QString::fromUtf8(m_prop.name()) << ":" << val; + // If the value has recently changed, show the change + if (text != m_lastText || m_lastChangeTime.elapsed() < 1000) { + setText(m_lastTextShowing + " -> " + text); + modPalette.setBrush(QPalette::Text, Qt::red); + m_lastChangeTime.start(); + m_lastText = text; + } + // If the value hasn't changed recently, just show the current value + else { + setText(text); + m_lastText = text; + m_lastTextShowing = text; + modPalette.setBrush(QPalette::Text, Qt::black); + } + setPalette(modPalette); + } +} diff --git a/tests/manual/qscreen/propertyfield.h b/tests/manual/qscreen/propertyfield.h new file mode 100644 index 0000000..21bfb8c --- /dev/null +++ b/tests/manual/qscreen/propertyfield.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PROPERTYFIELD_H +#define PROPERTYFIELD_H + +#include +#include +#include + +/*! + A QLineEdit for viewing the text form of a property on an object. + Automatically stays up-to-date when the property changes. + (This is rather like a QML TextField bound to a property.) + */ +class PropertyField : public QLineEdit +{ + Q_OBJECT +public: + explicit PropertyField(QObject* subject, const QMetaProperty& prop, QWidget *parent = 0); + +signals: + +public slots: + void propertyChanged(); + +protected: + QString valueToString(QVariant val); + +private: + QObject* m_subject; + QString m_lastText; + QString m_lastTextShowing; + QTime m_lastChangeTime; + const QMetaProperty m_prop; +}; + +#endif // PROPERTYFIELD_H diff --git a/tests/manual/qscreen/propertywatcher.cpp b/tests/manual/qscreen/propertywatcher.cpp new file mode 100644 index 0000000..9e55e76 --- /dev/null +++ b/tests/manual/qscreen/propertywatcher.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "propertywatcher.h" +#include +#include +#include +#include "propertyfield.h" + +PropertyWatcher::PropertyWatcher(QObject *subject, QString annotation, QWidget *parent) + : QWidget(parent), m_subject(subject), m_layout(new QFormLayout) +{ + setWindowTitle(QString("Properties of %1 %2 %3") + .arg(subject->metaObject()->className()).arg(subject->objectName()).arg(annotation)); + setMinimumSize(450, 300); + const QMetaObject* meta = m_subject->metaObject(); + + for (int i = 0; i < meta->propertyCount(); ++i) { + QMetaProperty prop = meta->property(i); + if (prop.isReadable()) { + PropertyField* field = new PropertyField(m_subject, prop); + m_layout->addRow(prop.name(), field); + } + } + QPushButton *updateButton = new QPushButton("update"); + connect(updateButton, &QPushButton::clicked, this, &PropertyWatcher::updateAllFields); + m_layout->addRow("", updateButton); + setLayout(m_layout); + connect(subject, &QObject::destroyed, this, &PropertyWatcher::subjectDestroyed); +} + +PropertyWatcher::~PropertyWatcher() +{ +} + +void PropertyWatcher::updateAllFields() +{ + QList fields = findChildren(); + foreach (PropertyField *field, fields) + field->propertyChanged(); + emit updatedAllFields(this); +} + +void PropertyWatcher::subjectDestroyed() +{ + hide(); + deleteLater(); +} diff --git a/tests/manual/qscreen/propertywatcher.h b/tests/manual/qscreen/propertywatcher.h new file mode 100644 index 0000000..4bd91c4 --- /dev/null +++ b/tests/manual/qscreen/propertywatcher.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGET_H +#define WIDGET_H + +#include + +class QLineEdit; +class QFormLayout; + +class PropertyWatcher : public QWidget +{ + Q_OBJECT + +public: + PropertyWatcher(QObject* subject, QString annotation = QString(), QWidget *parent = 0); + ~PropertyWatcher(); + QFormLayout *layout() { return m_layout; } + QObject* subject() { return m_subject; } + +public slots: + void updateAllFields(); + void subjectDestroyed(); + +signals: + void updatedAllFields(PropertyWatcher* sender); + +protected: + QObject* m_subject; + QFormLayout * m_layout; +}; + +#endif // WIDGET_H diff --git a/tests/manual/qscreen/qscreen.pro b/tests/manual/qscreen/qscreen.pro new file mode 100644 index 0000000..cec8bbf --- /dev/null +++ b/tests/manual/qscreen/qscreen.pro @@ -0,0 +1,12 @@ +QT += core gui widgets + +TARGET = qscreen +TEMPLATE = app + +SOURCES += main.cpp \ + propertywatcher.cpp \ + propertyfield.cpp + +HEADERS += \ + propertywatcher.h \ + propertyfield.h -- 2.7.4