[EXPLORER] -Implement the trick that makes the start button to get clicked when the...
[reactos.git] / reactos / base / shell / explorer / trayntfy.cpp
index ec502cf..6ece02d 100644 (file)
 
 #include "precomp.h"
 
-#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
-#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
-
 /*
  * SysPagerWnd
  */
-static const WCHAR szSysPagerWndClass [] = TEXT("SysPager");
+static const WCHAR szSysPagerWndClass [] = L"SysPager";
 
 // Data comes from shell32/systray.cpp -> TrayNotifyCDS_Dummy
 typedef struct _SYS_PAGER_COPY_DATA
@@ -86,7 +83,7 @@ public:
     {
         TBBUTTON tbBtn;
         NOTIFYICONDATA * notifyItem;
-        WCHAR text [] = TEXT("");
+        WCHAR text[] = L"";
 
         int index = FindItemByIconData(iconData, &notifyItem);
         if (index >= 0)
@@ -164,7 +161,7 @@ public:
         if (iconData->uFlags & NIF_ICON)
         {
             tbbi.dwMask |= TBIF_IMAGE;
-            tbbi.iImage = ImageList_AddIcon(m_ImageList, iconData->hIcon);
+            tbbi.iImage = ImageList_ReplaceIcon(m_ImageList, index, iconData->hIcon);
         }
 
         if (iconData->uFlags & NIF_TIP)
@@ -209,8 +206,6 @@ public:
         if (index < 0)
             return FALSE;
 
-        DeleteButton(index);
-
         if (!(notifyItem->dwState & NIS_HIDDEN))
         {
             m_VisibleButtonCount--;
@@ -218,6 +213,22 @@ public:
 
         delete notifyItem;
 
+        ImageList_Remove(m_ImageList, index);
+
+        int count = GetButtonCount();
+
+        /* 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);
+        }
+
+        /* Delete the right-most, now obsolete button */
+        DeleteButton(count - 1);
+
         return TRUE;
     }
 
@@ -256,7 +267,27 @@ private:
         NOTIFYICONDATA * notifyItem = GetItemData(wIndex);
 
         if (!::IsWindow(notifyItem->hWnd))
+        {
+            // 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");
+
+            HWND parentHWND = GetParent();
+            parentHWND = ::GetParent(parentHWND);
+
+            RECT windowRect;
+            ::GetClientRect(parentHWND, &windowRect);
+
+            RemoveButton(notifyItem);
+
+            SendMessage(parentHWND,
+                WM_SIZE,
+                0,
+                MAKELONG(windowRect.right - windowRect.left,
+                         windowRect.bottom - windowRect.top));
+
             return;
+        }
 
         if (uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST)
         {
@@ -271,10 +302,10 @@ private:
         if (pid == GetCurrentProcessId() ||
             (uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST))
         {
-            PostMessage(notifyItem->hWnd,
-                        notifyItem->uCallbackMessage,
-                        notifyItem->uID,
-                        uMsg);
+            ::PostMessage(notifyItem->hWnd,
+                          notifyItem->uCallbackMessage,
+                          notifyItem->uID,
+                          uMsg);
         }
         else
         {
@@ -288,7 +319,7 @@ private:
     LRESULT 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)
@@ -303,7 +334,7 @@ private:
     LRESULT OnTooltipShow(INT uCode, LPNMHDR hdr, BOOL& bHandled)
     {
         RECT rcTip, rcItem;
-        GetWindowRect(hdr->hwndFrom, &rcTip);
+        ::GetWindowRect(hdr->hwndFrom, &rcTip);
 
         SIZE szTip = { rcTip.right - rcTip.left, rcTip.bottom - rcTip.top };
 
@@ -319,13 +350,13 @@ private:
             if (hMon)
                 GetMonitorInfo(hMon, &monInfo);
             else
-                GetWindowRect(GetDesktopWindow(), &monInfo.rcMonitor);
+                ::GetWindowRect(GetDesktopWindow(), &monInfo.rcMonitor);
 
             GetItemRect(iBtn, &rcItem);
 
             POINT ptItem = { rcItem.left, rcItem.top };
             SIZE szItem = { rcItem.right - rcItem.left, rcItem.bottom - rcItem.top };
-            ClientToScreen(m_hWnd, &ptItem);
+            ClientToScreen(&ptItem);
 
             ptItem.x += szItem.cx / 2;
             ptItem.y -= szTip.cy;
@@ -414,6 +445,12 @@ public:
     LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
         Toolbar.Initialize(m_hWnd);
+
+        // Explicitly request running applications to re-register their systray icons
+        ::SendNotifyMessageW(HWND_BROADCAST,
+                             RegisterWindowMessageW(L"TaskbarCreated"),
+                             0, 0);
+
         return TRUE;
     }
 
@@ -585,7 +622,7 @@ public:
  * TrayClockWnd
  */
 
-static const WCHAR szTrayClockWndClass [] = TEXT("TrayClockWClass");
+static const WCHAR szTrayClockWndClass[] = L"TrayClockWClass";
 
 #define ID_TRAYCLOCK_TIMER  0
 #define ID_TRAYCLOCK_TIMER_INIT 1
@@ -594,14 +631,14 @@ static const struct
 {
     BOOL IsTime;
     DWORD dwFormatFlags;
-    LPCTSTR lpFormat;
+    LPCWSTR lpFormat;
 } ClockWndFormats [] = {
-        { TRUE, 0, NULL },
-        { FALSE, 0, TEXT("dddd") },
-        { FALSE, DATE_SHORTDATE, NULL }
+    { TRUE, 0, NULL },
+    { FALSE, 0, L"dddd" },
+    { FALSE, DATE_SHORTDATE, NULL }
 };
 
-#define CLOCKWND_FORMAT_COUNT (sizeof(ClockWndFormats) / sizeof(ClockWndFormats[0]))
+#define CLOCKWND_FORMAT_COUNT (_ARRAYSIZE(ClockWndFormats))
 
 #define TRAY_CLOCK_WND_SPACING_X    0
 #define TRAY_CLOCK_WND_SPACING_Y    0
@@ -646,7 +683,7 @@ public:
         ZeroMemory(&LocalTime, sizeof(LocalTime));
         ZeroMemory(&CurrentSize, sizeof(CurrentSize));
         ZeroMemory(LineSizes, sizeof(LineSizes));
-        ZeroMemory(szLines, sizeof(LineSizes));
+        ZeroMemory(szLines, sizeof(szLines));
     }
     virtual ~CTrayClockWnd() { }
 
@@ -674,20 +711,19 @@ public:
                 0,
                 TMT_TEXTCOLOR,
                 &textColor);
+
+            if (this->hFont != NULL)
+                DeleteObject(this->hFont);
+
+            SetFont(hFont, FALSE);
         }
         else
         {
-            NONCLIENTMETRICS ncm = { 0 };
-            ncm.cbSize = sizeof(ncm);
-            SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, FALSE);
-
-            hFont = CreateFontIndirectW(&ncm.lfMessageFont);
-
+            /* We don't need to set a font here, our parent will use 
+              * WM_SETFONT to set the right one when themes are not enabled. */
             textColor = RGB(0, 0, 0);
         }
 
-        SetFont(hFont, FALSE);
-
         CloseThemeData(clockTheme);
 
         return TRUE;
@@ -702,20 +738,20 @@ public:
     {
         HDC hDC;
         HFONT hPrevFont;
-        INT c, i;
+        UINT c, i;
         BOOL bRet = TRUE;
 
-        hDC = GetDC(m_hWnd);
+        hDC = GetDC();
         if (hDC != NULL)
         {
             if (hFont)
                 hPrevFont = (HFONT) SelectObject(hDC, hFont);
 
-            for (i = 0; i != CLOCKWND_FORMAT_COUNT && bRet; i++)
+            for (i = 0; i < CLOCKWND_FORMAT_COUNT && bRet; i++)
             {
-                if (szLines[i][0] != TEXT('\0') &&
-                    !GetTextExtentPoint(hDC, szLines[i], _tcslen(szLines[i]),
-                    &LineSizes[i]))
+                if (szLines[i][0] != L'\0' &&
+                    !GetTextExtentPointW(hDC, szLines[i], wcslen(szLines[i]),
+                                         &LineSizes[i]))
                 {
                     bRet = FALSE;
                     break;
@@ -725,14 +761,14 @@ public:
             if (hFont)
                 SelectObject(hDC, hPrevFont);
 
-            ReleaseDC(m_hWnd, hDC);
+            ReleaseDC(hDC);
 
             if (bRet)
             {
                 LineSpacing = 0;
 
                 /* calculate the line spacing */
-                for (i = 0, c = 0; i != CLOCKWND_FORMAT_COUNT; i++)
+                for (i = 0, c = 0; i < CLOCKWND_FORMAT_COUNT; i++)
                 {
                     if (LineSizes[i].cx > 0)
                     {
@@ -743,7 +779,7 @@ public:
 
                 if (c > 0)
                 {
-                    /* We want a spaceing of 1/2 line */
+                    /* We want a spacing of 1/2 line */
                     LineSpacing = (LineSpacing / c) / 2;
                 }
 
@@ -757,7 +793,7 @@ public:
     WORD GetMinimumSize(IN BOOL Horizontal, IN OUT PSIZE pSize)
     {
         WORD iLinesVisible = 0;
-        INT i;
+        UINT i;
         SIZE szMax = { 0, 0 };
 
         if (!LinesMeasured)
@@ -766,9 +802,7 @@ public:
         if (!LinesMeasured)
             return 0;
 
-        for (i = 0;
-            i != CLOCKWND_FORMAT_COUNT;
-            i++)
+        for (i = 0; i < CLOCKWND_FORMAT_COUNT; i++)
         {
             if (LineSizes[i].cx != 0)
             {
@@ -810,28 +844,26 @@ public:
     }
 
 
-    VOID        UpdateWnd()
+    VOID UpdateWnd()
     {
         SIZE szPrevCurrent;
-        INT BufSize, iRet, i;
+        UINT BufSize, i;
+        INT iRet;
         RECT rcClient;
 
-        ZeroMemory(LineSizes,
-            sizeof(LineSizes));
+        ZeroMemory(LineSizes, sizeof(LineSizes));
 
         szPrevCurrent = CurrentSize;
 
-        for (i = 0;
-            i != CLOCKWND_FORMAT_COUNT;
-            i++)
+        for (i = 0; i < CLOCKWND_FORMAT_COUNT; i++)
         {
-            szLines[i][0] = TEXT('\0');
-            BufSize = sizeof(szLines[0]) / sizeof(szLines[0][0]);
+            szLines[i][0] = L'\0';
+            BufSize = _countof(szLines[0]);
 
             if (ClockWndFormats[i].IsTime)
             {
                 iRet = GetTimeFormat(LOCALE_USER_DEFAULT,
-                    AdvancedSettings.bShowSeconds ? ClockWndFormats[i].dwFormatFlags : TIME_NOSECONDS,
+                    TaskBarSettings.bShowSeconds ? ClockWndFormats[i].dwFormatFlags : TIME_NOSECONDS,
                     &LocalTime,
                     ClockWndFormats[i].lpFormat,
                     szLines[i],
@@ -868,7 +900,7 @@ public:
             CurrentSize = szWnd;
         }
 
-        if (IsWindowVisible(m_hWnd))
+        if (IsWindowVisible())
         {
             InvalidateRect(NULL, TRUE);
 
@@ -879,7 +911,7 @@ public:
                 NMHDR nmh;
 
                 nmh.hwndFrom = m_hWnd;
-                nmh.idFrom = GetWindowLongPtr(m_hWnd, GWLP_ID);
+                nmh.idFrom = GetWindowLongPtr(GWLP_ID);
                 nmh.code = NTNWM_REALIGN;
 
                 SendMessage(hWndNotify,
@@ -890,20 +922,20 @@ public:
         }
     }
 
-    VOID        Update()
+    VOID Update()
     {
         GetLocalTime(&LocalTime);
         UpdateWnd();
     }
 
-    UINT        CalculateDueTime()
+    UINT CalculateDueTime()
     {
         UINT uiDueTime;
 
         /* Calculate the due time */
         GetLocalTime(&LocalTime);
         uiDueTime = 1000 - (UINT) LocalTime.wMilliseconds;
-        if (AdvancedSettings.bShowSeconds)
+        if (TaskBarSettings.bShowSeconds)
             uiDueTime += (UINT) LocalTime.wSecond * 100;
         else
             uiDueTime += (59 - (UINT) LocalTime.wSecond) * 1000;
@@ -920,7 +952,7 @@ public:
         return uiDueTime;
     }
 
-    BOOL        ResetTime()
+    BOOL ResetTime()
     {
         UINT uiDueTime;
         BOOL Ret;
@@ -949,7 +981,7 @@ public:
         return Ret;
     }
 
-    VOID        CalibrateTimer()
+    VOID CalibrateTimer()
     {
         UINT uiDueTime;
         BOOL Ret;
@@ -961,7 +993,7 @@ public:
 
         uiDueTime = CalculateDueTime();
 
-        if (AdvancedSettings.bShowSeconds)
+        if (TaskBarSettings.bShowSeconds)
         {
             uiWait1 = 1000 - 200;
             uiWait2 = 1000;
@@ -1011,7 +1043,8 @@ public:
     {
         RECT rcClient;
         HFONT hPrevFont;
-        int iPrevBkMode, i, line;
+        INT iPrevBkMode;
+        UINT i, line;
 
         PAINTSTRUCT ps;
         HDC hDC = (HDC) wParam;
@@ -1039,8 +1072,8 @@ public:
             rcClient.bottom = rcClient.top + CurrentSize.cy;
 
             for (i = 0, line = 0;
-                i != CLOCKWND_FORMAT_COUNT && line < VisibleLines;
-                i++)
+                 i < CLOCKWND_FORMAT_COUNT && line < VisibleLines;
+                 i++)
             {
                 if (LineSizes[i].cx != 0)
                 {
@@ -1049,7 +1082,7 @@ public:
                         TRAY_CLOCK_WND_SPACING_X,
                         rcClient.top + TRAY_CLOCK_WND_SPACING_Y,
                         szLines[i],
-                        _tcslen(szLines[i]));
+                        wcslen(szLines[i]));
 
                     rcClient.top += LineSizes[i].cy + LineSpacing;
                     line++;
@@ -1169,8 +1202,10 @@ public:
         MESSAGE_HANDLER(WM_SIZE, OnSize)
         MESSAGE_HANDLER(WM_PAINT, OnPaint)
         MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
+        MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged)
         MESSAGE_HANDLER(WM_TIMER, OnTimer)
         MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
+        MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
         MESSAGE_HANDLER(TCWM_GETMINIMUMSIZE, OnGetMinimumSize)
         MESSAGE_HANDLER(TCWM_UPDATETIME, OnUpdateTime)
 
@@ -1191,10 +1226,7 @@ public:
         Create(hWndParent, 0, NULL, dwStyle);
 
         if (m_hWnd != NULL)
-        {
             SetWindowTheme(m_hWnd, L"TrayNotify", NULL);
-            OnThemeChanged();
-        }
 
         return m_hWnd;
 
@@ -1299,25 +1331,17 @@ public:
         m_pager = new CSysPagerWnd();
         m_pager->_Init(m_hWnd, !HideClock);
 
-        OnThemeChanged();
-
         return TRUE;
     }
 
-    BOOL GetMinimumSize(IN BOOL Horizontal, IN OUT PSIZE pSize)
+    BOOL GetMinimumSize(IN OUT PSIZE pSize)
     {
         SIZE szClock = { 0, 0 };
         SIZE szTray = { 0, 0 };
 
-        IsHorizontal = Horizontal;
-        if (IsHorizontal)
-            SetWindowTheme(m_hWnd, L"TrayNotifyHoriz", NULL);
-        else
-            SetWindowTheme(m_hWnd, L"TrayNotifyVert", NULL);
-
         if (!HideClock)
         {
-            if (Horizontal)
+            if (IsHorizontal)
             {
                 szClock.cy = pSize->cy - 2 * TRAY_NOTIFY_WND_SPACING_Y;
                 if (szClock.cy <= 0)
@@ -1330,7 +1354,7 @@ public:
                     goto NoClock;
             }
 
-            m_clock->SendMessage(TCWM_GETMINIMUMSIZE, (WPARAM) Horizontal, (LPARAM) &szClock);
+            m_clock->SendMessage(TCWM_GETMINIMUMSIZE, (WPARAM) IsHorizontal, (LPARAM) &szClock);
 
             szTrayClockMin = szClock;
         }
@@ -1338,7 +1362,7 @@ public:
         NoClock:
         szTrayClockMin = szClock;
 
-        if (Horizontal)
+        if (IsHorizontal)
         {
             szTray.cy = pSize->cy - 2 * TRAY_NOTIFY_WND_SPACING_Y;
         }
@@ -1347,11 +1371,11 @@ public:
             szTray.cx = pSize->cx - 2 * TRAY_NOTIFY_WND_SPACING_X;
         }
 
-        m_pager->GetSize(Horizontal, &szTray);
+        m_pager->GetSize(IsHorizontal, &szTray);
 
         szTrayNotify = szTray;
 
-        if (Horizontal)
+        if (IsHorizontal)
         {
             pSize->cx = 2 * TRAY_NOTIFY_WND_SPACING_X;
 
@@ -1427,6 +1451,7 @@ public:
 
     LRESULT DrawBackground(HDC hdc)
     {
+        HRESULT res;
         RECT rect;
 
         GetClientRect(&rect);
@@ -1438,10 +1463,10 @@ public:
                 DrawThemeParentBackground(m_hWnd, hdc, &rect);
             }
 
-            DrawThemeBackground(TrayTheme, hdc, TNP_BACKGROUND, 0, &rect, 0);
+            res = DrawThemeBackground(TrayTheme, hdc, TNP_BACKGROUND, 0, &rect, 0);
         }
 
-        return TRUE;
+        return res;
     }
 
     LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
@@ -1469,15 +1494,26 @@ public:
 
     BOOL GetClockRect(OUT PRECT rcClock)
     {
-        if (!IsWindowVisible(m_clock->m_hWnd))
+        if (!m_clock->IsWindowVisible())
             return FALSE;
 
-        return GetWindowRect(m_clock->m_hWnd, rcClock);
+        return m_clock->GetWindowRect(rcClock);
     }
 
     LRESULT OnGetMinimumSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
-        return (LRESULT) GetMinimumSize((BOOL) wParam, (PSIZE) lParam);
+        BOOL Horizontal = (BOOL) wParam;
+
+        if (Horizontal != IsHorizontal)
+        {
+            IsHorizontal = Horizontal;
+            if (IsHorizontal)
+                SetWindowTheme(m_hWnd, L"TrayNotifyHoriz", NULL);
+            else
+                SetWindowTheme(m_hWnd, L"TrayNotifyVert", NULL);
+        }
+
+        return (LRESULT) GetMinimumSize((PSIZE) lParam);
     }
 
     LRESULT OnUpdateTime(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)