Add framestrut mouse events.
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>
Wed, 27 Jun 2012 14:20:18 +0000 (16:20 +0200)
committerQt by Nokia <qt-info@nokia.com>
Fri, 29 Jun 2012 14:22:19 +0000 (16:22 +0200)
- Add infrastructure to QWindowSystemInterface.
- Add a setter for enabling framestrut events
  to QPlatformWindow.
- Add Windows implementation, pass keyboard modifiers.

QDockWidget relies on it for docking.

Task-number: QTBUG-26296
Change-Id: I9d84b356e9a5eb341f57b6f51f34b6b494ff7f87
Reviewed-by: Jørgen Lind <jorgen.lind@nokia.com>
14 files changed:
src/gui/kernel/qguiapplication.cpp
src/gui/kernel/qplatformwindow.h
src/gui/kernel/qplatformwindow_qpa.cpp
src/gui/kernel/qwindowsysteminterface_qpa.cpp
src/gui/kernel/qwindowsysteminterface_qpa.h
src/gui/kernel/qwindowsysteminterface_qpa_p.h
src/plugins/platforms/windows/qwindowscontext.cpp
src/plugins/platforms/windows/qwindowsmousehandler.cpp
src/plugins/platforms/windows/qwindowsmousehandler.h
src/plugins/platforms/windows/qwindowswindow.cpp
src/plugins/platforms/windows/qwindowswindow.h
src/widgets/kernel/qwidgetwindow_qpa.cpp
src/widgets/kernel/qwidgetwindow_qpa_p.h
src/widgets/widgets/qdockwidget.cpp

index a3d9c1f..a27a855 100644 (file)
@@ -1098,6 +1098,7 @@ bool QGuiApplicationPrivate::processNativeEvent(QWindow *window, const QByteArra
 void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e)
 {
     switch(e->type) {
+    case QWindowSystemInterfacePrivate::FrameStrutMouse:
     case QWindowSystemInterfacePrivate::Mouse:
         QGuiApplicationPrivate::processMouseEvent(static_cast<QWindowSystemInterfacePrivate::MouseEvent *>(e));
         break;
@@ -1179,9 +1180,10 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
     QEvent::Type type;
     // move first
     Qt::MouseButtons stateChange = e->buttons ^ buttons;
+    const bool frameStrut = e->type == QWindowSystemInterfacePrivate::FrameStrutMouse;
     if (e->globalPos != QGuiApplicationPrivate::lastCursorPosition && (stateChange != Qt::NoButton)) {
         QWindowSystemInterfacePrivate::MouseEvent * newMouseEvent =
-                new QWindowSystemInterfacePrivate::MouseEvent(e->window.data(), e->timestamp, e->localPos, e->globalPos, e->buttons, e->modifiers);
+                new QWindowSystemInterfacePrivate::MouseEvent(e->window.data(), e->timestamp, e->type, e->localPos, e->globalPos, e->buttons, e->modifiers);
         QWindowSystemInterfacePrivate::windowSystemEventQueue.prepend(newMouseEvent); // just in case the move triggers a new event loop
         stateChange = Qt::NoButton;
     }
@@ -1204,7 +1206,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
     bool doubleClick = false;
 
     if (QGuiApplicationPrivate::lastCursorPosition != globalPoint) {
-        type = QEvent::MouseMove;
+        type = frameStrut ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove;
         QGuiApplicationPrivate::lastCursorPosition = globalPoint;
         if (qAbs(globalPoint.x() - mousePressX) > mouse_double_click_distance||
             qAbs(globalPoint.y() - mousePressY) > mouse_double_click_distance)
@@ -1226,14 +1228,14 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
         if (button & e->buttons) {
             ulong doubleClickInterval = static_cast<ulong>(qApp->styleHints()->mouseDoubleClickInterval());
             doubleClick = e->timestamp - mousePressTime < doubleClickInterval && button == mousePressButton;
-            type = QEvent::MouseButtonPress;
+            type = frameStrut ? QEvent::NonClientAreaMouseButtonPress : QEvent::MouseButtonPress;
             mousePressTime = e->timestamp;
             mousePressButton = button;
             const QPoint point = QGuiApplicationPrivate::lastCursorPosition.toPoint();
             mousePressX = point.x();
             mousePressY = point.y();
         } else {
-            type = QEvent::MouseButtonRelease;
+            type = frameStrut ? QEvent::NonClientAreaMouseButtonRelease : QEvent::MouseButtonRelease;
         }
     }
 
@@ -1253,7 +1255,9 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
             cursor->pointerEvent(ev);
 #endif
     QGuiApplication::sendSpontaneousEvent(window, &ev);
-    if (!e->synthetic && !ev.isAccepted() && qApp->testAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents)) {
+    if (!e->synthetic && !ev.isAccepted()
+        && !frameStrut
+        && qApp->testAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents)) {
         if (!m_fakeTouchDevice) {
             m_fakeTouchDevice = new QTouchDevice;
             QWindowSystemInterface::registerTouchDevice(m_fakeTouchDevice);
@@ -1287,7 +1291,8 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
     }
     if (doubleClick) {
         mousePressButton = Qt::NoButton;
-        QMouseEvent dblClickEvent(QEvent::MouseButtonDblClick, localPoint, localPoint, globalPoint,
+        const QEvent::Type doubleClickType = frameStrut ? QEvent::NonClientAreaMouseButtonDblClick : QEvent::MouseButtonDblClick;
+        QMouseEvent dblClickEvent(doubleClickType, localPoint, localPoint, globalPoint,
                                   button, buttons, e->modifiers);
         dblClickEvent.setTimestamp(e->timestamp);
         QGuiApplication::sendSpontaneousEvent(window, &dblClickEvent);
index cded1fe..a6a519e 100644 (file)
@@ -122,6 +122,9 @@ public:
 
     virtual bool startSystemResize(const QPoint &pos, Qt::Corner corner);
 
+    virtual void setFrameStrutEventsEnabled(bool enabled);
+    virtual bool frameStrutEventsEnabled() const;
+
 protected:
     QScopedPointer<QPlatformWindowPrivate> d_ptr;
 private:
index d2ec683..3c2246c 100644 (file)
@@ -374,6 +374,29 @@ bool QPlatformWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
 }
 
 /*!
+    Reimplement this method to set whether frame strut events
+    should be sent to \a enabled.
+
+    \sa frameStrutEventsEnabled
+*/
+
+void QPlatformWindow::setFrameStrutEventsEnabled(bool enabled)
+{
+    if (enabled)
+        qWarning("This plugin does not support frame strut events.");
+}
+
+/*!
+    Reimplement this method to return whether
+    frame strut events are enabled.
+*/
+
+bool QPlatformWindow::frameStrutEventsEnabled() const
+{
+    return false;
+}
+
+/*!
     \class QPlatformWindow
     \since 4.8
     \internal
index c707d4e..139df98 100644 (file)
@@ -149,6 +149,21 @@ void QWindowSystemInterface::handleMouseEvent(QWindow *w, ulong timestamp, const
     QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
 }
 
+void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
+{
+    const unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
+    handleFrameStrutMouseEvent(w, time, local, global, b, mods);
+}
+
+void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
+{
+    QWindowSystemInterfacePrivate::MouseEvent * e =
+            new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp,
+                                                          QWindowSystemInterfacePrivate::FrameStrutMouse,
+                                                          local, global, b, mods);
+    QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
+}
+
 bool QWindowSystemInterface::tryHandleSynchronousShortcutEvent(QWindow *w, int k, Qt::KeyboardModifiers mods,
                                                                const QString & text, bool autorep, ushort count)
 {
index 34587f6..b55f3e3 100644 (file)
@@ -68,6 +68,8 @@ class Q_GUI_EXPORT QWindowSystemInterface
 public:
     static void handleMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier);
     static void handleMouseEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier);
+    static void handleFrameStrutMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier);
+    static void handleFrameStrutMouseEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier);
 
     static bool tryHandleSynchronousShortcutEvent(QWindow *w, int k, Qt::KeyboardModifiers mods,
                                                   const QString & text = QString(), bool autorep = false, ushort count = 1);
index 919a7de..8fb0652 100644 (file)
@@ -60,6 +60,7 @@ public:
         ActivatedWindow,
         WindowStateChanged,
         Mouse,
+        FrameStrutMouse,
         Wheel,
         Key,
         Touch,
@@ -156,6 +157,9 @@ public:
         MouseEvent(QWindow * w, ulong time, const QPointF & local, const QPointF & global,
                    Qt::MouseButtons b, Qt::KeyboardModifiers mods)
             : InputEvent(w, time, Mouse, mods), localPos(local), globalPos(global), buttons(b) { }
+        MouseEvent(QWindow * w, ulong time, EventType t, const QPointF & local, const QPointF & global,
+                   Qt::MouseButtons b, Qt::KeyboardModifiers mods)
+            : InputEvent(w, time, t, mods), localPos(local), globalPos(global), buttons(b) { }
         QPointF localPos;
         QPointF globalPos;
         Qt::MouseButtons buttons;
index 8917532..ba32369 100644 (file)
@@ -817,9 +817,12 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
 #endif
     case QtWindows::ExposeEvent:
         return platformWindow->handleWmPaint(hwnd, message, wParam, lParam);
+    case QtWindows::NonClientMouseEvent:
+        if (platformWindow->frameStrutEventsEnabled())
+            return d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
+        break;
     case QtWindows::MouseWheelEvent:
     case QtWindows::MouseEvent:
-    case QtWindows::NonClientMouseEvent:
     case QtWindows::LeaveEvent:
         return d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
     case QtWindows::TouchEvent:
index eb7d291..e9a2b5c 100644 (file)
@@ -40,6 +40,7 @@
 ****************************************************************************/
 
 #include "qwindowsmousehandler.h"
+#include "qwindowskeymapper.h"
 #include "qwindowscontext.h"
 #include "qwindowswindow.h"
 #include "qwindowsintegration.h"
@@ -130,14 +131,37 @@ QWindowsMouseHandler::QWindowsMouseHandler() :
 {
 }
 
+Qt::MouseButtons QWindowsMouseHandler::queryMouseButtons()
+{
+    Qt::MouseButtons result = 0;
+    const bool mouseSwapped = GetSystemMetrics(SM_SWAPBUTTON);
+    if (GetAsyncKeyState(VK_LBUTTON) < 0)
+        result |= mouseSwapped ? Qt::RightButton: Qt::LeftButton;
+    if (GetAsyncKeyState(VK_RBUTTON) < 0)
+        result |= mouseSwapped ? Qt::LeftButton : Qt::RightButton;
+    if (GetAsyncKeyState(VK_MBUTTON) < 0)
+        result |= Qt::MidButton;
+    return result;
+}
+
 bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
                                                QtWindows::WindowsEventType et,
                                                MSG msg, LRESULT *result)
 {
-    if (et & QtWindows::NonClientEventFlag)
-        return false;
     if (et == QtWindows::MouseWheelEvent)
         return translateMouseWheelEvent(window, hwnd, msg, result);
+
+    const QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
+    if (et & QtWindows::NonClientEventFlag) {
+        const QPoint globalPosition = winEventPosition;
+        const QPoint clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition);
+        const Qt::MouseButtons buttons = QWindowsMouseHandler::queryMouseButtons();
+        QWindowSystemInterface::handleFrameStrutMouseEvent(window, clientPosition,
+                                                           globalPosition, buttons,
+                                                           QWindowsKeyMapper::queryKeyboardModifiers());
+        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
@@ -161,7 +185,6 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
             return true;
         }
     }
-    const QPoint client(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
     // Enter new window: track to generate leave event.
     if (m_windowUnderMouse != window) {
         // The tracking on m_windowUnderMouse might still be active and
@@ -186,9 +209,11 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
             qWarning("TrackMouseEvent failed.");
 #endif // !Q_OS_WINCE
     }
-    QWindowSystemInterface::handleMouseEvent(window, client,
-                                             QWindowsGeometryHint::mapToGlobal(hwnd, client),
-                                             keyStateToMouseButtons((int)msg.wParam));
+    const QPoint clientPosition = winEventPosition;
+    QWindowSystemInterface::handleMouseEvent(window, clientPosition,
+                                             QWindowsGeometryHint::mapToGlobal(hwnd, clientPosition),
+                                             keyStateToMouseButtons((int)msg.wParam),
+                                             QWindowsKeyMapper::queryKeyboardModifiers());
     return true;
 }
 
index a978840..e3d329e 100644 (file)
@@ -70,6 +70,7 @@ public:
     static inline Qt::KeyboardModifiers keyStateToModifiers(int);
     static inline int mouseButtonsToKeyState(Qt::MouseButtons);
 
+    static Qt::MouseButtons queryMouseButtons();
     QWindow *windowUnderMouse() const { return m_windowUnderMouse.data(); }
 
 private:
index 7fa43e0..b553c15 100644 (file)
@@ -1489,6 +1489,15 @@ bool QWindowsWindow::startSystemResize(const QPoint &, Qt::Corner corner)
     return true;
 }
 
+void QWindowsWindow::setFrameStrutEventsEnabled(bool enabled)
+{
+    if (enabled) {
+        setFlag(FrameStrutEventsEnabled);
+    } else {
+        clearFlag(FrameStrutEventsEnabled);
+    }
+}
+
 #ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO
 void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
 {
index 182bef7..475982a 100644 (file)
@@ -123,7 +123,8 @@ public:
         OpenGLDoubleBuffered = 0x20,
         OpenGlPixelFormatInitialized = 0x40,
         BlockedByModal = 0x80,
-        SizeGripOperation = 0x100
+        SizeGripOperation = 0x100,
+        FrameStrutEventsEnabled = 0x200
     };
 
     struct WindowData
@@ -178,6 +179,9 @@ public:
 
     virtual bool startSystemResize(const QPoint &pos, Qt::Corner corner);
 
+    void setFrameStrutEventsEnabled(bool enabled);
+    bool frameStrutEventsEnabled() const { return testFlag(FrameStrutEventsEnabled); }
+
     Qt::WindowState windowState_sys() const;
     Qt::WindowStates windowStates_sys() const;
 
index f8a5178..1b076d1 100644 (file)
@@ -137,6 +137,13 @@ bool QWidgetWindow::event(QEvent *event)
         handleMouseEvent(static_cast<QMouseEvent *>(event));
         return true;
 
+    case QEvent::NonClientAreaMouseMove:
+    case QEvent::NonClientAreaMouseButtonPress:
+    case QEvent::NonClientAreaMouseButtonRelease:
+    case QEvent::NonClientAreaMouseButtonDblClick:
+        handleNonClientAreaMouseEvent(static_cast<QMouseEvent *>(event));
+        return true;
+
     case QEvent::TouchBegin:
     case QEvent::TouchUpdate:
     case QEvent::TouchEnd:
@@ -208,6 +215,11 @@ void QWidgetWindow::handleEnterLeaveEvent(QEvent *event)
     }
 }
 
+void QWidgetWindow::handleNonClientAreaMouseEvent(QMouseEvent *e)
+{
+    QApplication::sendSpontaneousEvent(m_widget, e);
+}
+
 void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
 {
     if (qApp->d_func()->inPopupMode()) {
index 8afa3f3..5750a05 100644 (file)
@@ -74,6 +74,7 @@ protected:
     void handleEnterLeaveEvent(QEvent *);
     void handleKeyEvent(QKeyEvent *);
     void handleMouseEvent(QMouseEvent *);
+    void handleNonClientAreaMouseEvent(QMouseEvent *);
     void handleTouchEvent(QTouchEvent *);
     void handleMoveEvent(QMoveEvent *);
     void handleResizeEvent(QResizeEvent *);
index be216ec..551549f 100644 (file)
 #include <qdrawutil.h>
 #include <qevent.h>
 #include <qfontmetrics.h>
+#include <qwindow.h>
 #include <qmainwindow.h>
 #include <qrubberband.h>
 #include <qstylepainter.h>
 #include <qtoolbutton.h>
 #include <qdebug.h>
 
+#include <qpa/qplatformwindow.h>
 #include <private/qwidgetresizehandler_p.h>
 
 #include "qdockwidget_p.h"
@@ -1052,6 +1054,11 @@ void QDockWidgetPrivate::setWindowState(bool floating, bool unplug, const QRect
         }
     }
 
+    if (unplug && floating && nativeDeco)
+        if (const QWindow *window = q->windowHandle())
+            if (QPlatformWindow *platformWindow = window->handle())
+                platformWindow->setFrameStrutEventsEnabled(true);
+
     resizer->setActive(QWidgetResizeHandler::Resize, !unplug && floating && !nativeDeco);
 }