[EXPLORER-NEW]
[reactos.git] / base / shell / explorer-new / traywnd.c
index 0cfdb21..d05ae39 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,13 +112,26 @@ 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];
-    _tcscpy(szParams, TEXT("shell32.dll,Control_RunDLL "));
-    _tcscat(szParams, applet);
+
+    StringCbCopy(szParams, sizeof(szParams),
+        TEXT("shell32.dll,Control_RunDLL "));
+    if (FAILED(StringCbCat(szParams, sizeof(szParams),
+            applet)))
+        return FALSE;
+
     return (ShellExecute(hwnd, TEXT("open"), TEXT("rundll32.exe"), szParams, NULL, SW_SHOWDEFAULT) > (HINSTANCE)32);
 }
 
@@ -479,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
@@ -487,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;
@@ -525,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]))
@@ -582,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
@@ -596,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;
@@ -707,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,
@@ -763,15 +838,6 @@ ITrayWindowImpl_RegLoadSettings(IN OUT ITrayWindowImpl *This)
 
         /* FIXME: Are there more flags? */
 
-        if (This->hWnd != NULL)
-            SetWindowPos (This->hWnd,
-                          This->AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
-                          0,
-                          0,
-                          0,
-                          0,
-                          SWP_NOMOVE | SWP_NOSIZE);
-
         if (sr.Position > ABE_BOTTOM)
             This->Position = ABE_BOTTOM;
         else
@@ -789,6 +855,7 @@ ITrayWindowImpl_RegLoadSettings(IN OUT ITrayWindowImpl *This)
     else
     {
         This->Position = ABE_BOTTOM;
+        This->AlwaysOnTop = TRUE;
 
         /* Use the minimum size of the taskbar, we'll use the start
            button as a minimum for now. Make sure we calculate the
@@ -808,6 +875,15 @@ ITrayWindowImpl_RegLoadSettings(IN OUT ITrayWindowImpl *This)
                                               MONITOR_DEFAULTTOPRIMARY);
     }
 
+    if (This->hWnd != NULL)
+        SetWindowPos(This->hWnd,
+        This->AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
+        0,
+        0,
+        0,
+        0,
+        SWP_NOMOVE | SWP_NOSIZE);
+
     /* Determine a minimum tray window rectangle. The "client" height is
        zero here since we cannot determine an optimal minimum width when
        loaded as a vertical tray window. We just need to make sure the values
@@ -837,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
@@ -947,6 +1023,8 @@ ITrayWindowImpl_TrackCtxMenu(IN OUT ITrayWindowImpl *This,
                               cmdId,
                               pcmContext,
                               Context);
+
+        DestroyMenu(hPopup);
     }
 
     return cmdId;
@@ -980,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);
@@ -1580,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
@@ -1892,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;
     }
@@ -2067,6 +2160,221 @@ ITrayWindowImpl_DisplayRunFileDlg(IN ITrayWindowImpl *This)
     CloseHandle(CreateThread(NULL, 0, RunFileDlgThread, This, 0, NULL));
 }
 
+static void PopupStartMenu(IN ITrayWindowImpl *This)
+{
+    if (This->StartMenuPopup != NULL)
+    {
+        POINTL pt;
+        RECTL rcExclude;
+        DWORD dwFlags = 0;
+
+        if (GetWindowRect(This->hwndStart,
+            (RECT*) &rcExclude))
+        {
+            switch (This->Position)
+            {
+            case ABE_BOTTOM:
+                pt.x = rcExclude.left;
+                pt.y = rcExclude.top;
+                dwFlags |= MPPF_BOTTOM;
+                break;
+            case ABE_TOP:
+            case ABE_LEFT:
+                pt.x = rcExclude.left;
+                pt.y = rcExclude.bottom;
+                dwFlags |= MPPF_TOP | MPPF_ALIGN_RIGHT;
+                break;
+            case ABE_RIGHT:
+                pt.x = rcExclude.right;
+                pt.y = rcExclude.bottom;
+                dwFlags |= MPPF_TOP | MPPF_ALIGN_LEFT;
+                break;
+            }
+
+            IMenuPopup_Popup(This->StartMenuPopup,
+                &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,
@@ -2107,6 +2415,19 @@ TrayWndProc(IN HWND hwnd,
 
         switch (uMsg)
         {
+            case WM_DISPLAYCHANGE:
+
+                /* Load the saved tray window settings */
+                ITrayWindowImpl_RegLoadSettings(This);
+
+                /* Move the tray window to the right position and resize it if neccessary */
+                ITrayWindowImpl_CheckTrayWndPosition(This);
+
+                /* Align all controls on the tray window */
+                ITrayWindowImpl_AlignControls(This, NULL);
+
+                break;
+
             case WM_COPYDATA:
             {
                 if (This->hwndTrayNotify)
@@ -2210,6 +2531,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;
             }
@@ -2227,6 +2556,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;
             }
@@ -2545,49 +2882,28 @@ HandleTrayContextMenu:
                 break;
 
             case TWM_OPENSTARTMENU:
-                SendMessage(This->hWnd, WM_COMMAND, MAKEWPARAM(BN_CLICKED, IDC_STARTBTN), (LPARAM)This->hwndStart);
-                break;
+            {
+                HWND hwndStartMenu;
+                HRESULT hr = IUnknown_GetWindow((IUnknown*)This->StartMenuPopup, &hwndStartMenu);
+                if (FAILED(hr))
+                    break;
 
+                if (IsWindowVisible(hwndStartMenu))
+                    SetWindowPos(hwndStartMenu, 0,0,0,0,0, SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
+                else
+                    SendMessage(This->hWnd, WM_COMMAND, MAKEWPARAM(BN_CLICKED, IDC_STARTBTN), (LPARAM)This->hwndStart);
+
+                break;
+            }
             case WM_COMMAND:
                 if ((HWND)lParam == This->hwndStart)
                 {
-                    if (This->StartMenuPopup != NULL)
-                    {
-                        POINTL pt;
-                        RECTL rcExclude;
-                        DWORD dwFlags = 0;
-
-                        if (GetWindowRect(This->hwndStart,
-                                          (RECT*)&rcExclude))
-                        {
-                            if (ITrayWindowImpl_IsPosHorizontal(This))
-                            {
-                                pt.x = rcExclude.left;
-                                pt.y = rcExclude.top;
-                                dwFlags |= MPPF_BOTTOM;
-                            }
-                            else
-                            {
-                                if (This->Position == ABE_LEFT)
-                                    pt.x = rcExclude.left;
-                                else
-                                    pt.x = rcExclude.right;
-
-                                pt.y = rcExclude.bottom;
-                                dwFlags |= MPPF_BOTTOM;
-                            }
-
-                            IMenuPopup_Popup(This->StartMenuPopup,
-                                             &pt,
-                                             &rcExclude,
-                                             dwFlags);
-                        }
-                    }
+                    PopupStartMenu(This);
                     break;
                 }
 
                 if (This->TrayBandSite == NULL ||
-                    !SUCCEEDED(ITrayBandSite_ProcessMessage(This->TrayBandSite,
+                    FAILED(ITrayBandSite_ProcessMessage(This->TrayBandSite,
                                                             hwnd,
                                                             uMsg,
                                                             wParam,
@@ -2598,9 +2914,38 @@ HandleTrayContextMenu:
                     {
                         /* FIXME: Handle these commands as well */
                         case IDM_TASKBARANDSTARTMENU:
+
+                            ITrayWindowImpl_DisplayProperties(ITrayWindow_from_impl(This));
+                            break;
+
                         case IDM_SEARCH:
+                            break;
+
                         case IDM_HELPANDSUPPORT:
+                        {
+                            /* TODO: Implement properly */
+
+                            LPCWSTR strSite = L"http://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:
                         {
@@ -2630,6 +2975,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;
         }
@@ -2685,7 +3051,7 @@ CreateTrayWindowContextMenu(IN HWND hWndOwner,
                                                         CMF_NORMAL,
                                                         &pcm)))
             {
-                DbgPrint("ITrayBandSite::AddContextMenus succeeded!\n");
+                TRACE("ITrayBandSite::AddContextMenus succeeded!\n");
                 *(IContextMenu **)ppcmContext = pcm;
             }
         }
@@ -2790,6 +3156,8 @@ CreateTrayWindow(VOID)
 
         ITrayWindowImpl_Open(TrayWindow);
 
+        g_TrayWindow = This;
+
         return TrayWindow;
     }
 
@@ -2884,7 +3252,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);
@@ -2896,7 +3264,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);
 }
 
@@ -2906,7 +3274,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);
 }
 
@@ -2914,7 +3282,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;
 }
 
@@ -2923,7 +3291,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;
 }
@@ -2933,7 +3301,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;
@@ -2944,7 +3312,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;
 }
 
@@ -2960,3 +3328,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