Add ContextMenu event to QWindowSystemInterface
authorMiikka Heikkinen <miikka.heikkinen@digia.com>
Mon, 22 Oct 2012 11:43:38 +0000 (14:43 +0300)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Thu, 25 Oct 2012 08:08:04 +0000 (10:08 +0200)
Context menu key wasn't working, as QPA had no handling for it.
Added ContextMenu event to QWindowSystemInterface and proper handling
to QGuiApplication and QWidgetWindow.

Also provide Windows implementation.

Task-number: QTBUG-27648
Change-Id: I7ce71ec4b5cdcc7be758e67f9faf6d863f7b19be
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
Reviewed-by: Samuel Rødal <samuel.rodal@digia.com>
src/gui/kernel/qguiapplication.cpp
src/gui/kernel/qguiapplication_p.h
src/gui/kernel/qwindowsysteminterface.cpp
src/gui/kernel/qwindowsysteminterface.h
src/gui/kernel/qwindowsysteminterface_p.h
src/plugins/platforms/windows/qtwindowsglobal.h
src/plugins/platforms/windows/qwindowscontext.cpp
src/plugins/platforms/windows/qwindowscontext.h
src/widgets/kernel/qwidgetwindow.cpp
src/widgets/kernel/qwidgetwindow_qpa_p.h

index a67917c..64d2f80 100644 (file)
@@ -1211,6 +1211,12 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv
         QGuiApplicationPrivate::processFileOpenEvent(
                     static_cast<QWindowSystemInterfacePrivate::FileOpenEvent *>(e));
         break;
+#ifndef QT_NO_CONTEXTMENU
+        case QWindowSystemInterfacePrivate::ContextMenu:
+        QGuiApplicationPrivate::processContextMenuEvent(
+                    static_cast<QWindowSystemInterfacePrivate::ContextMenuEvent *>(e));
+        break;
+#endif
     default:
         qWarning() << "Unknown user input event type:" << e->type;
         break;
@@ -1639,6 +1645,19 @@ void QGuiApplicationPrivate::processPlatformPanelEvent(QWindowSystemInterfacePri
     QGuiApplication::sendSpontaneousEvent(e->window.data(), &ev);
 }
 
+#ifndef QT_NO_CONTEXTMENU
+void QGuiApplicationPrivate::processContextMenuEvent(QWindowSystemInterfacePrivate::ContextMenuEvent *e)
+{
+    // Widgets do not care about mouse triggered context menu events. Also, do not forward event
+    // to a window blocked by a modal window.
+    if (!e->window || e->mouseTriggered || e->window->d_func()->blockedByModalWindow)
+        return;
+
+    QContextMenuEvent ev(QContextMenuEvent::Keyboard, e->pos, e->globalPos, e->modifiers);
+    QGuiApplication::sendSpontaneousEvent(e->window.data(), &ev);
+}
+#endif
+
 Q_GUI_EXPORT uint qHash(const QGuiApplicationPrivate::ActiveTouchPointsKey &k)
 {
     return qHash(k.device) + k.touchPointId;
index 0c81d78..44a9275 100644 (file)
@@ -138,6 +138,9 @@ public:
     static void processTabletLeaveProximityEvent(QWindowSystemInterfacePrivate::TabletLeaveProximityEvent *e);
 
     static void processPlatformPanelEvent(QWindowSystemInterfacePrivate::PlatformPanelEvent *e);
+#ifndef QT_NO_CONTEXTMENU
+    static void processContextMenuEvent(QWindowSystemInterfacePrivate::ContextMenuEvent *e);
+#endif
 
 #ifndef QT_NO_DRAGANDDROP
     static QPlatformDragQtResponse processDrag(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions);
index 82e0e44..6fb10b6 100644 (file)
@@ -630,6 +630,18 @@ void QWindowSystemInterface::handlePlatformPanelEvent(QWindow *w)
     QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
 }
 
+#ifndef QT_NO_CONTEXTMENU
+void QWindowSystemInterface::handleContextMenuEvent(QWindow *w, bool mouseTriggered,
+                                                    const QPoint &pos, const QPoint &globalPos,
+                                                    Qt::KeyboardModifiers modifiers)
+{
+    QWindowSystemInterfacePrivate::ContextMenuEvent *e =
+            new QWindowSystemInterfacePrivate::ContextMenuEvent(w, mouseTriggered, pos,
+                                                                globalPos, modifiers);
+    QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
+}
+#endif
+
 Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier) {
     QWindowSystemInterface::handleMouseEvent(w, local, global,  b,  mods);
 }
index 74b5a13..b4b2e84 100644 (file)
@@ -175,6 +175,11 @@ public:
     static void handleTabletLeaveProximityEvent(int device, int pointerType, qint64 uid);
 
     static void handlePlatformPanelEvent(QWindow *w);
+#ifndef QT_NO_CONTEXTMENU
+    static void handleContextMenuEvent(QWindow *w, bool mouseTriggered,
+                                       const QPoint &pos, const QPoint &globalPos,
+                                       Qt::KeyboardModifiers modifiers);
+#endif
 
     // For event dispatcher implementations
     static bool sendWindowSystemEvents(QEventLoop::ProcessEventsFlags flags);
index 4e907f3..1b5351d 100644 (file)
@@ -77,7 +77,8 @@ public:
         Tablet,
         TabletEnterProximity,
         TabletLeaveProximity,
-        PlatformPanel
+        PlatformPanel,
+        ContextMenu
     };
 
     class WindowSystemEvent {
@@ -333,6 +334,21 @@ public:
         QPointer<QWindow> window;
     };
 
+#ifndef QT_NO_CONTEXTMENU
+    class ContextMenuEvent : public WindowSystemEvent {
+    public:
+        explicit ContextMenuEvent(QWindow *w, bool mouseTriggered, const QPoint &pos,
+                                  const QPoint &globalPos, Qt::KeyboardModifiers modifiers)
+            : WindowSystemEvent(ContextMenu), window(w), mouseTriggered(mouseTriggered), pos(pos),
+              globalPos(globalPos), modifiers(modifiers) { }
+        QPointer<QWindow> window;
+        bool mouseTriggered;
+        QPoint pos;       // Only valid if triggered by mouse
+        QPoint globalPos; // Only valid if triggered by mouse
+        Qt::KeyboardModifiers modifiers;
+    };
+#endif
+
     class WindowSystemEventList {
         QList<WindowSystemEvent *> impl;
         mutable QMutex mutex;
index 73f963b..7ff8edb 100644 (file)
@@ -105,6 +105,7 @@ enum WindowsEventType // Simplify event types
     ThemeChanged = ThemingEventFlag + 1,
     DisplayChangedEvent = 437,
     SettingChangedEvent = DisplayChangedEvent + 1,
+    ContextMenu = 123,
     UnknownEvent = 542
 };
 
@@ -194,6 +195,10 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
         return QtWindows::DisplayChangedEvent;
     case WM_THEMECHANGED:
         return QtWindows::ThemeChanged;
+#ifndef QT_NO_CONTEXTMENU
+    case WM_CONTEXTMENU:
+        return QtWindows::ContextMenu;
+#endif
     default:
         break;
     }
index 3d4871d..42db58a 100644 (file)
@@ -869,6 +869,11 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
                 QWindowsWindow::baseWindowOf(modalWindow)->alertWindow();
         break;
 #endif
+#ifndef QT_NO_CONTEXTMENU
+    case QtWindows::ContextMenu:
+        handleContextMenuEvent(platformWindow->window(), msg);
+        return true;
+#endif
     default:
         break;
     }
@@ -900,6 +905,24 @@ void QWindowsContext::handleFocusEvent(QtWindows::WindowsEventType et,
     }
 }
 
+#ifndef QT_NO_CONTEXTMENU
+void QWindowsContext::handleContextMenuEvent(QWindow *window, const MSG &msg)
+{
+    bool mouseTriggered = false;
+    QPoint globalPos;
+    QPoint pos;
+    if (msg.lParam != (int)0xffffffff) {
+        mouseTriggered = true;
+        globalPos.setX(msg.pt.x);
+        globalPos.setY(msg.pt.y);
+        pos = QWindowsGeometryHint::mapFromGlobal(msg.hwnd, globalPos);
+    }
+
+    QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, pos, globalPos,
+                                                   QWindowsKeyMapper::queryKeyboardModifiers());
+}
+#endif
+
 /*!
     \brief Windows functions for actual windows.
 
index dcc636b..ef48a52 100644 (file)
@@ -187,6 +187,9 @@ public:
 
 private:
     void handleFocusEvent(QtWindows::WindowsEventType et, QWindowsWindow *w);
+#ifndef QT_NO_CONTEXTMENU
+    void handleContextMenuEvent(QWindow *window, const MSG &msg);
+#endif
     void unregisterWindowClasses();
 
     QScopedPointer<QWindowsContextPrivate> d;
index 5f25e12..900818d 100644 (file)
@@ -200,7 +200,11 @@ bool QWidgetWindow::event(QEvent *event)
         handleTabletEvent(static_cast<QTabletEvent *>(event));
         return true;
 #endif
-
+#ifndef QT_NO_CONTEXTMENU
+    case QEvent::ContextMenu:
+        handleContextMenuEvent(static_cast<QContextMenuEvent *>(event));
+        return true;
+#endif
     default:
         break;
     }
@@ -618,6 +622,35 @@ void QWidgetWindow::handleTabletEvent(QTabletEvent *event)
 }
 #endif // QT_NO_TABLETEVENT
 
+#ifndef QT_NO_CONTEXTMENU
+void QWidgetWindow::handleContextMenuEvent(QContextMenuEvent *e)
+{
+    // We are only interested in keyboard originating context menu events here,
+    // mouse originated context menu events for widgets are generated in mouse handling methods.
+    if (e->reason() != QContextMenuEvent::Keyboard)
+        return;
+
+    QWidget *fw = QWidget::keyboardGrabber();
+    if (!fw) {
+        if (QApplication::activePopupWidget()) {
+            fw = (QApplication::activePopupWidget()->focusWidget()
+                  ? QApplication::activePopupWidget()->focusWidget()
+                  : QApplication::activePopupWidget());
+        } else if (QApplication::focusWidget()) {
+            fw = QApplication::focusWidget();
+        } else {
+            fw = m_widget;
+        }
+    }
+    if (fw && fw->isEnabled()) {
+        QPoint pos = fw->inputMethodQuery(Qt::ImMicroFocus).toRect().center();
+        QContextMenuEvent widgetEvent(QContextMenuEvent::Keyboard, pos, fw->mapToGlobal(pos),
+                                      e->modifiers());
+        QGuiApplication::sendSpontaneousEvent(fw, &widgetEvent);
+    }
+}
+#endif // QT_NO_CONTEXTMENU
+
 void QWidgetWindow::updateObjectName()
 {
     QString name = m_widget->objectName();
index 80aa022..e832249 100644 (file)
@@ -92,6 +92,9 @@ protected:
 #ifndef QT_NO_TABLETEVENT
     void handleTabletEvent(QTabletEvent *);
 #endif
+#ifndef QT_NO_CONTEXTMENU
+    void handleContextMenuEvent(QContextMenuEvent *);
+#endif
 
 private slots:
     void updateObjectName();