summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/windows/qwindowsmousehandler.cpp
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@digia.com>2012-10-01 17:09:24 +0300
committerThe Qt Project <gerrit-noreply@qt-project.org>2012-10-04 14:24:44 +0200
commitc1197677901648893856084178291078035f2bc2 (patch)
treee0d9bda443f4b11feb733652fa22a29f3aab1f2d /src/plugins/platforms/windows/qwindowsmousehandler.cpp
parentdcc2e84fd0cdc90d633d2e5992ab1fc03e2aa861 (diff)
Fix Windows mouse enter/leave event generation
QWidget::underMouse() did not report correct widget in cases where mouse was grabbed by popup, which was especially disruptive in case of QCompleter popup, as that wouldn't close anymore with off-popup clicks. Root problem was that mouse capture in Windows caused enter/leave events for QWindows to be generated incorrectly. QPlatformWindow documentation specifies that enter/leave events should be sent independent of explicit mouse grabs and only automatic mouse grabbing done when button is pressed should suppress enter/leave events. Updated Windows mouse handling to conform to this. Task-number: QTBUG-27283 Change-Id: Iecf786a702f7d29e6026c42ff8ec4c9cbf1b6ac3 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
Diffstat (limited to 'src/plugins/platforms/windows/qwindowsmousehandler.cpp')
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.cpp82
1 files changed, 58 insertions, 24 deletions
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
index 52172320af..55cf3a3a53 100644
--- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
@@ -44,6 +44,7 @@
#include "qwindowscontext.h"
#include "qwindowswindow.h"
#include "qwindowsintegration.h"
+#include "qwindowsscreen.h"
#include <qpa/qwindowsysteminterface.h>
#include <QtGui/QGuiApplication>
@@ -127,6 +128,7 @@ static inline void compressMouseMove(MSG *msg)
QWindowsMouseHandler::QWindowsMouseHandler() :
m_windowUnderMouse(0),
+ m_trackedWindow(0),
m_touchDevice(0)
{
}
@@ -162,20 +164,32 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
return false; // Allow further event processing (dragging of windows).
}
+
*result = 0;
if (msg.message == WM_MOUSELEAVE) {
- // When moving out of a child, MouseMove within parent is received first
- // (see below)
if (QWindowsContext::verboseEvents)
- qDebug() << "WM_MOUSELEAVE for " << window << " current= " << m_windowUnderMouse;
- if (window == m_windowUnderMouse) {
- QWindowSystemInterface::handleLeaveEvent(window);
+ qDebug() << "WM_MOUSELEAVE for " << window << " previous window under mouse = " << m_windowUnderMouse << " tracked window =" << m_trackedWindow;
+
+ // When moving out of a window, WM_MOUSEMOVE within the moved-to window is received first,
+ // so if m_trackedWindow is not the window here, it means the cursor has left the
+ // application.
+ if (window == m_trackedWindow) {
+ QWindow *leaveTarget = m_windowUnderMouse ? m_windowUnderMouse : m_trackedWindow;
+ if (QWindowsContext::verboseEvents)
+ qDebug() << "Generating leave event for " << leaveTarget;
+ QWindowSystemInterface::handleLeaveEvent(leaveTarget);
+ m_trackedWindow = 0;
m_windowUnderMouse = 0;
}
return true;
}
- compressMouseMove(&msg);
+
QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle());
+ const QPoint globalPosition = QWindowsGeometryHint::mapToGlobal(hwnd, winEventPosition);
+ QWindow *currentWindowUnderMouse = platformWindow->hasMouseCapture() ?
+ QWindowsScreen::windowAt(globalPosition) : window;
+
+ compressMouseMove(&msg);
// Qt expects the platform plugin to capture the mouse on
// any button press until release.
if (!platformWindow->hasMouseCapture()
@@ -202,22 +216,13 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
return true;
}
}
- // Enter new window: track to generate leave event.
- if (m_windowUnderMouse != window) {
- // The tracking on m_windowUnderMouse might still be active and
- // trigger later on.
- if (m_windowUnderMouse) {
- if (QWindowsContext::verboseEvents)
- qDebug() << "Synthetic leave for " << m_windowUnderMouse;
- QWindowSystemInterface::handleLeaveEvent(m_windowUnderMouse);
- }
- m_windowUnderMouse = window;
- if (QWindowsContext::verboseEvents)
- qDebug() << "Entering " << window;
- QWindowsWindow::baseWindowOf(window)->applyCursor();
-//#ifndef Q_OS_WINCE
- QWindowSystemInterface::handleEnterEvent(window);
+
#ifndef Q_OS_WINCE
+ // Enter new window: track to generate leave event.
+ // If there is an active capture, we must track the actual capture window instead of window
+ // under cursor or leaves will trigger constantly, so always track the window we got
+ // native mouse event for.
+ if (window != m_trackedWindow) {
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
@@ -225,11 +230,40 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
tme.dwHoverTime = HOVER_DEFAULT; //
if (!TrackMouseEvent(&tme))
qWarning("TrackMouseEvent failed.");
+ m_trackedWindow = window;
+ }
#endif // !Q_OS_WINCE
+
+ // Qt expects enter/leave events for windows even when some window is capturing mouse input,
+ // except for automatic capture when mouse button is pressed - in that case enter/leave
+ // should be sent only after the last button is released.
+ // We need to track m_windowUnderMouse separately from m_trackedWindow, as
+ // Windows mouse tracking will not trigger WM_MOUSELEAVE for leaving window when
+ // mouse capture is set.
+ if (!platformWindow->hasMouseCapture()
+ || !platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)) {
+ if (m_windowUnderMouse != currentWindowUnderMouse) {
+ if (m_windowUnderMouse) {
+ if (QWindowsContext::verboseEvents)
+ qDebug() << "Synthetic leave for " << m_windowUnderMouse;
+ QWindowSystemInterface::handleLeaveEvent(m_windowUnderMouse);
+ // Clear tracking if we are no longer over application,
+ // since we have already sent the leave.
+ if (!currentWindowUnderMouse)
+ m_trackedWindow = 0;
+ }
+
+ if (currentWindowUnderMouse) {
+ if (QWindowsContext::verboseEvents)
+ qDebug() << "Entering " << currentWindowUnderMouse;
+ QWindowsWindow::baseWindowOf(currentWindowUnderMouse)->applyCursor();
+ QWindowSystemInterface::handleEnterEvent(currentWindowUnderMouse);
+ }
+ }
+ m_windowUnderMouse = currentWindowUnderMouse;
}
- const QPoint clientPosition = winEventPosition;
- QWindowSystemInterface::handleMouseEvent(window, clientPosition,
- QWindowsGeometryHint::mapToGlobal(hwnd, clientPosition),
+
+ QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition,
keyStateToMouseButtons((int)msg.wParam),
QWindowsKeyMapper::queryKeyboardModifiers());
return true;