From e7da97bf71108a0acd72629e383f884e2d756477 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Mon, 9 Feb 2015 01:16:51 +0100 Subject: QQuickWindow: Only send focus events to items that actually gain focus Sending focus events may result in further changes to which item actually has focus, so we cannot blindly send the focus events without first checking that it hasn't subsequently changed. To accomplish this, we delay sending events as long as possible, ensuring that all necessary bookkeeping is done first to ensure internal consistency. Task-number: QTBUG-40145 Change-Id: I7d93b3f8e3fea2ecce2151c88c29601deda12453 Reviewed-by: Shawn Rutledge --- src/quick/items/qquickwindow.cpp | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index ef534fe35d..14e7915dba 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -785,8 +785,10 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0; QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + QQuickItem *oldActiveFocusItem = 0; QQuickItem *currentActiveFocusItem = activeFocusItem; QQuickItem *newActiveFocusItem = 0; + bool sendFocusIn = false; lastFocusReason = reason; @@ -794,7 +796,6 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q // Does this change the active focus? if (item == contentItem || scopePrivate->activeFocus) { - QQuickItem *oldActiveFocusItem = 0; oldActiveFocusItem = activeFocusItem; if (item->isEnabled()) { newActiveFocusItem = item; @@ -813,8 +814,6 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q #endif activeFocusItem = 0; - QFocusEvent event(QEvent::FocusOut, reason); - q->sendEvent(oldActiveFocusItem, &event); QQuickItem *afi = oldActiveFocusItem; while (afi && afi != scope) { @@ -859,7 +858,19 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q afi = afi->parentItem(); } updateFocusItemTransform(); + sendFocusIn = true; + } + + // Now that all the state is changed, emit signals & events + // We must do this last, as this process may result in further changes to + // focus. + if (oldActiveFocusItem) { + QFocusEvent event(QEvent::FocusOut, reason); + q->sendEvent(oldActiveFocusItem, &event); + } + // Make sure that the FocusOut didn't result in another focus change. + if (sendFocusIn && activeFocusItem == newActiveFocusItem) { QFocusEvent event(QEvent::FocusIn, reason); q->sendEvent(newActiveFocusItem, &event); } @@ -912,9 +923,6 @@ void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item, activeFocusItem = 0; if (oldActiveFocusItem) { - QFocusEvent event(QEvent::FocusOut, reason); - q->sendEvent(oldActiveFocusItem, &event); - QQuickItem *afi = oldActiveFocusItem; while (afi && afi != scope) { if (QQuickItemPrivate::get(afi)->activeFocus) { @@ -944,7 +952,18 @@ void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item, Q_ASSERT(newActiveFocusItem == scope); activeFocusItem = scope; updateFocusItemTransform(); + } + + // Now that all the state is changed, emit signals & events + // We must do this last, as this process may result in further changes to + // focus. + if (oldActiveFocusItem) { + QFocusEvent event(QEvent::FocusOut, reason); + q->sendEvent(oldActiveFocusItem, &event); + } + // Make sure that the FocusOut didn't result in another focus change. + if (newActiveFocusItem && activeFocusItem == newActiveFocusItem) { QFocusEvent event(QEvent::FocusIn, reason); q->sendEvent(newActiveFocusItem, &event); } -- cgit v1.2.3