From 1a7da7096bbda17197738061902f4489af234bc0 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Tue, 2 Jun 2009 14:59:17 +0200 Subject: Setting a focus on a widget hierarchy which contains both visible and invisible widgets could cause a crash. Also, when there is a widget hierarchy A->B->C and A and C are marked as visible but B is hidden, when the user gives focus explicitely to C, we should remember that and respect it when B becomes visible. Task-number: 254563 Reviewed-by: Thierry Bastian --- src/gui/kernel/qwidget.cpp | 11 ++++++++++- tests/auto/qwidget/tst_qwidget.cpp | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 5538c11..d436ffb 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -5674,10 +5674,15 @@ void QWidget::setFocus(Qt::FocusReason reason) w = w->isWindow() ? 0 : w->parentWidget(); } } else { - while (w) { + while (w && w->isVisible()) { w->d_func()->focus_child = f; w = w->isWindow() ? 0 : w->parentWidget(); } + // a special case, if there is an invisible parent, notify him + // about the focus_child widget, so that if it becomes + // visible, the focus widget will be respected. + if (w) + w->d_func()->focus_child = f; } #ifndef QT_NO_GRAPHICSVIEW @@ -6729,6 +6734,10 @@ void QWidgetPrivate::show_helper() if (QApplicationPrivate::hidden_focus_widget == q) { QApplicationPrivate::hidden_focus_widget = 0; q->setFocus(Qt::OtherFocusReason); + } else if (focus_child) { + // if we are shown and there is an explicit focus child widget + // set, respect it by giving him focus. + focus_child->setFocus(Qt::OtherFocusReason); } // Process events when showing a Qt::SplashScreen widget before the event loop diff --git a/tests/auto/qwidget/tst_qwidget.cpp b/tests/auto/qwidget/tst_qwidget.cpp index 23ead01..3fad366 100644 --- a/tests/auto/qwidget/tst_qwidget.cpp +++ b/tests/auto/qwidget/tst_qwidget.cpp @@ -350,6 +350,9 @@ private slots: void updateOnDestroyedSignal(); void toplevelLineEditFocus(); + void focusWidget_task254563(); + void focusWidget_mixed_widget_hierarchy(); + private: bool ensureScreenSize(int width, int height); QWidget *testWidget; @@ -8977,5 +8980,37 @@ void tst_QWidget::toplevelLineEditFocus() QCOMPARE(QApplication::focusWidget(), &w); } +void tst_QWidget::focusWidget_task254563() +{ + //having different visibility for widget is important + QWidget top; + top.show(); + QWidget container(&top); + QWidget *widget = new QWidget(&container); + widget->show(); + + widget->setFocus(); //set focus (will set the focus widget up to the toplevel to be 'widget') + container.setFocus(); + delete widget; // will call clearFocus but that doesn't help + QVERIFY(top.focusWidget() != widget); //dangling pointer +} + +void tst_QWidget::focusWidget_mixed_widget_hierarchy() +{ + QWidget top; + top.show(); + QWidget notvisible(&top); + QWidget *visible = new QWidget(¬visible); + visible->show(); + + visible->setFocus(); + notvisible.setFocus(); + notvisible.show(); + QCOMPARE(top.focusWidget(), visible); + QCOMPARE(notvisible.focusWidget(), visible); + QCOMPARE(visible->focusWidget(), visible); +} + + QTEST_MAIN(tst_QWidget) #include "tst_qwidget.moc" -- cgit v0.12