Widgets: report focus object change to QtGui before sending widget events
Updating the focus child means the focus object of the window has changed. We need to report this to QtGui immediately so that it can e.g. inform the input context of the new focus object, before widgets reacting to the focus events start calling update() on the input method. Change-Id: Ie3f7b835591e71519e3f384c2abdad53242c9736 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
parent
166f23eb92
commit
6f504a1cdd
@ -6595,11 +6595,6 @@ void QWidget::setFocus(Qt::FocusReason reason)
|
||||
} else {
|
||||
f->d_func()->updateFocusChild();
|
||||
}
|
||||
|
||||
if (QTLWExtra *extra = f->window()->d_func()->maybeTopData()) {
|
||||
if (extra->window)
|
||||
emit extra->window->focusObjectChanged(f);
|
||||
}
|
||||
}
|
||||
|
||||
void QWidgetPrivate::setFocus_sys()
|
||||
@ -6634,6 +6629,11 @@ void QWidgetPrivate::updateFocusChild()
|
||||
w = w->isWindow() ? 0 : w->parentWidget();
|
||||
}
|
||||
}
|
||||
|
||||
if (QTLWExtra *extra = q->window()->d_func()->maybeTopData()) {
|
||||
if (extra->window)
|
||||
emit extra->window->focusObjectChanged(q);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -6675,9 +6675,15 @@ void QWidget::clearFocus()
|
||||
w->d_func()->focus_child = 0;
|
||||
w = w->parentWidget();
|
||||
}
|
||||
// Since focus_child is the basis for the top level QWidgetWindow's focusObject()
|
||||
// we need to report this change to the rest of Qt, but we match setFocus() and
|
||||
// do it at the end of the function.
|
||||
|
||||
// Since we've unconditionally cleared the focus_child of our parents, we need
|
||||
// to report this to the rest of Qt. Note that the focus_child is not the same
|
||||
// thing as the application's focusWidget, which is why this piece of code is
|
||||
// not inside the hasFocus() block below.
|
||||
if (QTLWExtra *extra = window()->d_func()->maybeTopData()) {
|
||||
if (extra->window)
|
||||
emit extra->window->focusObjectChanged(extra->window->focusObject());
|
||||
}
|
||||
|
||||
#ifndef QT_NO_GRAPHICSVIEW
|
||||
QWExtra *topData = d_func()->extra;
|
||||
@ -6700,15 +6706,6 @@ void QWidget::clearFocus()
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Since we've unconditionally cleared the focus_child of our parents, we need
|
||||
// to report this to the rest of Qt. Note that the focus_child is not the same
|
||||
// thing as the application's focusWidget, which is why this piece of code is
|
||||
// not inside the hasFocus() block above.
|
||||
if (QTLWExtra *extra = window()->d_func()->maybeTopData()) {
|
||||
if (extra->window)
|
||||
emit extra->window->focusObjectChanged(extra->window->focusObject());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -5216,16 +5216,40 @@ protected:
|
||||
widgetDuringFocusAboutToChange = qApp->focusWidget();
|
||||
return QWidget::event(ev);
|
||||
}
|
||||
virtual void focusInEvent(QFocusEvent *)
|
||||
{
|
||||
foucsObjectDuringFocusIn = qApp->focusObject();
|
||||
detectedBadEventOrdering = foucsObjectDuringFocusIn != mostRecentFocusObjectChange;
|
||||
}
|
||||
virtual void focusOutEvent(QFocusEvent *)
|
||||
{
|
||||
foucsObjectDuringFocusOut = qApp->focusObject();
|
||||
widgetDuringFocusOut = qApp->focusWidget();
|
||||
detectedBadEventOrdering = foucsObjectDuringFocusOut != mostRecentFocusObjectChange;
|
||||
}
|
||||
|
||||
void focusObjectChanged(QObject *focusObject)
|
||||
{
|
||||
mostRecentFocusObjectChange = focusObject;
|
||||
}
|
||||
|
||||
public:
|
||||
FocusWidget(QWidget *parent) : QWidget(parent), widgetDuringFocusAboutToChange(0), widgetDuringFocusOut(0) {}
|
||||
FocusWidget(QWidget *parent) : QWidget(parent),
|
||||
widgetDuringFocusAboutToChange(0), widgetDuringFocusOut(0),
|
||||
foucsObjectDuringFocusIn(0), foucsObjectDuringFocusOut(0),
|
||||
mostRecentFocusObjectChange(0), detectedBadEventOrdering(false)
|
||||
{
|
||||
connect(qGuiApp, &QGuiApplication::focusObjectChanged, this, &FocusWidget::focusObjectChanged);
|
||||
}
|
||||
|
||||
QWidget *widgetDuringFocusAboutToChange;
|
||||
QWidget *widgetDuringFocusOut;
|
||||
|
||||
QObject *foucsObjectDuringFocusIn;
|
||||
QObject *foucsObjectDuringFocusOut;
|
||||
|
||||
QObject *mostRecentFocusObjectChange;
|
||||
bool detectedBadEventOrdering;
|
||||
};
|
||||
|
||||
void tst_QWidget::setFocus()
|
||||
@ -5426,6 +5450,40 @@ void tst_QWidget::setFocus()
|
||||
QCOMPARE(window.focusWidget(), nullptr);
|
||||
QCOMPARE(QApplication::focusWidget(), nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
QWidget window;
|
||||
window.resize(m_testWidgetSize);
|
||||
window.move(windowPos);
|
||||
|
||||
FocusWidget child1(&window);
|
||||
QWidget child2(&window);
|
||||
|
||||
window.show();
|
||||
window.activateWindow();
|
||||
QVERIFY(QTest::qWaitForWindowExposed(&window));
|
||||
QTRY_VERIFY(QApplication::focusWindow());
|
||||
|
||||
QCOMPARE(QApplication::focusObject(), &window);
|
||||
|
||||
child1.setFocus();
|
||||
QTRY_VERIFY(child1.hasFocus());
|
||||
QCOMPARE(window.focusWidget(), &child1);
|
||||
QCOMPARE(QApplication::focusWidget(), &child1);
|
||||
QCOMPARE(QApplication::focusObject(), &child1);
|
||||
QCOMPARE(child1.foucsObjectDuringFocusIn, &child1);
|
||||
QVERIFY2(!child1.detectedBadEventOrdering,
|
||||
"focusObjectChanged should be delivered before widget focus events on setFocus");
|
||||
|
||||
child1.clearFocus();
|
||||
QTRY_VERIFY(!child1.hasFocus());
|
||||
QCOMPARE(window.focusWidget(), nullptr);
|
||||
QCOMPARE(QApplication::focusWidget(), nullptr);
|
||||
QCOMPARE(QApplication::focusObject(), &window);
|
||||
QVERIFY(child1.foucsObjectDuringFocusOut != &child1);
|
||||
QVERIFY2(!child1.detectedBadEventOrdering,
|
||||
"focusObjectChanged should be delivered before widget focus events on clearFocus");
|
||||
}
|
||||
}
|
||||
|
||||
template<class T> class EventSpy : public QObject
|
||||
|
Loading…
Reference in New Issue
Block a user