From b627dd2c24c5962c1e8f9d72bcbe9ebdfe6dfceb Mon Sep 17 00:00:00 2001 From: Felix Bourbonnais Date: Tue, 10 May 2016 10:06:53 -0400 Subject: QMenuBar: nested parenting fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QMenuBar now receives a parent changed event for each of its parent, grand-parent, ... This fixes a crash caused by an invalid QWidget pointer and makes sure the keyboard shortcuts events are relayed to the menu bar in all parenting/re-parenting cases by installing an event filter on each parent Task-number: QTBUG-53205 Change-Id: I419e6cbc52e28a67fb08a848a7161b4cb8ae4ae5 Reviewed-by: Gabriel de Dietrich Reviewed-by: Błażej Szczygieł --- src/widgets/widgets/qmenubar.cpp | 55 +++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 23 deletions(-) (limited to 'src/widgets/widgets/qmenubar.cpp') diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index cca0853a8f..3f42a07f39 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -706,7 +706,6 @@ void QMenuBarPrivate::init() } #endif q->setBackgroundRole(QPalette::Button); - oldWindow = oldParent = 0; handleReparent(); q->setMouseTracking(q->style()->styleHint(QStyle::SH_MenuBar_MouseTracking, 0, q)); @@ -1330,30 +1329,41 @@ void QMenuBarPrivate::handleReparent() { Q_Q(QMenuBar); QWidget *newParent = q->parentWidget(); - //Note: if parent is reparented, then window may change even if parent doesn't - // we need to install an event filter on parent, and remove the old one - - if (oldParent != newParent) { - if (oldParent) - oldParent->removeEventFilter(q); - if (newParent) - newParent->installEventFilter(q); + //Note: if parent is reparented, then window may change even if parent doesn't. + // We need to install an avent filter on each parent up to the parent that is + // also a window (for shortcuts) + QWidget *newWindow = newParent ? newParent->window() : Q_NULLPTR; + + QVector > newParents; + // Remove event filters on ex-parents, keep them on still-parents + // The parents are always ordered in the vector + foreach (const QPointer &w, oldParents) { + if (w) { + if (newParent == w) { + newParents.append(w); + if (newParent != newWindow) //stop at the window + newParent = newParent->parentWidget(); + } else { + w->removeEventFilter(q); + } + } } - //we also need event filter on top-level (for shortcuts) - QWidget *newWindow = newParent ? newParent->window() : 0; - - if (oldWindow != newWindow) { - if (oldParent && oldParent != oldWindow) - oldWindow->removeEventFilter(q); - - if (newParent && newParent != newWindow) - newWindow->installEventFilter(q); + // At this point, newParent is the next one to be added to newParents + while (newParent && newParent != newWindow) { + //install event filters all the way up to (excluding) the window + newParents.append(newParent); + newParent->installEventFilter(q); + newParent = newParent->parentWidget(); } - oldParent = newParent; - oldWindow = newWindow; + if (newParent && newWindow) { + // Install the event filter on the window + newParents.append(newParent); + newParent->installEventFilter(q); + } + oldParents = newParents; if (platformMenuBar) { if (newWindow) { @@ -1465,10 +1475,9 @@ bool QMenuBar::event(QEvent *e) bool QMenuBar::eventFilter(QObject *object, QEvent *event) { Q_D(QMenuBar); - if (object == parent() && object) { - if (event->type() == QEvent::ParentChange) //GrandparentChange + if (object && (event->type() == QEvent::ParentChange)) //GrandparentChange d->handleReparent(); - } + if (object == d->leftWidget || object == d->rightWidget) { switch (event->type()) { case QEvent::ShowToParent: -- cgit v1.2.3