From 851814cfedd678bfdf019eeafecd085b9df9058f Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 13 Nov 2009 16:56:21 +0100 Subject: Fix input method support on widgets that have a focus proxy set. When enabling/disabling a widget or changing its InputMethodEnabled attribute, use the focus proxy widget's input context for reset and for setting the focus widget on the input context. Task-number: QTBUG-5781 Reviewed-by: Denis --- src/gui/kernel/qwidget.cpp | 21 ++++++++------ src/gui/kernel/qwidget_p.h | 6 ++++ tests/auto/qwidget/tst_qwidget.cpp | 59 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 9 deletions(-) diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 4aa358f..0d8da0c 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -3084,9 +3084,10 @@ void QWidgetPrivate::setEnabled_helper(bool enable) #endif #ifndef QT_NO_IM if (q->testAttribute(Qt::WA_InputMethodEnabled) && q->hasFocus()) { - QInputContext *qic = inputContext(); + QWidget *focusWidget = effectiveFocusWidget(); + QInputContext *qic = focusWidget->d_func()->inputContext(); if (enable) { - qic->setFocusWidget(q); + qic->setFocusWidget(focusWidget); } else { qic->reset(); qic->setFocusWidget(0); @@ -10348,9 +10349,10 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) break; } case Qt::WA_NativeWindow: { #ifndef QT_NO_IM + QWidget *focusWidget = d->effectiveFocusWidget(); QInputContext *ic = 0; if (on && !internalWinId() && testAttribute(Qt::WA_InputMethodEnabled) && hasFocus()) { - ic = d->inputContext(); + ic = focusWidget->d_func()->inputContext(); ic->reset(); ic->setFocusWidget(0); } @@ -10359,7 +10361,7 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) if (on && !internalWinId() && testAttribute(Qt::WA_WState_Created)) d->createWinId(); if (ic && isEnabled()) - ic->setFocusWidget(this); + ic->setFocusWidget(focusWidget); #endif //QT_NO_IM break; } @@ -10391,13 +10393,14 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) break; case Qt::WA_InputMethodEnabled: { #ifndef QT_NO_IM - QInputContext *ic = d->ic; + QWidget *focusWidget = d->effectiveFocusWidget(); + QInputContext *ic = focusWidget->d_func()->ic; if (!ic && (!on || hasFocus())) - ic = d->inputContext(); + ic = focusWidget->d_func()->inputContext(); if (ic) { - if (on && hasFocus() && ic->focusWidget() != this && isEnabled()) { - ic->setFocusWidget(this); - } else if (!on && ic->focusWidget() == this) { + if (on && hasFocus() && ic->focusWidget() != focusWidget && isEnabled()) { + ic->setFocusWidget(focusWidget); + } else if (!on && ic->focusWidget() == focusWidget) { ic->reset(); ic->setFocusWidget(0); } diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index eea929b..66efcb5 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -465,6 +465,12 @@ public: void setLayoutItemMargins(QStyle::SubElement element, const QStyleOption *opt = 0); QInputContext *inputContext() const; + inline QWidget *effectiveFocusWidget() { + QWidget *w = q_func(); + while (w->focusProxy()) + w = w->focusProxy(); + return w; + } void setModal_sys(); diff --git a/tests/auto/qwidget/tst_qwidget.cpp b/tests/auto/qwidget/tst_qwidget.cpp index e027dd1..9692c6e 100644 --- a/tests/auto/qwidget/tst_qwidget.cpp +++ b/tests/auto/qwidget/tst_qwidget.cpp @@ -388,6 +388,8 @@ private slots: void cbaVisibility(); #endif + void focusProxyAndInputMethods(); + private: bool ensureScreenSize(int width, int height); QWidget *testWidget; @@ -9619,5 +9621,62 @@ void tst_QWidget::cbaVisibility() } #endif +class InputContextTester : public QInputContext +{ + Q_OBJECT +public: + QString identifierName() { return QString(); } + bool isComposing() const { return false; } + QString language() { return QString(); } + void reset() { ++resets; } + int resets; +}; + +void tst_QWidget::focusProxyAndInputMethods() +{ + InputContextTester *inputContext = new InputContextTester; + QWidget *toplevel = new QWidget(0, Qt::X11BypassWindowManagerHint); + toplevel->setAttribute(Qt::WA_InputMethodEnabled, true); + toplevel->setInputContext(inputContext); // ownership is transferred + + QWidget *child = new QWidget(toplevel); + child->setFocusProxy(toplevel); + child->setAttribute(Qt::WA_InputMethodEnabled, true); + + toplevel->setFocusPolicy(Qt::WheelFocus); + child->setFocusPolicy(Qt::WheelFocus); + + QVERIFY(!child->hasFocus()); + QVERIFY(!toplevel->hasFocus()); + + toplevel->show(); + QTest::qWaitForWindowShown(toplevel); + QApplication::setActiveWindow(toplevel); + QVERIFY(toplevel->hasFocus()); + QVERIFY(child->hasFocus()); + + // verify that toggling input methods on the child widget + // correctly propagate to the focus proxy's input method + // and that the input method gets the focus proxy passed + // as the focus widget instead of the child widget. + // otherwise input method queries go to the wrong widget + + QCOMPARE(inputContext->focusWidget(), toplevel); + + child->setAttribute(Qt::WA_InputMethodEnabled, false); + QVERIFY(!inputContext->focusWidget()); + + child->setAttribute(Qt::WA_InputMethodEnabled, true); + QCOMPARE(inputContext->focusWidget(), toplevel); + + child->setEnabled(false); + QVERIFY(!inputContext->focusWidget()); + + child->setEnabled(true); + QCOMPARE(inputContext->focusWidget(), toplevel); + + delete toplevel; +} + QTEST_MAIN(tst_QWidget) #include "tst_qwidget.moc" -- cgit v0.12