[EXPLORER] Handle WM_CONTEXTMENU message in CNotifyToolbar and BN_CLICKED notificatio...
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Mon, 2 Apr 2018 19:06:09 +0000 (21:06 +0200)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Mon, 2 Apr 2018 19:13:35 +0000 (21:13 +0200)
With these, we generate the WM_CONTEXTMENU and NIN_(KEY)SELECT
shell icon notifications that applications expect when they handle
shell notification icons with uVersion >= 3.

This fixes in particular the previously unresponsive icon of KVIrc 4.x,
and more generally *all* the notifiation icons of Qt applications.
CORE-10605 #resolve

base/shell/explorer/syspager.cpp

index 5340ba4..1755ebe 100644 (file)
@@ -165,12 +165,14 @@ public:
     bool SendNotifyCallback(InternalIconData* notifyItem, UINT uMsg);
 
 private:
+    LRESULT OnCtxMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
     VOID SendMouseEvent(IN WORD wIndex, IN UINT uMsg, IN WPARAM wParam);
     LRESULT OnMouseEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
     LRESULT OnTooltipShow(INT uCode, LPNMHDR hdr, BOOL& bHandled);
 
 public:
     BEGIN_MSG_MAP(CNotifyToolbar)
+        MESSAGE_HANDLER(WM_CONTEXTMENU, OnCtxMenu)
         MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseEvent)
         NOTIFY_CODE_HANDLER(TTN_SHOW, OnTooltipShow)
     END_MSG_MAP()
@@ -201,6 +203,7 @@ public:
     LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
     LRESULT OnGetInfoTip(INT uCode, LPNMHDR hdr, BOOL& bHandled);
     LRESULT OnCustomDraw(INT uCode, LPNMHDR hdr, BOOL& bHandled);
+    LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
     LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
     LRESULT OnCtxMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
     LRESULT OnBalloonPop(UINT uCode, LPNMHDR hdr, BOOL& bHandled);
@@ -240,6 +243,7 @@ public:
         MESSAGE_HANDLER(WM_CREATE, OnCreate)
         MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
         MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
+        MESSAGE_HANDLER(WM_COMMAND, OnCommand)
         MESSAGE_HANDLER(WM_SIZE, OnSize)
         MESSAGE_HANDLER(WM_CONTEXTMENU, OnCtxMenu)
         MESSAGE_HANDLER(WM_TIMER, OnTimer)
@@ -1015,6 +1019,54 @@ VOID CNotifyToolbar::ResizeImagelist()
     SetButtonSize(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
 }
 
+LRESULT CNotifyToolbar::OnCtxMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+{
+    bHandled = FALSE;
+
+    /*
+     * WM_CONTEXTMENU message can be generated either by the mouse,
+     * in which case lParam encodes the mouse coordinates where the
+     * user right-clicked the mouse, or can be generated by (Shift-)F10
+     * keyboard press, in which case lParam equals -1.
+     */
+    INT iBtn = GetHotItem();
+    if (iBtn < 0)
+        return 0;
+
+    InternalIconData* notifyItem = GetItemData(iBtn);
+
+    if (!::IsWindow(notifyItem->hWnd))
+        return 0;
+
+    if (notifyItem->uVersionCopy >= NOTIFYICON_VERSION)
+    {
+        /* Transmit the WM_CONTEXTMENU message if the notification icon supports it */
+        ::SendNotifyMessage(notifyItem->hWnd,
+                            notifyItem->uCallbackMessage,
+                            notifyItem->uID,
+                            WM_CONTEXTMENU);
+    }
+    else if (lParam == -1)
+    {
+        /*
+         * Otherwise, and only if the WM_CONTEXTMENU message was generated
+         * from the keyboard, simulate right-click mouse messages. This is
+         * not needed if the message came from the mouse because in this
+         * case the right-click mouse messages were already sent together.
+         */
+        ::SendNotifyMessage(notifyItem->hWnd,
+                            notifyItem->uCallbackMessage,
+                            notifyItem->uID,
+                            WM_RBUTTONDOWN);
+        ::SendNotifyMessage(notifyItem->hWnd,
+                            notifyItem->uCallbackMessage,
+                            notifyItem->uID,
+                            WM_RBUTTONUP);
+    }
+
+    return 0;
+}
+
 bool CNotifyToolbar::SendNotifyCallback(InternalIconData* notifyItem, UINT uMsg)
 {
     if (!::IsWindow(notifyItem->hWnd))
@@ -1045,10 +1097,10 @@ bool CNotifyToolbar::SendNotifyCallback(InternalIconData* notifyItem, UINT uMsg)
     }
     else
     {
-        SendMessage(notifyItem->hWnd,
-                    notifyItem->uCallbackMessage,
-                    notifyItem->uID,
-                    uMsg);
+        ::SendMessage(notifyItem->hWnd,
+                      notifyItem->uCallbackMessage,
+                      notifyItem->uID,
+                      uMsg);
     }
     return false;
 }
@@ -1087,7 +1139,6 @@ VOID CNotifyToolbar::SendMouseEvent(IN WORD wIndex, IN UINT uMsg, IN WPARAM wPar
 LRESULT CNotifyToolbar::OnMouseEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
 {
     POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
-
     INT iBtn = HitTest(&pt);
 
     if (iBtn >= 0)
@@ -1376,6 +1427,55 @@ LRESULT CSysPagerWnd::OnCustomDraw(INT uCode, LPNMHDR hdr, BOOL& bHandled)
     return TRUE;
 }
 
+LRESULT CSysPagerWnd::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+{
+    bHandled = FALSE;
+
+    /* Handles the BN_CLICKED notifications sent by the CNotifyToolbar member */
+    if (HIWORD(wParam) != BN_CLICKED)
+        return 0;
+
+    INT iBtn = LOWORD(wParam);
+    if (iBtn < 0)
+        return 0;
+
+    InternalIconData* notifyItem = Toolbar.GetItemData(iBtn);
+
+    if (!::IsWindow(notifyItem->hWnd))
+        return 0;
+
+    // TODO: Improve keyboard handling by looking whether one presses
+    // on ENTER, etc..., which roughly translates into "double-clicking".
+
+    if (notifyItem->uVersionCopy >= NOTIFYICON_VERSION)
+    {
+        /* Use new-style notifications if the notification icon supports them */
+        ::SendNotifyMessage(notifyItem->hWnd,
+                            notifyItem->uCallbackMessage,
+                            notifyItem->uID,
+                            NIN_SELECT); // TODO: Distinguish with NIN_KEYSELECT
+    }
+    else if (lParam == -1)
+    {
+        /*
+         * Otherwise, and only if the icon was selected via the keyboard,
+         * simulate right-click mouse messages. This is not needed if the
+         * selection was done by mouse because in this case the mouse
+         * messages were already sent.
+         */
+        ::SendNotifyMessage(notifyItem->hWnd,
+                            notifyItem->uCallbackMessage,
+                            notifyItem->uID,
+                            WM_LBUTTONDOWN); // TODO: Distinguish with double-click WM_LBUTTONDBLCLK
+        ::SendNotifyMessage(notifyItem->hWnd,
+                            notifyItem->uCallbackMessage,
+                            notifyItem->uID,
+                            WM_LBUTTONUP);
+    }
+
+    return 0;
+}
+
 LRESULT CSysPagerWnd::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
 {
     LRESULT Ret = TRUE;