e3bbfe00d1
If the next active window is already known at the time a focus out is received, pass it to QWindowSystemInterface. Fixes a test and Qt Creator's locator bar. Task-number: QTBUG-24186 Task-number: QTCREATORBUG-1 Change-Id: I0aed4c386c08ed182555c95640e1637c5b67f5ce Reviewed-by: Miikka Heikkinen <miikka.heikkinen@digia.com> Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com>
499 lines
17 KiB
C++
499 lines
17 KiB
C++
/****************************************************************************
|
|
**
|
|
** 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 <QtTest/QtTest>
|
|
#include <QtGui/QGuiApplication>
|
|
#include <QtGui/QWindow>
|
|
#include <QDebug>
|
|
|
|
class tst_QGuiApplication: public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
private slots:
|
|
void focusObject();
|
|
void allWindows();
|
|
void topLevelWindows();
|
|
void abortQuitOnShow();
|
|
void changeFocusWindow();
|
|
void keyboardModifiers();
|
|
void modalWindow();
|
|
};
|
|
|
|
class DummyWindow : public QWindow
|
|
{
|
|
public:
|
|
DummyWindow() : m_focusObject(0) {}
|
|
|
|
virtual QObject *focusObject() const
|
|
{
|
|
return m_focusObject;
|
|
}
|
|
|
|
void setFocusObject(QObject *object)
|
|
{
|
|
m_focusObject = object;
|
|
emit focusObjectChanged(object);
|
|
}
|
|
|
|
QObject *m_focusObject;
|
|
};
|
|
|
|
|
|
void tst_QGuiApplication::focusObject()
|
|
{
|
|
#ifdef Q_OS_MAC
|
|
QSKIP("This test fails intermittently, and at different locations. See QTBUG-24322");
|
|
#endif
|
|
int argc = 0;
|
|
QGuiApplication app(argc, 0);
|
|
|
|
QObject obj1, obj2, obj3;
|
|
DummyWindow window1;
|
|
DummyWindow window2;
|
|
window1.show();
|
|
|
|
QSignalSpy spy(&app, SIGNAL(focusObjectChanged(QObject *)));
|
|
|
|
|
|
// verify active window focus propagates to qguiapplication
|
|
QTest::qWaitForWindowShown(&window1);
|
|
window1.requestActivateWindow();
|
|
QTRY_COMPARE(app.focusWindow(), &window1);
|
|
|
|
window1.setFocusObject(&obj1);
|
|
QCOMPARE(app.focusObject(), &obj1);
|
|
QCOMPARE(spy.count(), 1);
|
|
|
|
spy.clear();
|
|
window1.setFocusObject(&obj2);
|
|
QCOMPARE(app.focusObject(), &obj2);
|
|
QCOMPARE(spy.count(), 1);
|
|
|
|
spy.clear();
|
|
window2.setFocusObject(&obj3);
|
|
QCOMPARE(app.focusObject(), &obj2); // not yet changed
|
|
window2.show();
|
|
QTest::qWaitForWindowShown(&window2);
|
|
QTRY_COMPARE(app.focusWindow(), &window2);
|
|
QCOMPARE(app.focusObject(), &obj3);
|
|
QCOMPARE(spy.count(), 1);
|
|
|
|
// focus change on unfocused window does not show
|
|
spy.clear();
|
|
window1.setFocusObject(&obj1);
|
|
QCOMPARE(spy.count(), 0);
|
|
QCOMPARE(app.focusObject(), &obj3);
|
|
}
|
|
|
|
void tst_QGuiApplication::allWindows()
|
|
{
|
|
int argc = 0;
|
|
QGuiApplication app(argc, 0);
|
|
QWindow *window1 = new QWindow;
|
|
QWindow *window2 = new QWindow(window1);
|
|
QVERIFY(app.allWindows().contains(window1));
|
|
QVERIFY(app.allWindows().contains(window2));
|
|
QCOMPARE(app.allWindows().count(), 2);
|
|
delete window1;
|
|
window1 = 0;
|
|
window2 = 0;
|
|
QVERIFY(!app.allWindows().contains(window2));
|
|
QVERIFY(!app.allWindows().contains(window1));
|
|
QCOMPARE(app.allWindows().count(), 0);
|
|
}
|
|
|
|
void tst_QGuiApplication::topLevelWindows()
|
|
{
|
|
int argc = 0;
|
|
QGuiApplication app(argc, 0);
|
|
QWindow *window1 = new QWindow;
|
|
QWindow *window2 = new QWindow(window1);
|
|
QVERIFY(app.topLevelWindows().contains(window1));
|
|
QVERIFY(!app.topLevelWindows().contains(window2));
|
|
QCOMPARE(app.topLevelWindows().count(), 1);
|
|
delete window1;
|
|
window1 = 0;
|
|
window2 = 0;
|
|
QVERIFY(!app.topLevelWindows().contains(window2));
|
|
QVERIFY(!app.topLevelWindows().contains(window1));
|
|
QCOMPARE(app.topLevelWindows().count(), 0);
|
|
}
|
|
|
|
class ShowCloseShowWindow : public QWindow
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
ShowCloseShowWindow(bool showAgain, QWindow *parent = 0)
|
|
: QWindow(parent), showAgain(showAgain)
|
|
{
|
|
QTimer::singleShot(0, this, SLOT(doClose()));
|
|
QTimer::singleShot(500, this, SLOT(exitApp()));
|
|
}
|
|
|
|
private slots:
|
|
void doClose() {
|
|
close();
|
|
if (showAgain)
|
|
show();
|
|
}
|
|
|
|
void exitApp() {
|
|
qApp->exit(1);
|
|
}
|
|
|
|
private:
|
|
bool showAgain;
|
|
};
|
|
|
|
void tst_QGuiApplication::abortQuitOnShow()
|
|
{
|
|
int argc = 0;
|
|
QGuiApplication app(argc, 0);
|
|
QWindow *window1 = new ShowCloseShowWindow(false);
|
|
window1->show();
|
|
QCOMPARE(app.exec(), 0);
|
|
|
|
QWindow *window2 = new ShowCloseShowWindow(true);
|
|
window2->show();
|
|
QCOMPARE(app.exec(), 1);
|
|
}
|
|
|
|
|
|
class FocusChangeWindow: public QWindow
|
|
{
|
|
protected:
|
|
virtual bool event(QEvent *ev)
|
|
{
|
|
if (ev->type() == QEvent::FocusAboutToChange)
|
|
windowDuringFocusAboutToChange = qGuiApp->focusWindow();
|
|
return QWindow::event(ev);
|
|
}
|
|
|
|
virtual void focusOutEvent(QFocusEvent *)
|
|
{
|
|
windowDuringFocusOut = qGuiApp->focusWindow();
|
|
}
|
|
|
|
public:
|
|
FocusChangeWindow() : QWindow(), windowDuringFocusAboutToChange(0), windowDuringFocusOut(0) {}
|
|
|
|
QWindow *windowDuringFocusAboutToChange;
|
|
QWindow *windowDuringFocusOut;
|
|
};
|
|
|
|
void tst_QGuiApplication::changeFocusWindow()
|
|
{
|
|
int argc = 0;
|
|
QGuiApplication app(argc, 0);
|
|
|
|
// focus is changed between FocusAboutToChange and FocusChanged
|
|
FocusChangeWindow window1, window2;
|
|
window1.show();
|
|
window2.show();
|
|
QTest::qWaitForWindowShown(&window1);
|
|
QTest::qWaitForWindowShown(&window2);
|
|
window1.requestActivateWindow();
|
|
QTRY_COMPARE(app.focusWindow(), &window1);
|
|
|
|
window2.requestActivateWindow();
|
|
QTRY_COMPARE(app.focusWindow(), &window2);
|
|
QCOMPARE(window1.windowDuringFocusAboutToChange, &window1);
|
|
QCOMPARE(window1.windowDuringFocusOut, &window2);
|
|
}
|
|
|
|
void tst_QGuiApplication::keyboardModifiers()
|
|
{
|
|
int argc = 0;
|
|
QGuiApplication app(argc, 0);
|
|
|
|
QWindow *window = new QWindow;
|
|
window->show();
|
|
QTest::qWaitForWindowShown(window);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
|
|
|
|
// mouse events
|
|
QPoint center = window->geometry().center();
|
|
QTest::mouseEvent(QTest::MousePress, window, Qt::LeftButton, Qt::NoModifier, center);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
|
|
QTest::mouseEvent(QTest::MouseRelease, window, Qt::LeftButton, Qt::NoModifier, center);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
|
|
QTest::mouseEvent(QTest::MousePress, window, Qt::RightButton, Qt::ControlModifier, center);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier);
|
|
QTest::mouseEvent(QTest::MouseRelease, window, Qt::RightButton, Qt::ControlModifier, center);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier);
|
|
|
|
// shortcut events
|
|
QWindowSystemInterface::tryHandleSynchronousShortcutEvent(window, Qt::Key_5, Qt::MetaModifier);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::MetaModifier);
|
|
QWindowSystemInterface::tryHandleSynchronousShortcutEvent(window, Qt::Key_Period, Qt::NoModifier);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
|
|
QWindowSystemInterface::tryHandleSynchronousShortcutEvent(window, Qt::Key_0, Qt::ControlModifier);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier);
|
|
|
|
// key events
|
|
QTest::keyEvent(QTest::Press, window, Qt::Key_C);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
|
|
QTest::keyEvent(QTest::Release, window, Qt::Key_C);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
|
|
|
|
QTest::keyEvent(QTest::Press, window, Qt::Key_U, Qt::ControlModifier);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier);
|
|
QTest::keyEvent(QTest::Release, window, Qt::Key_U, Qt::ControlModifier);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier);
|
|
|
|
QTest::keyEvent(QTest::Press, window, Qt::Key_T);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
|
|
QTest::keyEvent(QTest::Release, window, Qt::Key_T);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
|
|
|
|
QTest::keyEvent(QTest::Press, window, Qt::Key_E, Qt::ControlModifier);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier);
|
|
QTest::keyEvent(QTest::Release, window, Qt::Key_E, Qt::ControlModifier);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier);
|
|
|
|
// wheel events
|
|
QPoint global = window->mapToGlobal(center);
|
|
QPoint delta(0, 1);
|
|
QWindowSystemInterface::handleWheelEvent(window, center, global, delta, delta, Qt::NoModifier);
|
|
QWindowSystemInterface::sendWindowSystemEvents(app.eventDispatcher(), QEventLoop::AllEvents);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
|
|
QWindowSystemInterface::handleWheelEvent(window, center, global, delta, delta, Qt::AltModifier);
|
|
QWindowSystemInterface::sendWindowSystemEvents(app.eventDispatcher(), QEventLoop::AllEvents);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::AltModifier);
|
|
QWindowSystemInterface::handleWheelEvent(window, center, global, delta, delta, Qt::ControlModifier);
|
|
QWindowSystemInterface::sendWindowSystemEvents(app.eventDispatcher(), QEventLoop::AllEvents);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::ControlModifier);
|
|
|
|
// touch events
|
|
QList<const QTouchDevice *> touchDevices = QTouchDevice::devices();
|
|
if (!touchDevices.isEmpty()) {
|
|
QTouchDevice *touchDevice = const_cast<QTouchDevice *>(touchDevices.first());
|
|
QTest::touchEvent(window, touchDevice).press(1, center).release(1, center);
|
|
QCOMPARE(QGuiApplication::keyboardModifiers(), Qt::NoModifier);
|
|
}
|
|
|
|
window->close();
|
|
delete window;
|
|
}
|
|
|
|
class BlockableWindow : public QWindow
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
int blocked;
|
|
|
|
inline BlockableWindow()
|
|
: QWindow()
|
|
{
|
|
blocked = false;
|
|
}
|
|
|
|
bool event(QEvent *e)
|
|
{
|
|
switch (e->type()) {
|
|
case QEvent::WindowBlocked:
|
|
++blocked;
|
|
break;
|
|
case QEvent::WindowUnblocked:
|
|
--blocked;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return QWindow::event(e);
|
|
}
|
|
};
|
|
|
|
void tst_QGuiApplication::modalWindow()
|
|
{
|
|
int argc = 0;
|
|
QGuiApplication app(argc, 0);
|
|
|
|
BlockableWindow *window1 = new BlockableWindow;
|
|
|
|
BlockableWindow *window2 = new BlockableWindow;
|
|
|
|
BlockableWindow *windowModalWindow1 = new BlockableWindow;
|
|
windowModalWindow1->setTransientParent(window1);
|
|
windowModalWindow1->setWindowModality(Qt::WindowModal);
|
|
|
|
BlockableWindow *windowModalWindow2 = new BlockableWindow;
|
|
windowModalWindow2->setTransientParent(windowModalWindow1);
|
|
windowModalWindow2->setWindowModality(Qt::WindowModal);
|
|
|
|
BlockableWindow *applicationModalWindow1 = new BlockableWindow;
|
|
applicationModalWindow1->setWindowModality(Qt::ApplicationModal);
|
|
|
|
// show the 2 windows, nothing is blocked
|
|
window1->show();
|
|
window2->show();
|
|
QTest::qWaitForWindowShown(window1);
|
|
QTest::qWaitForWindowShown(window2);
|
|
QCOMPARE(app.modalWindow(), static_cast<QWindow *>(0));
|
|
QCOMPARE(window1->blocked, 0);
|
|
QCOMPARE(window2->blocked, 0);
|
|
QCOMPARE(windowModalWindow1->blocked, 0);
|
|
QCOMPARE(windowModalWindow2->blocked, 0);
|
|
QCOMPARE(applicationModalWindow1->blocked, 0);
|
|
|
|
// show applicationModalWindow1, everything is blocked
|
|
applicationModalWindow1->show();
|
|
QCOMPARE(app.modalWindow(), applicationModalWindow1);
|
|
QCOMPARE(window1->blocked, 1);
|
|
QCOMPARE(window2->blocked, 1);
|
|
QCOMPARE(windowModalWindow1->blocked, 1);
|
|
QCOMPARE(windowModalWindow2->blocked, 1);
|
|
QCOMPARE(applicationModalWindow1->blocked, 0);
|
|
|
|
// everything is unblocked when applicationModalWindow1 is hidden
|
|
applicationModalWindow1->hide();
|
|
QCOMPARE(app.modalWindow(), static_cast<QWindow *>(0));
|
|
QCOMPARE(window1->blocked, 0);
|
|
QCOMPARE(window2->blocked, 0);
|
|
QCOMPARE(windowModalWindow1->blocked, 0);
|
|
QCOMPARE(windowModalWindow2->blocked, 0);
|
|
QCOMPARE(applicationModalWindow1->blocked, 0);
|
|
|
|
// show the windowModalWindow1, only window1 is blocked
|
|
windowModalWindow1->show();
|
|
QCOMPARE(app.modalWindow(), windowModalWindow1);
|
|
QCOMPARE(window1->blocked, 1);
|
|
QCOMPARE(window2->blocked, 0);
|
|
QCOMPARE(windowModalWindow1->blocked, 0);
|
|
QCOMPARE(windowModalWindow2->blocked, 0);
|
|
QCOMPARE(applicationModalWindow1->blocked, 0);
|
|
|
|
// show the windowModalWindow2, windowModalWindow1 is blocked as well
|
|
windowModalWindow2->show();
|
|
QCOMPARE(app.modalWindow(), windowModalWindow2);
|
|
QCOMPARE(window1->blocked, 1);
|
|
QCOMPARE(window2->blocked, 0);
|
|
QCOMPARE(windowModalWindow1->blocked, 1);
|
|
QCOMPARE(windowModalWindow2->blocked, 0);
|
|
QCOMPARE(applicationModalWindow1->blocked, 0);
|
|
|
|
// hide windowModalWindow1, nothing is unblocked
|
|
windowModalWindow1->hide();
|
|
QCOMPARE(app.modalWindow(), windowModalWindow2);
|
|
QCOMPARE(window1->blocked, 1);
|
|
QCOMPARE(window2->blocked, 0);
|
|
QCOMPARE(windowModalWindow1->blocked, 1);
|
|
QCOMPARE(windowModalWindow2->blocked, 0);
|
|
QCOMPARE(applicationModalWindow1->blocked, 0);
|
|
|
|
// hide windowModalWindow2, windowModalWindow1 and window1 are unblocked
|
|
windowModalWindow2->hide();
|
|
QCOMPARE(app.modalWindow(), static_cast<QWindow *>(0));
|
|
QCOMPARE(window1->blocked, 0);
|
|
QCOMPARE(window2->blocked, 0);
|
|
QCOMPARE(windowModalWindow1->blocked, 0);
|
|
QCOMPARE(windowModalWindow2->blocked, 0);
|
|
QCOMPARE(applicationModalWindow1->blocked, 0);
|
|
|
|
// show windowModalWindow1 again, window1 is blocked
|
|
windowModalWindow1->show();
|
|
QCOMPARE(app.modalWindow(), windowModalWindow1);
|
|
QCOMPARE(window1->blocked, 1);
|
|
QCOMPARE(window2->blocked, 0);
|
|
QCOMPARE(windowModalWindow1->blocked, 0);
|
|
QCOMPARE(windowModalWindow2->blocked, 0);
|
|
QCOMPARE(applicationModalWindow1->blocked, 0);
|
|
|
|
// show windowModalWindow2 again, windowModalWindow1 is also blocked
|
|
windowModalWindow2->show();
|
|
QCOMPARE(app.modalWindow(), windowModalWindow2);
|
|
QCOMPARE(window1->blocked, 1);
|
|
QCOMPARE(window2->blocked, 0);
|
|
QCOMPARE(windowModalWindow1->blocked, 1);
|
|
QCOMPARE(windowModalWindow2->blocked, 0);
|
|
QCOMPARE(applicationModalWindow1->blocked, 0);
|
|
|
|
// show applicationModalWindow1, everything is blocked
|
|
applicationModalWindow1->show();
|
|
QCOMPARE(app.modalWindow(), applicationModalWindow1);
|
|
QCOMPARE(window1->blocked, 1);
|
|
QCOMPARE(window2->blocked, 1);
|
|
QCOMPARE(windowModalWindow1->blocked, 1);
|
|
QCOMPARE(windowModalWindow2->blocked, 1);
|
|
QCOMPARE(applicationModalWindow1->blocked, 0);
|
|
|
|
// hide applicationModalWindow1, windowModalWindow1 and window1 are blocked
|
|
applicationModalWindow1->hide();
|
|
QCOMPARE(app.modalWindow(), windowModalWindow2);
|
|
QCOMPARE(window1->blocked, 1);
|
|
QCOMPARE(window2->blocked, 0);
|
|
QCOMPARE(windowModalWindow1->blocked, 1);
|
|
QCOMPARE(windowModalWindow2->blocked, 0);
|
|
QCOMPARE(applicationModalWindow1->blocked, 0);
|
|
|
|
// hide windowModalWindow2, window1 is blocked
|
|
windowModalWindow2->hide();
|
|
QCOMPARE(app.modalWindow(), windowModalWindow1);
|
|
QCOMPARE(window1->blocked, 1);
|
|
QCOMPARE(window2->blocked, 0);
|
|
QCOMPARE(windowModalWindow1->blocked, 0);
|
|
QCOMPARE(windowModalWindow2->blocked, 0);
|
|
QCOMPARE(applicationModalWindow1->blocked, 0);
|
|
|
|
// hide windowModalWindow1, everything is unblocked
|
|
windowModalWindow1->hide();
|
|
QCOMPARE(app.modalWindow(), static_cast<QWindow *>(0));
|
|
QCOMPARE(window1->blocked, 0);
|
|
QCOMPARE(window2->blocked, 0);
|
|
QCOMPARE(windowModalWindow1->blocked, 0);
|
|
QCOMPARE(windowModalWindow2->blocked, 0);
|
|
QCOMPARE(applicationModalWindow1->blocked, 0);
|
|
|
|
window2->hide();
|
|
window1->hide();
|
|
|
|
delete applicationModalWindow1;
|
|
delete windowModalWindow2;
|
|
delete windowModalWindow1;
|
|
delete window2;
|
|
delete window1;
|
|
}
|
|
|
|
QTEST_APPLESS_MAIN(tst_QGuiApplication)
|
|
#include "tst_qguiapplication.moc"
|