[EXPLORER] Fix some issues with the notification area code,
authorDavid Quintana <gigaherz@gmail.com>
Tue, 16 Jan 2018 21:11:14 +0000 (22:11 +0100)
committerGiannis Adamopoulos <gadamopoulos@reactos.org>
Thu, 18 Jan 2018 00:20:20 +0000 (02:20 +0200)
and implement NIS_SHAREDICON while at it.

base/shell/explorer/trayntfy.cpp

index 95c40aa..c6bea29 100644 (file)
@@ -77,16 +77,41 @@ public:
         return -1;
     }
 
+    int FindExistingSharedIcon(HICON handle)
+    {
+        int count = GetButtonCount();
+        for (int i = 0; i < count; i++)
+        {
+            NOTIFYICONDATA * data = GetItemData(i);
+            if (data->hIcon == handle)
+            {
+                TBBUTTON btn;
+                GetButton(i, &btn);
+                return btn.iBitmap;
+            }
+        }
+
+        return -1;
+    }
+
     BOOL AddButton(IN CONST NOTIFYICONDATA *iconData)
     {
         TBBUTTON tbBtn;
         NOTIFYICONDATA * notifyItem;
         WCHAR text[] = L"";
 
+        TRACE("Adding icon %d from hWnd %08x flags%s%s state%s%s", 
+            iconData->uID, iconData->hWnd,
+            (iconData->uFlags & NIF_ICON) ? " ICON" : "",
+            (iconData->uFlags & NIF_STATE) ? " STATE" : "",
+            (iconData->dwState & NIS_HIDDEN) ? " HIDDEN" : "",
+            (iconData->dwState & NIS_SHAREDICON) ? " SHARED" : "");
+
         int index = FindItemByIconData(iconData, &notifyItem);
         if (index >= 0)
         {
-            return UpdateButton(iconData);
+            TRACE("Icon %d from hWnd %08x ALREADY EXISTS!", iconData->uID, iconData->hWnd);
+            return FALSE;
         }
 
         notifyItem = new NOTIFYICONDATA();
@@ -101,6 +126,11 @@ public:
         tbBtn.iString = (INT_PTR) text;
         tbBtn.idCommand = GetButtonCount();
 
+        if (iconData->uFlags & NIF_STATE)
+        {
+            notifyItem->dwState = iconData->dwState & iconData->dwStateMask;
+        }
+
         if (iconData->uFlags & NIF_MESSAGE)
         {
             notifyItem->uCallbackMessage = iconData->uCallbackMessage;
@@ -108,8 +138,22 @@ public:
 
         if (iconData->uFlags & NIF_ICON)
         {
-            notifyItem->hIcon = (HICON)CopyImage(iconData->hIcon, IMAGE_ICON, 0, 0, 0);
-            tbBtn.iBitmap = ImageList_AddIcon(m_ImageList, iconData->hIcon);
+            notifyItem->hIcon = iconData->hIcon;
+            BOOL hasSharedIcon = notifyItem->dwState & NIS_SHAREDICON;
+            if (hasSharedIcon)
+            {
+                INT iIcon = FindExistingSharedIcon(notifyItem->hIcon);
+                if (iIcon < 0)
+                {
+                    notifyItem->hIcon = NULL;
+                    TRACE("Shared icon requested, but HICON not found!!!");
+                }
+                tbBtn.iBitmap = iIcon;
+            }
+            else
+            {
+                tbBtn.iBitmap = ImageList_AddIcon(m_ImageList, notifyItem->hIcon);
+            }
         }
 
         if (iconData->uFlags & NIF_TIP)
@@ -118,15 +162,10 @@ public:
         }
 
         m_VisibleButtonCount++;
-        if (iconData->uFlags & NIF_STATE)
+        if (notifyItem->dwState & NIS_HIDDEN)
         {
-            notifyItem->dwState &= ~iconData->dwStateMask;
-            notifyItem->dwState |= (iconData->dwState & iconData->dwStateMask);
-            if (notifyItem->dwState & NIS_HIDDEN)
-            {
-                tbBtn.fsState |= TBSTATE_HIDDEN;
-                m_VisibleButtonCount--;
-            }
+            tbBtn.fsState |= TBSTATE_HIDDEN;
+            m_VisibleButtonCount--;
         }
 
         /* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */
@@ -142,34 +181,28 @@ public:
         NOTIFYICONDATA * notifyItem;
         TBBUTTONINFO tbbi = { 0 };
 
+        TRACE("Updating icon %d from hWnd %08x flags%s%s state%s%s",
+            iconData->uID, iconData->hWnd,
+            (iconData->uFlags & NIF_ICON) ? " ICON" : "",
+            (iconData->uFlags & NIF_STATE) ? " STATE" : "",
+            (iconData->dwState & NIS_HIDDEN) ? " HIDDEN" : "",
+            (iconData->dwState & NIS_SHAREDICON) ? " SHARED" : "");
+
         int index = FindItemByIconData(iconData, &notifyItem);
         if (index < 0)
         {
+            WARN("Icon %d from hWnd %08x DOES NOT EXIST!", iconData->uID, iconData->hWnd);
             return AddButton(iconData);
         }
 
+        TBBUTTON btn;
+        GetButton(index, &btn);
+        int oldIconIndex = btn.iBitmap;
+
         tbbi.cbSize = sizeof(tbbi);
         tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND;
         tbbi.idCommand = index;
 
-        if (iconData->uFlags & NIF_MESSAGE)
-        {
-            notifyItem->uCallbackMessage = iconData->uCallbackMessage;
-        }
-
-        if (iconData->uFlags & NIF_ICON)
-        {
-            DestroyIcon(notifyItem->hIcon);
-            notifyItem->hIcon = (HICON)CopyImage(iconData->hIcon, IMAGE_ICON, 0, 0, 0);
-            tbbi.dwMask |= TBIF_IMAGE;
-            tbbi.iImage = ImageList_ReplaceIcon(m_ImageList, index, iconData->hIcon);
-        }
-
-        if (iconData->uFlags & NIF_TIP)
-        {
-            StringCchCopy(notifyItem->szTip, _countof(notifyItem->szTip), iconData->szTip);
-        }
-
         if (iconData->uFlags & NIF_STATE)
         {
             if (iconData->dwStateMask & NIS_HIDDEN &&
@@ -192,6 +225,41 @@ public:
             notifyItem->dwState |= (iconData->dwState & iconData->dwStateMask);
         }
 
+        if (iconData->uFlags & NIF_MESSAGE)
+        {
+            notifyItem->uCallbackMessage = iconData->uCallbackMessage;
+        }
+
+        if (iconData->uFlags & NIF_ICON)
+        {
+            BOOL hasSharedIcon = notifyItem->dwState & NIS_SHAREDICON;
+            if (hasSharedIcon)
+            {
+                INT iIcon = FindExistingSharedIcon(iconData->hIcon);
+                if (iIcon >= 0)
+                {
+                    notifyItem->hIcon = iconData->hIcon;
+                    tbbi.dwMask |= TBIF_IMAGE;
+                    tbbi.iImage = iIcon;
+                }
+                else
+                {
+                    TRACE("Shared icon requested, but HICON not found!!! IGNORING!");
+                }
+            }
+            else
+            {
+                notifyItem->hIcon = iconData->hIcon;
+                tbbi.dwMask |= TBIF_IMAGE;
+                tbbi.iImage = ImageList_ReplaceIcon(m_ImageList, oldIconIndex, notifyItem->hIcon);
+            }
+        }
+
+        if (iconData->uFlags & NIF_TIP)
+        {
+            StringCchCopy(notifyItem->szTip, _countof(notifyItem->szTip), iconData->szTip);
+        }
+
         /* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */
 
         SetButtonInfo(index, &tbbi);
@@ -203,34 +271,48 @@ public:
     {
         NOTIFYICONDATA * notifyItem;
 
+        TRACE("Removing icon %d from hWnd %08x", iconData->uID, iconData->hWnd);
+
         int index = FindItemByIconData(iconData, &notifyItem);
         if (index < 0)
+        {
+            TRACE("Icon %d from hWnd %08x ALREADY MISSING!", iconData->uID, iconData->hWnd);
+
             return FALSE;
+        }
 
         if (!(notifyItem->dwState & NIS_HIDDEN))
         {
             m_VisibleButtonCount--;
         }
 
-        DestroyIcon(notifyItem->hIcon);
-
-        delete notifyItem;
-
-        ImageList_Remove(m_ImageList, index);
+        if (!(notifyItem->dwState & NIS_SHAREDICON))
+        {
+            TBBUTTON btn;
+            GetButton(index, &btn);
+            int oldIconIndex = btn.iBitmap;
+            ImageList_Remove(m_ImageList, oldIconIndex);
 
-        int count = GetButtonCount();
+            // Update other icons!
+            int count = GetButtonCount();
+            for (int i = 0; i < count; i++)
+            {
+                TBBUTTON btn;
+                GetButton(i, &btn);
 
-        /* shift all buttons one index to the left -- starting one index right
-           from item to delete -- to preserve their correct icon and tip */
-        for (int i = index; i < count - 1; i++)
-        {
-            notifyItem = GetItemData(i + 1);
-            SetItemData(i, notifyItem);
-            UpdateButton(notifyItem);
+                if (btn.iBitmap > oldIconIndex)
+                {
+                    TBBUTTONINFO tbbi2 = { 0 };
+                    tbbi2.cbSize = sizeof(tbbi2);
+                    tbbi2.dwMask = TBIF_BYINDEX | TBIF_IMAGE;
+                    tbbi2.iImage = btn.iBitmap-1;
+                    SetButtonInfo(i, &tbbi2);
+                }
+            }
         }
 
-        /* Delete the right-most, now obsolete button */
-        DeleteButton(count - 1);
+        delete notifyItem;
+        DeleteButton(index);
 
         return TRUE;
     }
@@ -269,7 +351,10 @@ public:
         for (int i = 0; i < count; i++)
         {
             NOTIFYICONDATA * data = GetItemData(i);
-            INT iIcon = ImageList_AddIcon(iml, data->hIcon);
+            BOOL hasSharedIcon = data->dwState & NIS_SHAREDICON;
+            INT iIcon = hasSharedIcon ? FindExistingSharedIcon(data->hIcon) : -1;
+            if (iIcon < 0)
+                iIcon = ImageList_AddIcon(iml, data->hIcon);
             TBBUTTONINFO tbbi = { sizeof(tbbi), TBIF_BYINDEX | TBIF_IMAGE, 0, iIcon};
             SetButtonInfo(i, &tbbi);
         }
@@ -304,7 +389,7 @@ private:
         {
             // We detect and destroy icons with invalid handles only on mouse move over systray, same as MS does.
             // Alternatively we could search for them periodically (would waste more resources).
-            TRACE("destroying icon with invalid handle\n");
+            TRACE("Destroying icon %d with invalid handle hWnd=%08x\n", notifyItem->uID, notifyItem->hWnd);
 
             HWND parentHWND = GetParent();
             parentHWND = ::GetParent(parentHWND);