diff options
Diffstat (limited to 'src/widgets')
-rw-r--r-- | src/widgets/kernel/qwidget.cpp | 18 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget_p.h | 2 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetwindow.cpp | 68 | ||||
-rw-r--r-- | src/widgets/styles/qstyleoption.h | 8 | ||||
-rw-r--r-- | src/widgets/widgets/qmenu.cpp | 86 | ||||
-rw-r--r-- | src/widgets/widgets/qmenu_p.h | 23 | ||||
-rw-r--r-- | src/widgets/widgets/qmenubar.cpp | 28 | ||||
-rw-r--r-- | src/widgets/widgets/qmenubar_p.h | 4 | ||||
-rw-r--r-- | src/widgets/widgets/qtabbar.cpp | 3 | ||||
-rw-r--r-- | src/widgets/widgets/qtoolbutton.cpp | 3 |
10 files changed, 130 insertions, 113 deletions
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 0d9cff01c4..293dafd932 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -283,6 +283,8 @@ QWidgetPrivate::QWidgetPrivate(int version) , renderToTextureReallyDirty(1) , renderToTextureComposeActive(0) #endif + , childrenHiddenByWState(0) + , childrenShownByExpose(0) #if defined(Q_OS_WIN) , noPaintOnScreen(0) #endif @@ -9035,13 +9037,23 @@ bool QWidget::event(QEvent *event) case QEvent::WindowStateChange: { const bool wasMinimized = static_cast<const QWindowStateChangeEvent *>(event)->oldState() & Qt::WindowMinimized; if (wasMinimized != isMinimized()) { + QWidget *widget = const_cast<QWidget *>(this); if (wasMinimized) { - QShowEvent showEvent; - QCoreApplication::sendEvent(const_cast<QWidget *>(this), &showEvent); + // Always send the spontaneous events here, otherwise it can break the application! + if (!d->childrenShownByExpose) { + // Show widgets only when they are not yet shown by the expose event + d->showChildren(true); + QShowEvent showEvent; + QCoreApplication::sendSpontaneousEvent(widget, &showEvent); + } + d->childrenHiddenByWState = false; // Set it always to "false" when window is restored } else { QHideEvent hideEvent; - QCoreApplication::sendEvent(const_cast<QWidget *>(this), &hideEvent); + QCoreApplication::sendSpontaneousEvent(widget, &hideEvent); + d->hideChildren(true); + d->childrenHiddenByWState = true; } + d->childrenShownByExpose = false; // Set it always to "false" when window state changes } changeEvent(event); } diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index 5f50315df5..f44c0aff21 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -752,6 +752,8 @@ public: uint renderToTextureReallyDirty : 1; uint renderToTextureComposeActive : 1; #endif + uint childrenHiddenByWState : 1; + uint childrenShownByExpose : 1; // *************************** Platform specific ************************************ #if defined(Q_OS_WIN) diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 2a4f31babf..f3fbe13763 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -387,7 +387,14 @@ void QWidgetWindow::handleEnterLeaveEvent(QEvent *event) const QEnterEvent *ee = static_cast<QEnterEvent *>(event); QWidget *child = m_widget->childAt(ee->pos()); QWidget *receiver = child ? child : m_widget.data(); - QApplicationPrivate::dispatchEnterLeave(receiver, 0, ee->screenPos()); + QWidget *leave = Q_NULLPTR; + if (QApplicationPrivate::inPopupMode() && receiver == m_widget + && qt_last_mouse_receiver != m_widget) { + // This allows to deliver the leave event to the native widget + // action on first-level menu. + leave = qt_last_mouse_receiver; + } + QApplicationPrivate::dispatchEnterLeave(receiver, leave, ee->screenPos()); qt_last_mouse_receiver = receiver; } } @@ -477,34 +484,31 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) receiver = popupChild; if (receiver != activePopupWidget) widgetPos = receiver->mapFromGlobal(event->globalPos()); - QWidget *alien = receiver; #if !defined(Q_OS_OSX) && !defined(Q_OS_IOS) // Cocoa tracks popups const bool reallyUnderMouse = activePopupWidget->rect().contains(mapped); const bool underMouse = activePopupWidget->underMouse(); - if (activePopupWidget != m_widget || (!underMouse && qt_button_down)) { - // If active popup menu is not the first-level popup menu then we must emulate enter/leave events, - // because first-level popup menu grabs the mouse and enter/leave events are delivered only to it - // by QPA. Make an exception for first-level popup menu when the mouse button is pressed on widget. - if (underMouse != reallyUnderMouse) { - if (reallyUnderMouse) { + if (underMouse != reallyUnderMouse) { + if (reallyUnderMouse) { + const QPoint receiverMapped = receiver->mapFromGlobal(event->screenPos().toPoint()); + // Prevent negative mouse position on enter event - this event + // should be properly handled in "handleEnterLeaveEvent()". + if (receiverMapped.x() >= 0 && receiverMapped.y() >= 0) { QApplicationPrivate::dispatchEnterLeave(receiver, Q_NULLPTR, event->screenPos()); qt_last_mouse_receiver = receiver; - } else { - QApplicationPrivate::dispatchEnterLeave(Q_NULLPTR, qt_last_mouse_receiver, event->screenPos()); - qt_last_mouse_receiver = receiver; - receiver = activePopupWidget; } + } else { + QApplicationPrivate::dispatchEnterLeave(Q_NULLPTR, qt_last_mouse_receiver, event->screenPos()); + qt_last_mouse_receiver = receiver; + receiver = activePopupWidget; } - } else if (!reallyUnderMouse) { - alien = Q_NULLPTR; } #endif QMouseEvent e(event->type(), widgetPos, event->windowPos(), event->screenPos(), event->button(), event->buttons(), event->modifiers(), event->source()); e.setTimestamp(event->timestamp()); - QApplicationPrivate::sendMouseEvent(receiver, &e, alien, receiver->window(), &qt_button_down, qt_last_mouse_receiver); + QApplicationPrivate::sendMouseEvent(receiver, &e, receiver, receiver->window(), &qt_button_down, qt_last_mouse_receiver); qt_last_mouse_receiver = receiver; } else { // close disabled popups when a mouse button is pressed or released @@ -881,10 +885,40 @@ void QWidgetWindow::handleDropEvent(QDropEvent *event) void QWidgetWindow::handleExposeEvent(QExposeEvent *event) { - if (isExposed()) { + QWidgetPrivate *wPriv = m_widget->d_func(); + const bool exposed = isExposed(); + + if (wPriv->childrenHiddenByWState) { + // If widgets has been previously hidden by window state change event + // and they aren't yet shown... + if (exposed) { + // If the window becomes exposed... + if (!wPriv->childrenShownByExpose) { + // ... and they haven't been shown by this function yet - show it. + wPriv->showChildren(true); + QShowEvent showEvent; + QCoreApplication::sendSpontaneousEvent(m_widget, &showEvent); + wPriv->childrenShownByExpose = true; + } + } else { + // If the window becomes not exposed... + if (wPriv->childrenShownByExpose) { + // ... and child widgets was previously shown by the expose event - hide widgets again. + // This is a workaround, because sometimes when window is minimized programatically, + // the QPA can notify that the window is exposed after changing window state to minimized + // and then, the QPA can send next expose event with null exposed region (not exposed). + wPriv->hideChildren(true); + QHideEvent hideEvent; + QCoreApplication::sendSpontaneousEvent(m_widget, &hideEvent); + wPriv->childrenShownByExpose = false; + } + } + } + + if (exposed) { m_widget->setAttribute(Qt::WA_Mapped); if (!event->region().isNull()) - m_widget->d_func()->syncBackingStore(event->region()); + wPriv->syncBackingStore(event->region()); } else { m_widget->setAttribute(Qt::WA_Mapped, false); } diff --git a/src/widgets/styles/qstyleoption.h b/src/widgets/styles/qstyleoption.h index b03e2cc860..8f41f379bc 100644 --- a/src/widgets/styles/qstyleoption.h +++ b/src/widgets/styles/qstyleoption.h @@ -670,7 +670,7 @@ T qstyleoption_cast(const QStyleOption *opt) || (int(Opt::Type) == QStyleOption::SO_Complex && opt->type > QStyleOption::SO_Complex))) return static_cast<T>(opt); - return 0; + return Q_NULLPTR; } template <typename T> @@ -682,7 +682,7 @@ T qstyleoption_cast(QStyleOption *opt) || (int(Opt::Type) == QStyleOption::SO_Complex && opt->type > QStyleOption::SO_Complex))) return static_cast<T>(opt); - return 0; + return Q_NULLPTR; } // -------------------------- QStyleHintReturn ------------------------------- @@ -731,7 +731,7 @@ T qstyleoption_cast(const QStyleHintReturn *hint) if (hint && hint->version <= Opt::Version && (hint->type == Opt::Type || int(Opt::Type) == QStyleHintReturn::SH_Default)) return static_cast<T>(hint); - return 0; + return Q_NULLPTR; } template <typename T> @@ -741,7 +741,7 @@ T qstyleoption_cast(QStyleHintReturn *hint) if (hint && hint->version <= Opt::Version && (hint->type == Opt::Type || int(Opt::Type) == QStyleHintReturn::SH_Default)) return static_cast<T>(hint); - return 0; + return Q_NULLPTR; } #if !defined(QT_NO_DEBUG_STREAM) diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index 95e9a0916a..eba17783ec 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -76,22 +76,6 @@ QT_BEGIN_NAMESPACE QMenu *QMenuPrivate::mouseDown = 0; -QPointer<QMenu> QMenuPrivate::previousMouseMenu(Q_NULLPTR); -static void handleEnterLeaveEvents(QPointer<QMenu> *previous_ptr, QMenu *next) -{ - QWidget *previous = previous_ptr->data(); - if (previous != next) { - if (previous) { - QEvent leaveEvent(QEvent::Leave); - QApplication::sendEvent(previous, &leaveEvent); - } - if (next) { - QEvent enterEvent(QEvent::Enter); - QApplication::sendEvent(next, &enterEvent); - } - } - *previous_ptr = next; -} /* QMenu code */ // internal class used for the torn off popup @@ -510,8 +494,6 @@ void QMenuPrivate::hideMenu(QMenu *menu) menu->d_func()->causedPopup.action = 0; menu->close(); menu->d_func()->causedPopup.widget = 0; - if (previousMouseMenu.data() == menu) - handleEnterLeaveEvents(&previousMouseMenu, Q_NULLPTR); } void QMenuPrivate::popupAction(QAction *action, int delay, bool activateFirst) @@ -677,10 +659,26 @@ void QMenuSloppyState::enter() m_parent->childEnter(); } +void QMenuSloppyState::childEnter() +{ + stopTimer(); + if (m_parent) + m_parent->childEnter(); +} + +void QMenuSloppyState::leave() +{ + if (!m_dont_start_time_on_leave) { + if (m_parent) + m_parent->childLeave(); + startTimerIfNotRunning(); + } +} + void QMenuSloppyState::childLeave() { if (m_enabled && !QMenuPrivate::get(m_menu)->hasReceievedEnter) { - startTimer(); + startTimerIfNotRunning(); if (m_parent) m_parent->childLeave(); } @@ -726,8 +724,17 @@ public: void QMenuSloppyState::timeout() { QMenuPrivate *menu_priv = QMenuPrivate::get(m_menu); + + bool reallyHasMouse = menu_priv->hasReceievedEnter; + if (!reallyHasMouse) { + // Check whether the menu really has a mouse, because only active popup + // menu gets the enter/leave events. Currently Cocoa is an exception. + const QPoint lastCursorPos = QGuiApplicationPrivate::lastCursorPosition.toPoint(); + reallyHasMouse = m_menu->frameGeometry().contains(lastCursorPos); + } + if (menu_priv->currentAction == m_reset_action - && menu_priv->hasReceievedEnter + && reallyHasMouse && (menu_priv->currentAction && menu_priv->currentAction->menu() == menu_priv->activeMenu)) { return; @@ -735,13 +742,13 @@ void QMenuSloppyState::timeout() ResetOnDestroy resetState(this, &m_init_guard); - if (hasParentActiveDelayTimer() || !m_menu || !m_menu->isVisible()) + if (hasParentActiveDelayTimer() || !m_menu->isVisible()) return; if (m_sub_menu) menu_priv->hideMenu(m_sub_menu); - if (menu_priv->hasReceievedEnter) + if (reallyHasMouse) menu_priv->setCurrentAction(m_reset_action,0); else menu_priv->setCurrentAction(Q_NULLPTR, 0); @@ -1095,10 +1102,8 @@ bool QMenuPrivate::mouseEventTaken(QMouseEvent *e) tearoffHighlighted = 0; } - if (q->frameGeometry().contains(e->globalPos())) { //otherwise if the event is in our rect we want it.. - handleEnterLeaveEvents(&previousMouseMenu, q); - return false; - } + if (q->frameGeometry().contains(e->globalPos())) + return false; //otherwise if the event is in our rect we want it.. for(QWidget *caused = causedPopup.widget; caused;) { bool passOnEvent = false; @@ -1114,17 +1119,16 @@ bool QMenuPrivate::mouseEventTaken(QMouseEvent *e) next_widget = m->d_func()->causedPopup.widget; } if (passOnEvent) { - handleEnterLeaveEvents(&previousMouseMenu,qobject_cast<QMenu *>(caused)); - if(e->type() != QEvent::MouseButtonRelease || mouseDown == caused) { - QMouseEvent new_e(e->type(), cpos, caused->mapTo(caused->topLevelWidget(), cpos), e->screenPos(), - e->button(), e->buttons(), e->modifiers(), e->source()); - QApplication::sendEvent(caused, &new_e); - return true; + if (e->type() != QEvent::MouseButtonRelease || mouseDown == caused) { + QMouseEvent new_e(e->type(), cpos, caused->mapTo(caused->topLevelWidget(), cpos), e->screenPos(), + e->button(), e->buttons(), e->modifiers(), e->source()); + QApplication::sendEvent(caused, &new_e); + return true; } } caused = next_widget; if (!caused) - handleEnterLeaveEvents(&previousMouseMenu, Q_NULLPTR); + sloppyState.leave(); // Start timers } return false; } @@ -3211,7 +3215,6 @@ void QMenu::enterEvent(QEvent *) Q_D(QMenu); d->hasReceievedEnter = true; d->sloppyState.enter(); - d->sloppyState.startTimer(); d->motions = -1; // force us to ignore the generate mouse move in mouseMoveEvent() } @@ -3222,7 +3225,6 @@ void QMenu::leaveEvent(QEvent *) { Q_D(QMenu); d->hasReceievedEnter = false; - d->sloppyState.leave(); if (!d->activeMenu && d->currentAction) setActiveAction(0); } @@ -3395,10 +3397,18 @@ void QMenu::internalDelayedPopup() const QRect actionRect(d->actionRect(d->currentAction)); const QPoint rightPos(mapToGlobal(QPoint(actionRect.right() + subMenuOffset + 1, actionRect.top()))); - QPoint pos(rightPos); - - d->activeMenu->popup(pos); + d->activeMenu->popup(rightPos); d->sloppyState.setSubMenuPopup(actionRect, d->currentAction, d->activeMenu); + +#if !defined(Q_OS_DARWIN) + // Send the leave event to the current menu - only active popup menu gets + // mouse enter/leave events. Currently Cocoa is an exception, so disable + // it there to avoid event duplication. + if (underMouse()) { + QEvent leaveEvent(QEvent::Leave); + QCoreApplication::sendEvent(this, &leaveEvent); + } +#endif } /*! diff --git a/src/widgets/widgets/qmenu_p.h b/src/widgets/widgets/qmenu_p.h index 0705cd12ea..56904f51d6 100644 --- a/src/widgets/widgets/qmenu_p.h +++ b/src/widgets/widgets/qmenu_p.h @@ -128,8 +128,6 @@ public: void reset(); bool enabled() const { return m_enabled; } - void setResetAction(QAction *action) { m_reset_action = action; } - enum MouseEventResult { EventIsProcessed, EventShouldBePropagated, @@ -154,22 +152,9 @@ public: } void enter(); + void childEnter(); - void childEnter() - { - stopTimer(); - if (m_parent) - m_parent->childEnter(); - } - - void leave() - { - if (m_dont_start_time_on_leave) - return; - if (m_parent) - m_parent->childLeave(); - startTimer(); - } + void leave(); void childLeave(); static float slope(const QPointF &p1, const QPointF &p2) @@ -195,8 +180,7 @@ public: if (!m_enabled) return EventShouldBePropagated; - if (!m_time.isActive()) - startTimer(); + startTimerIfNotRunning(); if (!m_sub_menu) { reset(); @@ -499,7 +483,6 @@ public: QAction* wceCommands(uint command); #endif QPointer<QWidget> noReplayFor; - static QPointer<QMenu> previousMouseMenu; }; #endif // QT_NO_MENU diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index 0e7b25f65d..8b5f370fc3 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -1010,13 +1010,11 @@ void QMenuBar::paintEvent(QPaintEvent *e) */ void QMenuBar::setVisible(bool visible) { -#if defined(Q_OS_MAC) || defined(Q_OS_WINCE) if (isNativeMenuBar()) { if (!visible) QWidget::setVisible(false); return; } -#endif QWidget::setVisible(visible); } @@ -1566,11 +1564,7 @@ QRect QMenuBar::actionGeometry(QAction *act) const QSize QMenuBar::minimumSizeHint() const { Q_D(const QMenuBar); -#if defined(Q_OS_MAC) || defined(Q_OS_WINCE) const bool as_gui_menubar = !isNativeMenuBar(); -#else - const bool as_gui_menubar = true; -#endif ensurePolished(); QSize ret(0, 0); @@ -1622,12 +1616,7 @@ QSize QMenuBar::minimumSizeHint() const QSize QMenuBar::sizeHint() const { Q_D(const QMenuBar); -#if defined(Q_OS_MAC) || defined(Q_OS_WINCE) const bool as_gui_menubar = !isNativeMenuBar(); -#else - const bool as_gui_menubar = true; -#endif - ensurePolished(); QSize ret(0, 0); @@ -1680,11 +1669,7 @@ QSize QMenuBar::sizeHint() const int QMenuBar::heightForWidth(int) const { Q_D(const QMenuBar); -#if defined(Q_OS_MAC) || defined(Q_OS_WINCE) const bool as_gui_menubar = !isNativeMenuBar(); -#else - const bool as_gui_menubar = true; -#endif const_cast<QMenuBarPrivate*>(d)->updateGeometries(); int height = 0; @@ -1830,10 +1815,8 @@ QWidget *QMenuBar::cornerWidget(Qt::Corner corner) const void QMenuBar::setNativeMenuBar(bool nativeMenuBar) { Q_D(QMenuBar); - if (d->nativeMenuBar == -1 || (nativeMenuBar != bool(d->nativeMenuBar))) { - d->nativeMenuBar = nativeMenuBar; - - if (!d->nativeMenuBar) { + if (nativeMenuBar != bool(d->platformMenuBar)) { + if (!nativeMenuBar) { delete d->platformMenuBar; d->platformMenuBar = 0; } else { @@ -1842,7 +1825,7 @@ void QMenuBar::setNativeMenuBar(bool nativeMenuBar) } updateGeometry(); - if (!d->nativeMenuBar && parentWidget()) + if (!nativeMenuBar && parentWidget()) setVisible(true); } } @@ -1850,10 +1833,7 @@ void QMenuBar::setNativeMenuBar(bool nativeMenuBar) bool QMenuBar::isNativeMenuBar() const { Q_D(const QMenuBar); - if (d->nativeMenuBar == -1) { - return !QApplication::instance()->testAttribute(Qt::AA_DontUseNativeMenuBar); - } - return d->nativeMenuBar; + return bool(d->platformMenuBar); } /*! diff --git a/src/widgets/widgets/qmenubar_p.h b/src/widgets/widgets/qmenubar_p.h index c88e4af836..bdff169451 100644 --- a/src/widgets/widgets/qmenubar_p.h +++ b/src/widgets/widgets/qmenubar_p.h @@ -65,7 +65,7 @@ class QMenuBarPrivate : public QWidgetPrivate public: QMenuBarPrivate() : itemsDirty(0), currentAction(0), mouseDown(0), closePopupMode(0), defaultPopDown(1), popupState(0), keyboardState(0), altPressed(0), - nativeMenuBar(-1), doChildEffects(false), platformMenuBar(0) + doChildEffects(false), platformMenuBar(0) #ifdef Q_OS_WINCE , wce_menubar(0), wceClassicMenu(false) @@ -108,8 +108,6 @@ public: uint keyboardState : 1, altPressed : 1; QPointer<QWidget> keyboardFocusWidget; - - int nativeMenuBar : 3; // Only has values -1, 0, and 1 //firing of events void activateAction(QAction *, QAction::ActionEvent); diff --git a/src/widgets/widgets/qtabbar.cpp b/src/widgets/widgets/qtabbar.cpp index 11700fe6f1..e51f484f6f 100644 --- a/src/widgets/widgets/qtabbar.cpp +++ b/src/widgets/widgets/qtabbar.cpp @@ -1958,9 +1958,8 @@ void QTabBar::mouseMoveEvent(QMouseEvent *event) } } - int offset = (event->pos() - d->dragStartPosition).manhattanLength(); if (event->buttons() == Qt::LeftButton - && offset > QApplication::startDragDistance() + && d->dragInProgress && d->validIndex(d->pressedIndex)) { bool vertical = verticalTabs(d->shape); int dragDistance; diff --git a/src/widgets/widgets/qtoolbutton.cpp b/src/widgets/widgets/qtoolbutton.cpp index 8b40325a24..80a061e6d5 100644 --- a/src/widgets/widgets/qtoolbutton.cpp +++ b/src/widgets/widgets/qtoolbutton.cpp @@ -196,7 +196,6 @@ QToolButton::QToolButton(QWidget * parent) void QToolButtonPrivate::init() { Q_Q(QToolButton); - delay = q->style()->styleHint(QStyle::SH_ToolButton_PopupDelay, 0, q); defaultAction = 0; #ifndef QT_NO_TOOLBAR if (qobject_cast<QToolBar*>(parent)) @@ -222,7 +221,7 @@ void QToolButtonPrivate::init() #endif setLayoutItemMargins(QStyle::SE_ToolButtonLayoutItem); - + delay = q->style()->styleHint(QStyle::SH_ToolButton_PopupDelay, 0, q); } /*! |