summaryrefslogtreecommitdiffstats
path: root/src/widgets
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@theqtcompany.com>2016-02-24 14:47:20 +0000
committerThe Qt Project <gerrit-noreply@qt-project.org>2016-02-24 14:47:20 +0000
commitb736151c2bb6c68f700d38274d740a6e0cf59a49 (patch)
tree83e110a7205757addba6e86a3c2367e4b52afa05 /src/widgets
parentff76300a5c9f209f625384f35ad0fdb0acebd799 (diff)
parent1fadc7292b66d4b3984bf5ef36c70b46b07a1c6b (diff)
Merge "Merge remote-tracking branch 'origin/5.6' into 5.7" into refs/staging/5.7
Diffstat (limited to 'src/widgets')
-rw-r--r--src/widgets/kernel/qwidgetwindow.cpp71
-rw-r--r--src/widgets/widgets/qmenu_mac.mm10
2 files changed, 64 insertions, 17 deletions
diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp
index 0bc05cc3b5..90473c6642 100644
--- a/src/widgets/kernel/qwidgetwindow.cpp
+++ b/src/widgets/kernel/qwidgetwindow.cpp
@@ -319,6 +319,14 @@ QPointer<QWidget> qt_last_mouse_receiver = 0;
void QWidgetWindow::handleEnterLeaveEvent(QEvent *event)
{
+#if !defined(Q_OS_OSX) && !defined(Q_OS_IOS) // Cocoa tracks popups
+ // Ignore all enter/leave events from QPA if we are not on the first-level context menu.
+ // This prevents duplicated events on most platforms. Fake events will be delivered in
+ // QWidgetWindow::handleMouseEvent(QMouseEvent *). Make an exception whether the widget
+ // is already under mouse - let the mouse leave.
+ if (QApplicationPrivate::inPopupMode() && m_widget != QApplication::activePopupWidget() && !m_widget->underMouse())
+ return;
+#endif
if (event->type() == QEvent::Leave) {
QWidget *enter = 0;
// Check from window system event queue if the next queued enter targets a window
@@ -413,14 +421,13 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
QEvent::MouseButtonRelease : QEvent::MouseButtonPress;
if (qApp->d_func()->inPopupMode()) {
QWidget *activePopupWidget = qApp->activePopupWidget();
- QWidget *popup = activePopupWidget;
QPoint mapped = event->pos();
- if (popup != m_widget)
- mapped = popup->mapFromGlobal(event->globalPos());
+ if (activePopupWidget != m_widget)
+ mapped = activePopupWidget->mapFromGlobal(event->globalPos());
bool releaseAfter = false;
- QWidget *popupChild = popup->childAt(mapped);
+ QWidget *popupChild = activePopupWidget->childAt(mapped);
- if (popup != qt_popup_down) {
+ if (activePopupWidget != qt_popup_down) {
qt_button_down = 0;
qt_popup_down = 0;
}
@@ -429,7 +436,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
case QEvent::MouseButtonPress:
case QEvent::MouseButtonDblClick:
qt_button_down = popupChild;
- qt_popup_down = popup;
+ qt_popup_down = activePopupWidget;
break;
case QEvent::MouseButtonRelease:
releaseAfter = true;
@@ -440,18 +447,41 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
int oldOpenPopupCount = openPopupCount;
- if (popup->isEnabled()) {
+ if (activePopupWidget->isEnabled()) {
// deliver event
qt_replay_popup_mouse_event = false;
- QWidget *receiver = popup;
+ QWidget *receiver = activePopupWidget;
QPoint widgetPos = mapped;
if (qt_button_down)
receiver = qt_button_down;
else if (popupChild)
receiver = popupChild;
- if (receiver != popup)
+ if (receiver != activePopupWidget)
widgetPos = receiver->mapFromGlobal(event->globalPos());
- QWidget *alien = m_widget->childAt(m_widget->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) {
+ 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 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());
@@ -463,7 +493,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
case QEvent::MouseButtonPress:
case QEvent::MouseButtonDblClick:
case QEvent::MouseButtonRelease:
- popup->close();
+ activePopupWidget->close();
break;
default:
break;
@@ -509,7 +539,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
} else if (event->type() == contextMenuTrigger
&& event->button() == Qt::RightButton
&& (openPopupCount == oldOpenPopupCount)) {
- QWidget *popupEvent = popup;
+ QWidget *popupEvent = activePopupWidget;
if (qt_button_down)
popupEvent = qt_button_down;
else if(popupChild)
@@ -727,13 +757,24 @@ void QWidgetWindow::handleWheelEvent(QWheelEvent *event)
if (QApplicationPrivate::instance()->modalState() && !qt_try_modal(m_widget, event->type()))
return;
+ QWidget *rootWidget = m_widget;
+ QPoint pos = event->pos();
+
+ // Use proper popup window for wheel event. Some QPA sends the wheel
+ // event to the root menu, so redirect it to the proper popup window.
+ QWidget *activePopupWidget = QApplication::activePopupWidget();
+ if (activePopupWidget && activePopupWidget != m_widget) {
+ rootWidget = activePopupWidget;
+ pos = rootWidget->mapFromGlobal(event->globalPos());
+ }
+
// which child should have it?
- QWidget *widget = m_widget->childAt(event->pos());
+ QWidget *widget = rootWidget->childAt(pos);
if (!widget)
- widget = m_widget;
+ widget = rootWidget;
- QPoint mapped = widget->mapFrom(m_widget, event->pos());
+ QPoint mapped = widget->mapFrom(rootWidget, pos);
QWheelEvent translated(mapped, event->globalPos(), event->pixelDelta(), event->angleDelta(), event->delta(), event->orientation(), event->buttons(), event->modifiers(), event->phase(), event->source());
QGuiApplication::sendSpontaneousEvent(widget, &translated);
diff --git a/src/widgets/widgets/qmenu_mac.mm b/src/widgets/widgets/qmenu_mac.mm
index c24779d61f..29f5913b5d 100644
--- a/src/widgets/widgets/qmenu_mac.mm
+++ b/src/widgets/widgets/qmenu_mac.mm
@@ -73,8 +73,11 @@ inline QPlatformNativeInterface::NativeResourceForIntegrationFunction resolvePla
\since 5.2
Returns the native NSMenu for this menu. Available on OS X only.
+
+ \note Qt sets the delegate on the native menu. If you need to set your own
+ delegate, make sure you save the original one and forward any calls to it.
*/
-NSMenu* QMenu::toNSMenu()
+NSMenu *QMenu::toNSMenu()
{
// Call into the cocoa platform plugin: qMenuToNSMenu(platformMenu())
QPlatformNativeInterface::NativeResourceForIntegrationFunction function = resolvePlatformFunction("qmenutonsmenu");
@@ -139,8 +142,11 @@ void QMenuPrivate::moveWidgetToPlatformItem(QWidget *widget, QPlatformMenuItem*
\since 5.2
Returns the native NSMenu for this menu bar. Available on OS X only.
+
+ \note Qt may set the delegate on the native menu bar. If you need to set your
+ own delegate, make sure you save the original one and forward any calls to it.
*/
-NSMenu* QMenuBar::toNSMenu()
+NSMenu *QMenuBar::toNSMenu()
{
// Call into the cocoa platform plugin: qMenuBarToNSMenu(platformMenuBar())
QPlatformNativeInterface::NativeResourceForIntegrationFunction function = resolvePlatformFunction("qmenubartonsmenu");