From 0307f5a7b271eea75e5d9c12c65caaf578a3384b Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 24 Oct 2011 13:57:12 +1000 Subject: [PATCH] Fix item focus following canvas focus. Restore canvas focus handling so that active item focus is added and removed as the canvas focus changes. Task-number: QTBUG-17320 Change-Id: Ief60f35da2f3a563f397ce026ca6fea289a200c4 Reviewed-by: Martin Jones --- src/declarative/items/qquickcanvas.cpp | 21 ++++++---- src/declarative/items/qquickcanvas.h | 3 ++ .../qquickfocusscope/tst_qquickfocusscope.cpp | 36 ++++++++++------- .../auto/declarative/qquickitem/tst_qquickitem.cpp | 13 ++++++ .../declarative/qquickitem2/tst_qquickitem.cpp | 47 +++++++++------------- .../qquicktextedit/tst_qquicktextedit.cpp | 25 +++--------- .../qquicktextinput/tst_qquicktextinput.cpp | 24 +++-------- 7 files changed, 83 insertions(+), 86 deletions(-) diff --git a/src/declarative/items/qquickcanvas.cpp b/src/declarative/items/qquickcanvas.cpp index 8f87ce7..52ef421 100644 --- a/src/declarative/items/qquickcanvas.cpp +++ b/src/declarative/items/qquickcanvas.cpp @@ -348,6 +348,17 @@ void QQuickCanvas::hideEvent(QHideEvent *) d->thread->stopRendering(); } +void QQuickCanvas::focusOutEvent(QFocusEvent *) +{ + Q_D(QQuickCanvas); + d->rootItem->setFocus(false); +} + +void QQuickCanvas::focusInEvent(QFocusEvent *) +{ + Q_D(QQuickCanvas); + d->rootItem->setFocus(true); +} /*! @@ -484,10 +495,6 @@ void QQuickCanvasPrivate::init(QQuickCanvas *c) rootItemPrivate->canvas = q; rootItemPrivate->flags |= QQuickItem::ItemIsFocusScope; - // QML always has focus. It is important that this call happens after the rootItem - // has a canvas.. - rootItem->setFocus(true); - bool threaded = !qmlNoThreadedRenderer(); if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL)) { @@ -626,13 +633,13 @@ void QQuickCanvasPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, F } if (!(options & DontChangeFocusProperty)) { - // if (item != rootItem || q->hasFocus()) { // ### refactor: focus handling... + if (item != rootItem || QGuiApplication::focusWindow() == q) { itemPrivate->focus = true; changed << item; - // } + } } - if (newActiveFocusItem) { // ### refactor: && q->hasFocus()) { + if (newActiveFocusItem && QGuiApplication::focusWindow() == q) { activeFocusItem = newActiveFocusItem; QQuickItemPrivate::get(newActiveFocusItem)->activeFocus = true; diff --git a/src/declarative/items/qquickcanvas.h b/src/declarative/items/qquickcanvas.h index 8b69744..e9b1b60 100644 --- a/src/declarative/items/qquickcanvas.h +++ b/src/declarative/items/qquickcanvas.h @@ -101,6 +101,9 @@ protected: virtual void showEvent(QShowEvent *); virtual void hideEvent(QHideEvent *); + virtual void focusInEvent(QFocusEvent *); + virtual void focusOutEvent(QFocusEvent *); + virtual bool event(QEvent *); virtual void keyPressEvent(QKeyEvent *); virtual void keyReleaseEvent(QKeyEvent *); diff --git a/tests/auto/declarative/qquickfocusscope/tst_qquickfocusscope.cpp b/tests/auto/declarative/qquickfocusscope/tst_qquickfocusscope.cpp index 6e7dd98..ffb9660 100644 --- a/tests/auto/declarative/qquickfocusscope/tst_qquickfocusscope.cpp +++ b/tests/auto/declarative/qquickfocusscope/tst_qquickfocusscope.cpp @@ -121,6 +121,7 @@ void tst_qquickfocusscope::basic() view->requestActivateWindow(); QTest::qWaitForWindowShown(view); + QTRY_VERIFY(view == qGuiApp->focusWindow()); QVERIFY(view->isTopLevel()); QVERIFY(item0->hasActiveFocus() == true); @@ -165,6 +166,7 @@ void tst_qquickfocusscope::nested() view->requestActivateWindow(); QTest::qWaitForWindowShown(view); + QTRY_VERIFY(view == qGuiApp->focusWindow()); QVERIFY(item1->hasActiveFocus() == true); QVERIFY(item2->hasActiveFocus() == true); @@ -191,6 +193,7 @@ void tst_qquickfocusscope::noFocus() view->show(); view->requestActivateWindow(); QTest::qWaitForWindowShown(view); + QTRY_VERIFY(view == qGuiApp->focusWindow()); QVERIFY(item0->hasActiveFocus() == false); QVERIFY(item1->hasActiveFocus() == false); @@ -283,6 +286,7 @@ void tst_qquickfocusscope::forceFocus() view->show(); view->requestActivateWindow(); QTest::qWaitForWindowShown(view); + QTRY_VERIFY(view == qGuiApp->focusWindow()); QVERIFY(item0->hasActiveFocus() == true); QVERIFY(item1->hasActiveFocus() == true); @@ -318,12 +322,8 @@ void tst_qquickfocusscope::noParentFocus() view->show(); view->requestActivateWindow(); - qApp->processEvents(); - -#ifdef Q_WS_X11 - // to be safe and avoid failing setFocus with window managers - qt_x11_wait_for_window_manager(view); -#endif + QTest::qWaitForWindowShown(view); + QTRY_VERIFY(view == qGuiApp->focusWindow()); QVERIFY(view->rootObject()->property("focus1") == false); QVERIFY(view->rootObject()->property("focus2") == false); @@ -352,6 +352,7 @@ void tst_qquickfocusscope::signalEmission() view->requestActivateWindow(); QTest::qWaitForWindowShown(view); + QTRY_VERIFY(view == qGuiApp->focusWindow()); QVariant blue(QColor("blue")); QVariant red(QColor("red")); @@ -417,12 +418,8 @@ void tst_qquickfocusscope::forceActiveFocus() view->show(); view->requestActivateWindow(); - qApp->processEvents(); - -#ifdef Q_WS_X11 - // to be safe and avoid failing setFocus with window managers - qt_x11_wait_for_window_manager(view); -#endif + QTest::qWaitForWindowShown(view); + QTRY_VERIFY(view == qGuiApp->focusWindow()); QQuickItem *rootObject = view->rootObject(); QVERIFY(rootObject); @@ -533,6 +530,8 @@ void tst_qquickfocusscope::canvasFocus() QQuickView *view = new QQuickView; view->setSource(QUrl::fromLocalFile(TESTDATA("canvasFocus.qml"))); + QQuickView alternateView; + QQuickItem *rootObject = view->rootObject(); QVERIFY(rootObject); @@ -558,8 +557,6 @@ void tst_qquickfocusscope::canvasFocus() QSignalSpy scope2ActiveFocusSpy(scope2, SIGNAL(activeFocusChanged(bool))); QSignalSpy item2ActiveFocusSpy(item2, SIGNAL(activeFocusChanged(bool))); - QEXPECT_FAIL("", "QTBUG-21054 - Root item hasFocus returns true already", Abort); - QCOMPARE(rootItem->hasFocus(), false); QCOMPARE(rootItem->hasActiveFocus(), false); QCOMPARE(scope1->hasFocus(), true); @@ -575,6 +572,7 @@ void tst_qquickfocusscope::canvasFocus() view->requestActivateWindow(); QTest::qWaitForWindowShown(view); + QTRY_VERIFY(view == qGuiApp->focusWindow()); // Now the canvas has focus, active focus given to item1 QCOMPARE(rootItem->hasFocus(), true); @@ -595,7 +593,12 @@ void tst_qquickfocusscope::canvasFocus() QCOMPARE(item1ActiveFocusSpy.count(), 1); - view->hide(); + // view->hide(); // seemingly doesn't remove focus, so have an another view steal it. + alternateView.show(); + alternateView.requestActivateWindow(); + QTest::qWaitForWindowShown(&alternateView); + QTRY_VERIFY(QGuiApplication::focusWindow() == &alternateView); + QCOMPARE(rootItem->hasFocus(), false); QCOMPARE(rootItem->hasActiveFocus(), false); QCOMPARE(scope1->hasFocus(), true); @@ -636,6 +639,9 @@ void tst_qquickfocusscope::canvasFocus() // give the canvas focus, and item2 will get active focus view->show(); + view->requestActivateWindow(); + QTest::qWaitForWindowShown(view); + QTRY_VERIFY(QGuiApplication::focusWindow() == view); QCOMPARE(rootItem->hasFocus(), true); QCOMPARE(rootItem->hasActiveFocus(), true); diff --git a/tests/auto/declarative/qquickitem/tst_qquickitem.cpp b/tests/auto/declarative/qquickitem/tst_qquickitem.cpp index 694fdc0..35346c8 100644 --- a/tests/auto/declarative/qquickitem/tst_qquickitem.cpp +++ b/tests/auto/declarative/qquickitem/tst_qquickitem.cpp @@ -239,6 +239,7 @@ void tst_qquickitem::simpleFocus() { QQuickCanvas canvas; ensureFocus(&canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas); QQuickItem *l1c1 = new TestItem(canvas.rootItem()); QQuickItem *l1c2 = new TestItem(canvas.rootItem()); @@ -289,6 +290,7 @@ void tst_qquickitem::scopedFocus() { QQuickCanvas canvas; ensureFocus(&canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas); QQuickItem *l1c1 = new TestItem(canvas.rootItem()); QQuickItem *l1c2 = new TestItem(canvas.rootItem()); @@ -368,6 +370,7 @@ void tst_qquickitem::addedToCanvas() { QQuickCanvas canvas; ensureFocus(&canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas); QQuickItem *item = new TestItem; @@ -387,6 +390,7 @@ void tst_qquickitem::addedToCanvas() { QQuickCanvas canvas; ensureFocus(&canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas); QQuickItem *item = new TestItem(canvas.rootItem()); @@ -415,6 +419,7 @@ void tst_qquickitem::addedToCanvas() { QQuickCanvas canvas; ensureFocus(&canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas); QQuickItem *tree = new TestItem; QQuickItem *c1 = new TestItem(tree); @@ -438,6 +443,7 @@ void tst_qquickitem::addedToCanvas() { QQuickCanvas canvas; ensureFocus(&canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas); QQuickItem *tree = new TestFocusScope; QQuickItem *c1 = new TestItem(tree); QQuickItem *c2 = new TestItem(tree); @@ -465,6 +471,7 @@ void tst_qquickitem::addedToCanvas() { QQuickCanvas canvas; ensureFocus(&canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas); QQuickItem *tree = new TestFocusScope; QQuickItem *c1 = new TestItem(tree); QQuickItem *c2 = new TestItem(tree); @@ -490,6 +497,7 @@ void tst_qquickitem::addedToCanvas() { QQuickCanvas canvas; ensureFocus(&canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas); QQuickItem *child = new TestItem(canvas.rootItem()); QQuickItem *tree = new TestFocusScope; QQuickItem *c1 = new TestItem(tree); @@ -529,6 +537,7 @@ void tst_qquickitem::changeParent() { QQuickCanvas canvas; ensureFocus(&canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas); QQuickItem *child = new TestItem(canvas.rootItem()); FocusState focusState; @@ -550,6 +559,7 @@ void tst_qquickitem::changeParent() { QQuickCanvas canvas; ensureFocus(&canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas); QQuickItem *child = new TestItem(canvas.rootItem()); QQuickItem *child2 = new TestItem(canvas.rootItem()); @@ -570,6 +580,7 @@ void tst_qquickitem::changeParent() { QQuickCanvas canvas; ensureFocus(&canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas); QQuickItem *child = new TestItem(canvas.rootItem()); QQuickItem *child2 = new TestFocusScope(canvas.rootItem()); QQuickItem *item = new TestItem(child); @@ -591,6 +602,7 @@ void tst_qquickitem::changeParent() { QQuickCanvas canvas; ensureFocus(&canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas); QQuickItem *child = new TestItem(canvas.rootItem()); QQuickItem *child2 = new TestFocusScope(canvas.rootItem()); QQuickItem *item = new TestItem(child2); @@ -612,6 +624,7 @@ void tst_qquickitem::changeParent() { QQuickCanvas canvas; ensureFocus(&canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas); QQuickItem *child = new TestItem(canvas.rootItem()); QQuickItem *child2 = new TestFocusScope(canvas.rootItem()); QQuickItem *item = new TestItem(child2); diff --git a/tests/auto/declarative/qquickitem2/tst_qquickitem.cpp b/tests/auto/declarative/qquickitem2/tst_qquickitem.cpp index 711ca17..648dbe2 100644 --- a/tests/auto/declarative/qquickitem2/tst_qquickitem.cpp +++ b/tests/auto/declarative/qquickitem2/tst_qquickitem.cpp @@ -213,12 +213,9 @@ void tst_QQuickItem::keys() canvas->setSource(QUrl::fromLocalFile(TESTDATA("keystest.qml"))); canvas->show(); - qApp->processEvents(); - - QEvent wa(QEvent::WindowActivate); - QApplication::sendEvent(canvas, &wa); - QFocusEvent fe(QEvent::FocusIn); - QApplication::sendEvent(canvas, &fe); + canvas->requestActivateWindow(); + QTest::qWaitForWindowShown(canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == canvas); QVERIFY(canvas->rootObject()); QCOMPARE(canvas->rootObject()->property("isEnabled").toBool(), true); @@ -334,16 +331,13 @@ void tst_QQuickItem::keysProcessingOrder() canvas->setSource(QUrl::fromLocalFile(TESTDATA("keyspriority.qml"))); canvas->show(); - qApp->processEvents(); + canvas->requestActivateWindow(); + QTest::qWaitForWindowShown(canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == canvas); KeyTestItem *testItem = qobject_cast(canvas->rootObject()); QVERIFY(testItem); - QEvent wa(QEvent::WindowActivate); - QApplication::sendEvent(canvas, &wa); - QFocusEvent fe(QEvent::FocusIn); - QApplication::sendEvent(canvas, &fe); - QKeyEvent key(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier, "A", false, 1); QApplication::sendEvent(canvas, &key); QCOMPARE(testObject->mKey, int(Qt::Key_A)); @@ -546,12 +540,9 @@ void tst_QQuickItem::keyNavigation() canvas->setSource(QUrl::fromLocalFile(TESTDATA("keynavigationtest.qml"))); canvas->show(); - qApp->processEvents(); - - QEvent wa(QEvent::WindowActivate); - QApplication::sendEvent(canvas, &wa); - QFocusEvent fe(QEvent::FocusIn); - QApplication::sendEvent(canvas, &fe); + canvas->requestActivateWindow(); + QTest::qWaitForWindowShown(canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == canvas); QQuickItem *item = findItem(canvas->rootObject(), "item1"); QVERIFY(item); @@ -626,7 +617,9 @@ void tst_QQuickItem::keyNavigation_RightToLeft() canvas->setSource(QUrl::fromLocalFile(TESTDATA("keynavigationtest.qml"))); canvas->show(); - qApp->processEvents(); + canvas->requestActivateWindow(); + QTest::qWaitForWindowShown(canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == canvas); QQuickItem *rootItem = qobject_cast(canvas->rootObject()); QVERIFY(rootItem); @@ -679,12 +672,9 @@ void tst_QQuickItem::keyNavigation_skipNotVisible() canvas->setSource(QUrl::fromLocalFile(TESTDATA("keynavigationtest.qml"))); canvas->show(); - qApp->processEvents(); - - QEvent wa(QEvent::WindowActivate); - QApplication::sendEvent(canvas, &wa); - QFocusEvent fe(QEvent::FocusIn); - QApplication::sendEvent(canvas, &fe); + canvas->requestActivateWindow(); + QTest::qWaitForWindowShown(canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == canvas); QQuickItem *item = findItem(canvas->rootObject(), "item1"); QVERIFY(item); @@ -757,7 +747,9 @@ void tst_QQuickItem::keyNavigation_implicitSetting() canvas->setSource(QUrl::fromLocalFile(TESTDATA("keynavigationtest_implicit.qml"))); canvas->show(); - qApp->processEvents(); + canvas->requestActivateWindow(); + QTest::qWaitForWindowShown(canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == canvas); QEvent wa(QEvent::WindowActivate); QApplication::sendEvent(canvas, &wa); @@ -1056,8 +1048,9 @@ void tst_QQuickItem::propertyChanges() canvas->setBaseSize(QSize(300, 300)); canvas->setSource(QUrl::fromLocalFile(TESTDATA("propertychanges.qml"))); canvas->show(); - + canvas->requestActivateWindow(); QTest::qWaitForWindowShown(canvas); + QTRY_VERIFY(QGuiApplication::focusWindow() == canvas); QQuickItem *item = findItem(canvas->rootObject(), "item"); QQuickItem *parentItem = findItem(canvas->rootObject(), "parentItem"); diff --git a/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp index a0d36d6..86c33a6 100644 --- a/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp +++ b/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp @@ -1683,31 +1683,18 @@ void tst_qquicktextedit::cursorVisible() QCOMPARE(edit.isCursorVisible(), true); QCOMPARE(spy.count(), 5); - QEXPECT_FAIL("", "Most likely a side-effect of QTBUG-21489", Abort); - view.setWindowState(Qt::WindowNoState); + QQuickView alternateView; + alternateView.show(); + alternateView.requestActivateWindow(); + QTest::qWaitForWindowShown(&alternateView); + QCOMPARE(edit.isCursorVisible(), false); QCOMPARE(spy.count(), 6); view.requestActivateWindow(); + QTest::qWaitForWindowShown(&view); QCOMPARE(edit.isCursorVisible(), true); QCOMPARE(spy.count(), 7); - - // on mac, setActiveWindow(0) on mac does not deactivate the current application - // (you have to switch to a different app or hide the current app to trigger this) -#if !defined(Q_WS_MAC) - // on mac, setActiveWindow(0) on mac does not deactivate the current application - // (you have to switch to a different app or hide the current app to trigger this) -// QApplication::setActiveWindow(0); -// QTRY_COMPARE(QApplication::focusWindow(), static_cast(0)); -// QCOMPARE(edit.isCursorVisible(), false); -// QCOMPARE(spy.count(), 8); - -// view.requestActivateWindow(); -// QTest::qWaitForWindowShown(&view); -// QTRY_COMPARE(view.windowState(), Qt::WindowActive); -// QCOMPARE(edit.isCursorVisible(), true); -// QCOMPARE(spy.count(), 9); -#endif } void tst_qquicktextedit::delegateLoading_data() diff --git a/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp index 8c8166b..23224d0 100644 --- a/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp +++ b/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp @@ -1798,30 +1798,18 @@ void tst_qquicktextinput::cursorVisible() QCOMPARE(input.isCursorVisible(), true); QCOMPARE(spy.count(), 5); - view.setWindowState(Qt::WindowNoState); - QEXPECT_FAIL("", "Most likely a side-effect of QTBUG-21489", Abort); + QQuickView alternateView; + alternateView.show(); + alternateView.requestActivateWindow(); + QTest::qWaitForWindowShown(&alternateView); + QCOMPARE(input.isCursorVisible(), false); QCOMPARE(spy.count(), 6); view.requestActivateWindow(); + QTest::qWaitForWindowShown(&view); QCOMPARE(input.isCursorVisible(), true); QCOMPARE(spy.count(), 7); - - // on mac, setActiveWindow(0) on mac does not deactivate the current application - // (you have to switch to a different app or hide the current app to trigger this) -#if !defined(Q_WS_MAC) - // QGuiApplication has no equivalent of setActiveWindow(0). Is this different to clearing the - // active state of the window or can it be removed? -// QApplication::setActiveWindow(0); -// QTRY_COMPARE(QApplication::focusWindow(), static_cast(0)); -// QCOMPARE(input.isCursorVisible(), false); -// QCOMPARE(spy.count(), 8); - -// view.requestActivateWindow(); -// QTRY_COMPARE(view.windowState(), Qt::WindowActive); -// QCOMPARE(input.isCursorVisible(), true); -// QCOMPARE(spy.count(), 9); -#endif } void tst_qquicktextinput::cursorRectangle() -- 2.7.4