[EXPLORER_NEW]
[reactos.git] / base / shell / explorer-new / traywnd.c
index 506409d..3cd2f77 100644 (file)
 
 #include "precomp.h"
 
+extern HRESULT InitShellServices(HDPA * phdpa);
+extern HRESULT ShutdownShellServices(HDPA hdpa);
+
 static const TRAYWINDOW_CTXMENU TrayWindowCtxMenu;
 
 #define WM_APP_TRAYDESTROY  (WM_APP + 0x100)
 
+#define TIMER_ID_AUTOHIDE 1
+#define TIMER_ID_MOUSETRACK 2
+#define MOUSETRACK_INTERVAL 100
+#define AUTOHIDE_DELAY_HIDE 2000
+#define AUTOHIDE_DELAY_SHOW 50
+#define AUTOHIDE_INTERVAL_ANIMATING 10
+
+#define AUTOHIDE_SPEED_SHOW 10
+#define AUTOHIDE_SPEED_HIDE 1
+
+#define AUTOHIDE_HIDDEN 0
+#define AUTOHIDE_SHOWING 1
+#define AUTOHIDE_SHOWN 2
+#define AUTOHIDE_HIDING 3
+
 static LONG TrayWndCount = 0;
 
 static const TCHAR szTrayWndClass[] = TEXT("Shell_TrayWnd");
@@ -94,8 +112,16 @@ typedef struct
 
     HWND hwndTrayPropertiesOwner;
     HWND hwndRunFileDlgOwner;
+
+    UINT AutoHideState;
+    SIZE AutoHideOffset;
+    TRACKMOUSEEVENT MouseTrackingInfo;
+
+    HDPA hdpaShellServices;
 } ITrayWindowImpl;
 
+static ITrayWindowImpl * g_TrayWindow;
+
 BOOL LaunchCPanel(HWND hwnd, LPCTSTR applet)
 {
     TCHAR szParams[MAX_PATH];
@@ -484,7 +510,13 @@ GetPrimaryScreenRect:
                                                   &rcScreen,
                                                   &szTray,
                                                   pRect);
-
+        if (This->AutoHide)
+        {
+            pRect->left += This->AutoHideOffset.cx;
+            pRect->right += This->AutoHideOffset.cx;
+            pRect->top += This->AutoHideOffset.cy;
+            pRect->bottom += This->AutoHideOffset.cy;
+        }
         hMon = hMonNew;
     }
     else
@@ -492,6 +524,13 @@ GetPrimaryScreenRect:
         /* The user is dragging the tray window on the same monitor. We don't need
            to recalculate the rectangle */
         *pRect = This->rcTrayWnd[Pos];
+        if (This->AutoHide)
+        {
+            pRect->left += This->AutoHideOffset.cx;
+            pRect->right += This->AutoHideOffset.cx;
+            pRect->top += This->AutoHideOffset.cy;
+            pRect->bottom += This->AutoHideOffset.cy;
+        }
     }
 
     *phMonitor = hMon;
@@ -530,6 +569,13 @@ ITrayWindowImpl_ChangingWinPos(IN OUT ITrayWindowImpl *This,
         rcTray.top = pwp->y;
         rcTray.right = rcTray.left + pwp->cx;
         rcTray.bottom = rcTray.top + pwp->cy;
+        if (This->AutoHide)
+        {
+            rcTray.left -= This->AutoHideOffset.cx;
+            rcTray.right -= This->AutoHideOffset.cx;
+            rcTray.top -= This->AutoHideOffset.cy;
+            rcTray.bottom -= This->AutoHideOffset.cy;
+        }
 
         if (!EqualRect(&rcTray,
                        &This->rcTrayWnd[This->DraggingPosition]))
@@ -587,6 +633,13 @@ ITrayWindowImpl_ChangingWinPos(IN OUT ITrayWindowImpl *This,
                                                      &rcTray);
             }
 
+            if (This->AutoHide)
+            {
+                rcTray.left -= This->AutoHideOffset.cx;
+                rcTray.right -= This->AutoHideOffset.cx;
+                rcTray.top -= This->AutoHideOffset.cy;
+                rcTray.bottom -= This->AutoHideOffset.cy;
+            }
             This->rcTrayWnd[This->Position] = rcTray;
         }
         else
@@ -601,6 +654,14 @@ ChangePos:
         This->TraySize.cx = rcTray.right - rcTray.left;
         This->TraySize.cy = rcTray.bottom - rcTray.top;
 
+        if (This->AutoHide)
+        {
+            rcTray.left += This->AutoHideOffset.cx;
+            rcTray.right += This->AutoHideOffset.cx;
+            rcTray.top += This->AutoHideOffset.cy;
+            rcTray.bottom += This->AutoHideOffset.cy;
+        }
+
         pwp->flags &= ~(SWP_NOMOVE | SWP_NOSIZE);
         pwp->x = rcTray.left;
         pwp->y = rcTray.top;
@@ -712,7 +773,16 @@ ITrayWindowImpl_CheckTrayWndPosition(IN OUT ITrayWindowImpl *This)
     RECT rcTray;
 
     rcTray = This->rcTrayWnd[This->Position];
-//    DbgPrint("CheckTray: %d: %d,%d,%d,%d\n", This->Position, rcTray.left, rcTray.top, rcTray.right, rcTray.bottom);
+    
+    if (This->AutoHide)
+    {
+        rcTray.left += This->AutoHideOffset.cx;
+        rcTray.right += This->AutoHideOffset.cx;
+        rcTray.top += This->AutoHideOffset.cy;
+        rcTray.bottom += This->AutoHideOffset.cy;
+    }
+
+//    TRACE("CheckTray: %d: %d,%d,%d,%d\n", This->Position, rcTray.left, rcTray.top, rcTray.right, rcTray.bottom);
 
     /* Move the tray window */
     SetWindowPos(This->hWnd,
@@ -843,7 +913,7 @@ ITrayWindowImpl_RegLoadSettings(IN OUT ITrayWindowImpl *This)
                                                   &rcScreen,
                                                   &This->TraySize,
                                                   &This->rcTrayWnd[Pos]);
-//        DbgPrint("rcTrayWnd[%d(%d)]: %d,%d,%d,%d\n", Pos, This->Position, This->rcTrayWnd[Pos].left, This->rcTrayWnd[Pos].top, This->rcTrayWnd[Pos].right, This->rcTrayWnd[Pos].bottom);
+//        TRACE("rcTrayWnd[%d(%d)]: %d,%d,%d,%d\n", Pos, This->Position, This->rcTrayWnd[Pos].left, This->rcTrayWnd[Pos].top, This->rcTrayWnd[Pos].right, This->rcTrayWnd[Pos].bottom);
     }
 
     /* Determine which monitor we are on. It shouldn't matter which docked
@@ -953,6 +1023,8 @@ ITrayWindowImpl_TrackCtxMenu(IN OUT ITrayWindowImpl *This,
                               cmdId,
                               pcmContext,
                               Context);
+
+        DestroyMenu(hPopup);
     }
 
     return cmdId;
@@ -986,6 +1058,13 @@ ITrayWindowImpl_Destroy(ITrayWindowImpl *This)
     (void)InterlockedExchangePointer((PVOID*)&This->hWnd,
                                      NULL);
 
+
+    if (This->hdpaShellServices != NULL)
+    {
+        ShutdownShellServices(This->hdpaShellServices);
+        This->hdpaShellServices = NULL;
+    }
+
     if (This->himlStartBtn != NULL)
     {
         ImageList_Destroy(This->himlStartBtn);
@@ -1586,6 +1665,14 @@ SetStartBtnImage:
     /* Align all controls on the tray window */
     ITrayWindowImpl_AlignControls(This,
                                   NULL);
+
+    InitShellServices(&(This->hdpaShellServices));
+
+    if (This->AutoHide)
+    {
+        This->AutoHideState = AUTOHIDE_HIDING;
+        SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL);
+    }
 }
 
 static HRESULT STDMETHODCALLTYPE
@@ -1898,7 +1985,7 @@ ITrayWindowImpl_ExecContextMenuCmd(IN OUT ITrayWindow *iface,
             break;
 
         default:
-            DbgPrint("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd);
+            TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd);
             bHandled = FALSE;
             break;
     }
@@ -2108,10 +2195,186 @@ static void PopupStartMenu(IN ITrayWindowImpl *This)
                 &pt,
                 &rcExclude,
                 dwFlags);
+
+            SendMessageW(This->hwndStart, BM_SETSTATE, TRUE, 0);
+        }
+    }
+}
+
+static void
+ProcessMouseTracking(ITrayWindowImpl * This)
+{
+    RECT rcCurrent;
+    POINT pt;
+    BOOL over;
+    UINT state = This->AutoHideState;
+
+    GetCursorPos(&pt);
+    GetWindowRect(This->hWnd, &rcCurrent);
+    over = PtInRect(&rcCurrent, pt);
+
+    if (SendMessage(This->hwndStart, BM_GETSTATE, 0, 0) != BST_UNCHECKED)
+    {
+        over = TRUE;
+    }
+
+    if (over)
+    {
+        if (state == AUTOHIDE_HIDING)
+        {
+            TRACE("AutoHide cancelling hide.\n");
+            This->AutoHideState = AUTOHIDE_SHOWING;
+            SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
+        }
+        else if (state == AUTOHIDE_HIDDEN)
+        {
+            TRACE("AutoHide starting show.\n");
+            This->AutoHideState = AUTOHIDE_SHOWING;
+            SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_SHOW, NULL);
+        }
+    }
+    else
+    {
+        if (state == AUTOHIDE_SHOWING)
+        {
+            TRACE("AutoHide cancelling show.\n");
+            This->AutoHideState = AUTOHIDE_HIDING;
+            SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
+        }
+        else if (state == AUTOHIDE_SHOWN)
+        {
+            TRACE("AutoHide starting hide.\n");
+            This->AutoHideState = AUTOHIDE_HIDING;
+            SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL);
         }
+
+        KillTimer(This->hWnd, TIMER_ID_MOUSETRACK);
     }
 }
 
+static void
+ProcessAutoHide(ITrayWindowImpl * This)
+{
+    RECT rc = This->rcTrayWnd[This->Position];
+    INT w = This->TraySize.cx - GetSystemMetrics(SM_CXBORDER) * 2 - 1;
+    INT h = This->TraySize.cy - GetSystemMetrics(SM_CYBORDER) * 2 - 1;
+
+    TRACE("AutoHide Timer received for %u, rc=(%d, %d, %d, %d), w=%d, h=%d.\n", This->AutoHideState, rc.left, rc.top, rc.right, rc.bottom, w, h);
+
+    switch (This->AutoHideState)
+    {
+    case AUTOHIDE_HIDING:
+        switch (This->Position)
+        {
+        case ABE_LEFT:
+            This->AutoHideOffset.cy = 0;
+            This->AutoHideOffset.cx -= AUTOHIDE_SPEED_HIDE;
+            if (This->AutoHideOffset.cx < -w)
+                This->AutoHideOffset.cx = -w;
+            break;
+        case ABE_TOP:
+            This->AutoHideOffset.cx = 0;
+            This->AutoHideOffset.cy -= AUTOHIDE_SPEED_HIDE;
+            if (This->AutoHideOffset.cy < -h)
+                This->AutoHideOffset.cy = -h;
+            break;
+        case ABE_RIGHT:
+            This->AutoHideOffset.cy = 0;
+            This->AutoHideOffset.cx += AUTOHIDE_SPEED_HIDE;
+            if (This->AutoHideOffset.cx > w)
+                This->AutoHideOffset.cx = w;
+            break;
+        case ABE_BOTTOM:
+            This->AutoHideOffset.cx = 0;
+            This->AutoHideOffset.cy += AUTOHIDE_SPEED_HIDE;
+            if (This->AutoHideOffset.cy > h)
+                This->AutoHideOffset.cy = h;
+            break;
+        }
+
+        if (This->AutoHideOffset.cx != w && This->AutoHideOffset.cy != h)
+        {
+            SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
+            break;
+        }
+
+        /* fallthrough */
+    case AUTOHIDE_HIDDEN:
+
+        switch (This->Position)
+        {
+        case ABE_LEFT:
+            This->AutoHideOffset.cx = -w;
+            This->AutoHideOffset.cy = 0;
+            break;
+        case ABE_TOP:
+            This->AutoHideOffset.cx = 0;
+            This->AutoHideOffset.cy = -h;
+            break;
+        case ABE_RIGHT:
+            This->AutoHideOffset.cx = w;
+            This->AutoHideOffset.cy = 0;
+            break;
+        case ABE_BOTTOM:
+            This->AutoHideOffset.cx = 0;
+            This->AutoHideOffset.cy = h;
+            break;
+        }
+
+        KillTimer(This->hWnd, TIMER_ID_AUTOHIDE);
+        This->AutoHideState = AUTOHIDE_HIDDEN;
+        break;
+
+    case AUTOHIDE_SHOWING:
+        if (This->AutoHideOffset.cx >= AUTOHIDE_SPEED_SHOW)
+        {
+            This->AutoHideOffset.cx -= AUTOHIDE_SPEED_SHOW;
+        }
+        else if (This->AutoHideOffset.cx <= -AUTOHIDE_SPEED_SHOW)
+        {
+            This->AutoHideOffset.cx += AUTOHIDE_SPEED_SHOW;
+        }
+        else
+        {
+            This->AutoHideOffset.cx = 0;
+        }
+
+        if (This->AutoHideOffset.cy >= AUTOHIDE_SPEED_SHOW)
+        {
+            This->AutoHideOffset.cy -= AUTOHIDE_SPEED_SHOW;
+        }
+        else if (This->AutoHideOffset.cy <= -AUTOHIDE_SPEED_SHOW)
+        {
+            This->AutoHideOffset.cy += AUTOHIDE_SPEED_SHOW;
+        }
+        else
+        {
+            This->AutoHideOffset.cy = 0;
+        }
+
+        if (This->AutoHideOffset.cx != 0 || This->AutoHideOffset.cy != 0)
+        {
+            SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
+            break;
+        }
+
+        /* fallthrough */
+    case AUTOHIDE_SHOWN:
+
+        KillTimer(This->hWnd, TIMER_ID_AUTOHIDE);
+        This->AutoHideState = AUTOHIDE_SHOWN;
+        break;
+    }
+
+    rc.left += This->AutoHideOffset.cx;
+    rc.right += This->AutoHideOffset.cx;
+    rc.top += This->AutoHideOffset.cy;
+    rc.bottom += This->AutoHideOffset.cy;
+
+    TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc.left, rc.top, rc.right, rc.bottom, This->AutoHideState);
+    SetWindowPos(This->hWnd, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE | SWP_NOZORDER);
+}
+
 static LRESULT CALLBACK
 TrayWndProc(IN HWND hwnd,
             IN UINT uMsg,
@@ -2186,8 +2449,7 @@ TrayWndProc(IN HWND hwnd,
             case WM_ERASEBKGND:
                 if (!This->TaskbarTheme)
                     goto DefHandler;
-                return ITrayWindowImpl_DrawBackground(This,
-                                                      (HDC)wParam);
+                return ITrayWindowImpl_DrawBackground(This, (HDC)wParam);
             case WM_CTLCOLORBTN:
                 SetBkMode((HDC)wParam, TRANSPARENT);
                 return (LRESULT)GetStockObject(HOLLOW_BRUSH);
@@ -2268,6 +2530,14 @@ TrayWndProc(IN HWND hwnd,
                 else
                 {
                     *pRect = This->rcTrayWnd[This->Position];
+
+                    if (This->AutoHide)
+                    {
+                        pRect->left += This->AutoHideOffset.cx;
+                        pRect->right += This->AutoHideOffset.cx;
+                        pRect->top += This->AutoHideOffset.cy;
+                        pRect->bottom += This->AutoHideOffset.cy;
+                    }
                 }
                 return TRUE;
             }
@@ -2285,6 +2555,14 @@ TrayWndProc(IN HWND hwnd,
                 else
                 {
                     *pRect = This->rcTrayWnd[This->Position];
+                    
+                    if (This->AutoHide)
+                    {
+                        pRect->left += This->AutoHideOffset.cx;
+                        pRect->right += This->AutoHideOffset.cx;
+                        pRect->top += This->AutoHideOffset.cy;
+                        pRect->bottom += This->AutoHideOffset.cy;
+                    }
                 }
                 return TRUE;
             }
@@ -2610,9 +2888,13 @@ HandleTrayContextMenu:
                     break;
 
                 if (IsWindowVisible(hwndStartMenu))
-                    SetWindowPos(hwndStartMenu, 0,0,0,0,0, SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
+                {
+                    IMenuPopup_OnSelect(This->StartMenuPopup, MPOS_CANCELLEVEL);
+                }
                 else
+                {
                     SendMessage(This->hWnd, WM_COMMAND, MAKEWPARAM(BN_CLICKED, IDC_STARTBTN), (LPARAM)This->hwndStart);
+                }
 
                 break;
             }
@@ -2640,8 +2922,33 @@ HandleTrayContextMenu:
                             break;
 
                         case IDM_SEARCH:
+                            break;
+
                         case IDM_HELPANDSUPPORT:
+                        {
+                            /* TODO: Implement properly */
+
+                            LPCWSTR strSite = L"https://www.reactos.org/";
+
+                            /* TODO: Make localizable */
+                            LPCWSTR strCaption = L"Sorry";
+                            LPCWSTR strMessage = L"ReactOS could not browse to '%s' (error %d). Please make sure there is a web browser installed.";
+                            WCHAR tmpMessage[512];
+
+                            /* TODO: Read from the registry */
+                            LPCWSTR strVerb = NULL; /* default */
+                            LPCWSTR strPath = strSite;
+                            LPCWSTR strParams = NULL;
+
+                            /* The return value is defined as HINSTANCE for backwards compatibility only, the cast is needed */
+                            int result = (int) ShellExecuteW(hwnd, strVerb, strPath, strParams, NULL, SW_SHOWNORMAL);
+                            if (result <= 32)
+                            {
+                                StringCchPrintfW(tmpMessage, 512, strMessage, strSite, result);
+                                MessageBoxExW(hwnd, tmpMessage, strCaption, MB_OK, 0);
+                            }
                             break;
+                        }
 
                         case IDM_RUN:
                         {
@@ -2671,6 +2978,27 @@ HandleTrayContextMenu:
                 }
                 break;
 
+            case WM_MOUSEMOVE:
+            case WM_NCMOUSEMOVE:
+
+                if (This->AutoHide)
+                {
+                    SetTimer(This->hWnd, TIMER_ID_MOUSETRACK, MOUSETRACK_INTERVAL, NULL);
+                }
+
+                break;
+            case WM_TIMER:
+                if (wParam == TIMER_ID_MOUSETRACK)
+                {
+                    ProcessMouseTracking(This);
+                }
+                else if (wParam == TIMER_ID_AUTOHIDE)
+                {
+                    ProcessAutoHide(This);
+                }
+
+                goto DefHandler;
+
             default:
                 goto DefHandler;
         }
@@ -2726,7 +3054,7 @@ CreateTrayWindowContextMenu(IN HWND hWndOwner,
                                                         CMF_NORMAL,
                                                         &pcm)))
             {
-                DbgPrint("ITrayBandSite::AddContextMenus succeeded!\n");
+                TRACE("ITrayBandSite::AddContextMenus succeeded!\n");
                 *(IContextMenu **)ppcmContext = pcm;
             }
         }
@@ -2831,6 +3159,8 @@ CreateTrayWindow(VOID)
 
         ITrayWindowImpl_Open(TrayWindow);
 
+        g_TrayWindow = This;
+
         return TrayWindow;
     }
 
@@ -2925,7 +3255,7 @@ ITrayWindowImpl_IShellDesktopTray_QueryInterface(IN OUT IShellDesktopTray *iface
     ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface);
     ITrayWindow *tray = ITrayWindow_from_impl(This);
 
-    DbgPrint("IShellDesktopTray::QueryInterface(0x%p, 0x%p)\n", riid, ppvObj);
+    TRACE("IShellDesktopTray::QueryInterface(0x%p, 0x%p)\n", riid, ppvObj);
     return ITrayWindowImpl_QueryInterface(tray,
                                           riid,
                                           ppvObj);
@@ -2937,7 +3267,7 @@ ITrayWindowImpl_IShellDesktopTray_Release(IN OUT IShellDesktopTray *iface)
     ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface);
     ITrayWindow *tray = ITrayWindow_from_impl(This);
 
-    DbgPrint("IShellDesktopTray::Release()\n");
+    TRACE("IShellDesktopTray::Release()\n");
     return ITrayWindowImpl_Release(tray);
 }
 
@@ -2947,7 +3277,7 @@ ITrayWindowImpl_IShellDesktopTray_AddRef(IN OUT IShellDesktopTray *iface)
     ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface);
     ITrayWindow *tray = ITrayWindow_from_impl(This);
 
-    DbgPrint("IShellDesktopTray::AddRef()\n");
+    TRACE("IShellDesktopTray::AddRef()\n");
     return ITrayWindowImpl_AddRef(tray);
 }
 
@@ -2955,7 +3285,7 @@ static ULONG STDMETHODCALLTYPE
 ITrayWindowImpl_IShellDesktopTray_GetState(IN OUT IShellDesktopTray *iface)
 {
     /* FIXME: Return ABS_ flags? */
-    DbgPrint("IShellDesktopTray::GetState() unimplemented!\n");
+    TRACE("IShellDesktopTray::GetState() unimplemented!\n");
     return 0;
 }
 
@@ -2964,7 +3294,7 @@ ITrayWindowImpl_IShellDesktopTray_GetTrayWindow(IN OUT IShellDesktopTray *iface,
                                                 OUT HWND *phWndTray)
 {
     ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface);
-    DbgPrint("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray);
+    TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray);
     *phWndTray = This->hWnd;
     return S_OK;
 }
@@ -2974,7 +3304,7 @@ ITrayWindowImpl_IShellDesktopTray_RegisterDesktopWindow(IN OUT IShellDesktopTray
                                                         IN HWND hWndDesktop)
 {
     ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface);
-    DbgPrint("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop);
+    TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop);
 
     This->hWndDesktop = hWndDesktop;
     return S_OK;
@@ -2985,7 +3315,7 @@ ITrayWindowImpl_IShellDesktopTray_Unknown(IN OUT IShellDesktopTray *iface,
                                           IN DWORD dwUnknown1,
                                           IN DWORD dwUnknown2)
 {
-    DbgPrint("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1, dwUnknown2);
+    TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1, dwUnknown2);
     return S_OK;
 }
 
@@ -3001,3 +3331,16 @@ static const IShellDesktopTrayVtbl IShellDesktopTrayImpl_Vtbl =
     ITrayWindowImpl_IShellDesktopTray_RegisterDesktopWindow,
     ITrayWindowImpl_IShellDesktopTray_Unknown
 };
+
+HRESULT
+ITrayWindowImpl_RaiseStartButton(ITrayWindowImpl * This)
+{
+    SendMessageW(This->hwndStart, BM_SETSTATE, FALSE, 0);
+    return S_OK;
+}
+
+HRESULT
+Tray_OnStartMenuDismissed()
+{
+    return ITrayWindowImpl_RaiseStartButton(g_TrayWindow);
+}
\ No newline at end of file