[EXPLORER-NEW]
[reactos.git] / base / shell / explorer-new / traywnd.c
index 21c3e27..d05ae39 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <precomp.h>
+#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");
@@ -43,6 +61,7 @@ typedef struct
     const IShellDesktopTrayVtbl *lpVtblShellDesktopTray;
     LONG Ref;
 
+    HTHEME TaskbarTheme;
     HWND hWnd;
     HWND hWndDesktop;
 
@@ -91,14 +110,28 @@ typedef struct
     IMenuPopup *StartMenuPopup;
     HBITMAP hbmStartMenu;
 
-    HWND hWndTrayProperties;
+    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);
 }
 
@@ -371,11 +404,11 @@ ITrayWindowImpl_GetMinimumWindowSize(IN OUT ITrayWindowImpl *This,
     RECT rcMin = {0};
 
     AdjustWindowRectEx(&rcMin,
-                       GetWindowLongPtr(This->hWnd,
-                                        GWL_STYLE),
+                       GetWindowLong(This->hWnd,
+                                     GWL_STYLE),
                        FALSE,
-                       GetWindowLongPtr(This->hWnd,
-                                        GWL_EXSTYLE));
+                       GetWindowLong(This->hWnd,
+                                     GWL_EXSTYLE));
 
     *pRect = rcMin;
 }
@@ -477,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
@@ -485,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;
@@ -523,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]))
@@ -580,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
@@ -594,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;
@@ -654,7 +722,7 @@ ITrayWindowImpl_ResizeWorkArea(IN OUT ITrayWindowImpl *This)
     RECT rcTray,rcWorkArea;
 
     /* If monitor has changed then fix the previous monitors work area */
-    if(This->PreviousMonitor!=This->Monitor)
+    if (This->PreviousMonitor != This->Monitor)
     {
         ITrayWindowImpl_GetScreenRect(This,
                                     This->PreviousMonitor,
@@ -670,25 +738,25 @@ ITrayWindowImpl_ResizeWorkArea(IN OUT ITrayWindowImpl *This)
     ITrayWindowImpl_GetScreenRect(This,
                                   This->Monitor,
                                   &rcWorkArea);
-    This->PreviousMonitor=This->Monitor;
+    This->PreviousMonitor = This->Monitor;
 
     /* If AutoHide is false then change the workarea to exclude the area that
        the taskbar covers. */
-    if(!This->AutoHide)
+    if (!This->AutoHide)
     {
-        switch(This->Position)
+        switch (This->Position)
         {
             case ABE_TOP:
-                rcWorkArea.top=rcTray.bottom;
+                rcWorkArea.top = rcTray.bottom;
                 break;
             case ABE_LEFT:
-                rcWorkArea.left=rcTray.right;
+                rcWorkArea.left = rcTray.right;
                 break;
             case ABE_RIGHT:
-                rcWorkArea.right=rcTray.left;
+                rcWorkArea.right = rcTray.left;
                 break;
             case ABE_BOTTOM:
-                rcWorkArea.bottom=rcTray.top;
+                rcWorkArea.bottom = rcTray.top;
                 break;
         }
     }
@@ -705,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,
@@ -761,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
@@ -787,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
@@ -806,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
@@ -835,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
@@ -945,6 +1023,8 @@ ITrayWindowImpl_TrackCtxMenu(IN OUT ITrayWindowImpl *This,
                               cmdId,
                               pcmContext,
                               Context);
+
+        DestroyMenu(hPopup);
     }
 
     return cmdId;
@@ -978,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);
@@ -1027,6 +1114,12 @@ ITrayWindowImpl_Destroy(ITrayWindowImpl *This)
         This->TrayBandSite = NULL;
     }
 
+    if (This->TaskbarTheme)
+    {
+        CloseThemeData(This->TaskbarTheme);
+        This->TaskbarTheme = NULL;
+    }
+
     ITrayWindowImpl_Release(ITrayWindow_from_impl(This));
 
     if (InterlockedDecrement(&TrayWndCount) == 0)
@@ -1113,6 +1206,7 @@ ITrayWindowImpl_AlignControls(IN OUT ITrayWindowImpl *This,
     BOOL Horizontal;
     HDWP dwp;
 
+    ITrayWindowImpl_UpdateStartButton(This, NULL);
     if (prcClient != NULL)
     {
         rcClient = *prcClient;
@@ -1401,11 +1495,26 @@ Cleanup:
     return hBitmap;
 }
 
+static VOID
+ITrayWindowImpl_UpdateTheme(IN OUT ITrayWindowImpl *This)
+{
+    if (This->TaskbarTheme)
+        CloseThemeData(This->TaskbarTheme);
+
+    if (IsThemeActive())
+        This->TaskbarTheme = OpenThemeData(This->hWnd, L"Taskbar");
+    else
+        This->TaskbarTheme = 0;
+}
+
 static VOID
 ITrayWindowImpl_Create(IN OUT ITrayWindowImpl *This)
 {
     TCHAR szStartCaption[32];
 
+    SetWindowTheme(This->hWnd, L"TaskBar", NULL);
+    ITrayWindowImpl_UpdateTheme(This);
+
     InterlockedIncrement(&TrayWndCount);
 
     if (!LoadString(hExplorerInstance,
@@ -1458,6 +1567,7 @@ ITrayWindowImpl_Create(IN OUT ITrayWindowImpl *This)
                                      NULL);
     if (This->hwndStart)
     {
+        SetWindowTheme(This->hwndStart, L"Start", NULL);
         SendMessage(This->hwndStart,
                     WM_SETFONT,
                     (WPARAM)This->hStartBtnFont,
@@ -1538,6 +1648,7 @@ SetStartBtnImage:
     This->TrayBandSite = CreateTrayBandSite(ITrayWindow_from_impl(This),
                                             &This->hwndRebar,
                                             &This->hwndTaskSwitch);
+    SetWindowTheme(This->hwndRebar, L"TaskBar", NULL);
 
     /* Create the tray notification window */
     This->hwndTrayNotify = CreateTrayNotifyWnd(ITrayWindow_from_impl(This),
@@ -1554,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
@@ -1594,13 +1713,11 @@ ITrayWindowImpl_Construct(VOID)
     ITrayWindowImpl *This;
 
     This = HeapAlloc(hProcessHeap,
-                     0,
+                     HEAP_ZERO_MEMORY,
                      sizeof(*This));
     if (This == NULL)
         return NULL;
 
-    ZeroMemory(This,
-               sizeof(*This));
     This->lpVtbl = &ITrayWindowImpl_Vtbl;
     This->lpVtblShellDesktopTray = &IShellDesktopTrayImpl_Vtbl;
     This->Ref = 1;
@@ -1724,19 +1841,56 @@ ITrayWIndowImpl_GetCaptionFonts(IN OUT ITrayWindow *iface,
     return This->hCaptionFont;
 }
 
+static DWORD WINAPI
+TrayPropertiesThread(IN OUT PVOID pParam)
+{
+    ITrayWindowImpl *This = pParam;
+    HWND hwnd;
+    RECT posRect;
+
+    GetWindowRect(This->hwndStart, &posRect);
+    hwnd = CreateWindowEx(0,
+                          WC_STATIC,
+                          NULL,
+                          WS_OVERLAPPED | WS_DISABLED | WS_CLIPSIBLINGS | WS_BORDER | SS_LEFT,
+                          posRect.left,
+                          posRect.top,
+                          posRect.right - posRect.left,
+                          posRect.bottom - posRect.top,
+                          NULL,
+                          NULL,
+                          NULL,
+                          NULL);
+
+    This->hwndTrayPropertiesOwner = hwnd;
+
+    DisplayTrayProperties(hwnd);
+
+    This->hwndTrayPropertiesOwner = NULL;
+    DestroyWindow(hwnd);
+
+    return 0;
+}
+
 static HWND STDMETHODCALLTYPE
 ITrayWindowImpl_DisplayProperties(IN OUT ITrayWindow *iface)
 {
     ITrayWindowImpl *This = impl_from_ITrayWindow(iface);
+    HWND hTrayProp;
 
-    if (This->hWndTrayProperties != NULL)
+    if (This->hwndTrayPropertiesOwner)
     {
-        BringWindowToTop(This->hWndTrayProperties);
-        return This->hWndTrayProperties;
+        hTrayProp = GetLastActivePopup(This->hwndTrayPropertiesOwner);
+        if (hTrayProp != NULL &&
+            hTrayProp != This->hwndTrayPropertiesOwner)
+        {
+            SetForegroundWindow(hTrayProp);
+            return NULL;
+        }
     }
 
-    This->hWndTrayProperties = DisplayTrayProperties(ITrayWindow_from_impl(This));
-    return This->hWndTrayProperties;
+    CloseHandle(CreateThread(NULL, 0, TrayPropertiesThread, This, 0, NULL));
+    return NULL;
 }
 
 static VOID
@@ -1831,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;
     }
@@ -1883,6 +2037,344 @@ static const ITrayWindowVtbl ITrayWindowImpl_Vtbl =
     ITrayWindowImpl_Lock
 };
 
+static int
+ITrayWindowImpl_DrawBackground(IN ITrayWindowImpl *This,
+                               IN HDC dc)
+{
+    int backoundPart;
+    RECT rect;
+
+    GetClientRect(This->hWnd, &rect);
+    switch (This->Position)
+    {
+        case ABE_LEFT:
+            backoundPart = TBP_BACKGROUNDLEFT;
+            break;
+        case ABE_TOP:
+            backoundPart = TBP_BACKGROUNDTOP;
+            break;
+        case ABE_RIGHT:
+            backoundPart = TBP_BACKGROUNDRIGHT;
+            break;
+        case ABE_BOTTOM:
+        default:
+            backoundPart = TBP_BACKGROUNDBOTTOM;
+            break;
+    }
+    DrawThemeBackground(This->TaskbarTheme, dc, backoundPart, 0, &rect, 0);
+    return 0;
+}
+
+static int
+ITrayWindowImpl_DrawSizer(IN ITrayWindowImpl *This,
+                          IN HRGN hRgn)
+{
+    HDC hdc;
+    RECT rect;
+    int backoundPart;
+
+    GetWindowRect(This->hWnd, &rect);
+    OffsetRect(&rect, -rect.left, -rect.top);
+
+    hdc = GetDCEx(This->hWnd, hRgn, DCX_WINDOW | DCX_INTERSECTRGN | DCX_PARENTCLIP);
+
+    switch (This->Position)
+    {
+        case ABE_LEFT:
+            backoundPart = TBP_SIZINGBARLEFT;
+            rect.left = rect.right - GetSystemMetrics(SM_CXSIZEFRAME);
+            break;
+        case ABE_TOP:
+            backoundPart = TBP_SIZINGBARTOP;
+            rect.top = rect.bottom - GetSystemMetrics(SM_CYSIZEFRAME);
+            break;
+        case ABE_RIGHT:
+            backoundPart = TBP_SIZINGBARRIGHT;
+            rect.right = rect.left + GetSystemMetrics(SM_CXSIZEFRAME);
+            break;
+        case ABE_BOTTOM:
+        default:
+            backoundPart = TBP_SIZINGBARBOTTOM;
+            rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZEFRAME);
+            break;
+    }
+
+    DrawThemeBackground(This->TaskbarTheme, hdc, backoundPart, 0, &rect, 0);
+
+    ReleaseDC(This->hWnd, hdc);
+    return 0;
+}
+
+static DWORD WINAPI
+RunFileDlgThread(IN OUT PVOID pParam)
+{
+    ITrayWindowImpl *This = pParam;
+    HANDLE hShell32;
+    RUNFILEDLG RunFileDlg;
+    HWND hwnd;
+    RECT posRect;
+
+    GetWindowRect(This->hwndStart,&posRect);
+
+    hwnd = CreateWindowEx(0,
+                          WC_STATIC,
+                          NULL,
+                          WS_OVERLAPPED | WS_DISABLED | WS_CLIPSIBLINGS | WS_BORDER | SS_LEFT,
+                          posRect.left,
+                          posRect.top,
+                          posRect.right - posRect.left,
+                          posRect.bottom - posRect.top,
+                          NULL,
+                          NULL,
+                          NULL,
+                          NULL);
+
+    This->hwndRunFileDlgOwner = hwnd;
+
+    hShell32 = GetModuleHandle(TEXT("SHELL32.DLL"));
+    RunFileDlg = (RUNFILEDLG)GetProcAddress(hShell32, (LPCSTR)61);
+
+    RunFileDlg(hwnd, NULL, NULL, NULL, NULL, RFF_CALCDIRECTORY);
+
+    This->hwndRunFileDlgOwner = NULL;
+    DestroyWindow(hwnd);
+
+    return 0;
+}
+
+static void
+ITrayWindowImpl_DisplayRunFileDlg(IN ITrayWindowImpl *This)
+{
+    HWND hRunDlg;
+    if (This->hwndRunFileDlgOwner)
+    {
+        hRunDlg = GetLastActivePopup(This->hwndRunFileDlgOwner);
+        if (hRunDlg != NULL &&
+            hRunDlg != This->hwndRunFileDlgOwner)
+        {
+            SetForegroundWindow(hRunDlg);
+            return;
+        }
+    }
+
+    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,
@@ -1923,6 +2415,45 @@ 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)
+                {
+                    TrayNotify_NotifyMsg(This->hwndTrayNotify,
+                                         wParam,
+                                         lParam);
+                }
+                return TRUE;
+            }
+            case WM_THEMECHANGED:
+                ITrayWindowImpl_UpdateTheme(This);
+                return 0;
+            case WM_NCPAINT:
+                if (!This->TaskbarTheme)
+                    goto DefHandler;
+                return ITrayWindowImpl_DrawSizer(This,
+                                                 (HRGN)wParam);
+            case WM_ERASEBKGND:
+                if (!This->TaskbarTheme)
+                    goto DefHandler;
+                return ITrayWindowImpl_DrawBackground(This,
+                                                      (HDC)wParam);
+            case WM_CTLCOLORBTN:
+                SetBkMode((HDC)wParam, TRANSPARENT);
+                return (LRESULT)GetStockObject(HOLLOW_BRUSH);
             case WM_NCHITTEST:
             {
                 RECT rcClient;
@@ -1936,12 +2467,13 @@ TrayWndProc(IN HWND hwnd,
                     return HTBORDER;
                 }
 
+                SetLastError(ERROR_SUCCESS);
                 if (GetClientRect(hwnd,
                                   &rcClient) &&
-                    MapWindowPoints(hwnd,
-                                    NULL,
-                                    (LPPOINT)&rcClient,
-                                    2) != 0)
+                    (MapWindowPoints(hwnd,
+                                     NULL,
+                                     (LPPOINT)&rcClient,
+                                     2) != 0 || GetLastError() == ERROR_SUCCESS))
                 {
                     pt.x = (SHORT)LOWORD(lParam);
                     pt.y = (SHORT)HIWORD(lParam);
@@ -1961,30 +2493,23 @@ TrayWndProc(IN HWND hwnd,
                             if (pt.y > rcClient.bottom)
                                 return HTBOTTOM;
                             break;
-
-                        case ABE_BOTTOM:
-                            if (pt.y < rcClient.top)
-                                return HTTOP;
-                            break;
-
                         case ABE_LEFT:
                             if (pt.x > rcClient.right)
                                 return HTRIGHT;
                             break;
-
                         case ABE_RIGHT:
                             if (pt.x < rcClient.left)
                                 return HTLEFT;
                             break;
-
+                        case ABE_BOTTOM:
                         default:
+                            if (pt.y < rcClient.top)
+                                return HTTOP;
                             break;
                     }
                 }
-
                 return HTBORDER;
             }
-
             case WM_MOVING:
             {
                 POINT ptCursor;
@@ -2006,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;
             }
@@ -2023,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;
             }
@@ -2037,7 +2578,7 @@ TrayWndProc(IN HWND hwnd,
             case WM_SIZE:
             {
                 RECT rcClient;
-
+                InvalidateRect(This->hWnd, NULL, TRUE);
                 if (wParam == SIZE_RESTORED && lParam == 0)
                 {
                     ITrayWindowImpl_ResizeWorkArea(This);
@@ -2290,9 +2831,23 @@ HandleTrayContextMenu:
             }
 
             case WM_NCLBUTTONDBLCLK:
+            {
                 /* We "handle" this message so users can't cause a weird maximize/restore
                    window animation when double-clicking the tray window! */
+
+                /* We should forward mouse messages to child windows here.
+                   Right now, this is only clock double-click */
+                RECT rcClock;
+                if (TrayNotify_GetClockRect(This->hwndTrayNotify, &rcClock))
+                {
+                    POINT ptClick;
+                    ptClick.x = MAKEPOINTS(lParam).x;
+                    ptClick.y = MAKEPOINTS(lParam).y;
+                    if (PtInRect(&rcClock, ptClick))
+                        LaunchCPanel(NULL, TEXT("timedate.cpl"));
+                }
                 break;
+            }
 
             case WM_NCCREATE:
             {
@@ -2326,69 +2881,75 @@ HandleTrayContextMenu:
                 DestroyWindow(hwnd);
                 break;
 
+            case TWM_OPENSTARTMENU:
+            {
+                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,
                                                             lParam,
                                                             &Ret)))
                 {
-                    switch(LOWORD(wParam))
+                    switch (LOWORD(wParam))
                     {
                         /* FIXME: Handle these commands as well */
                         case IDM_TASKBARANDSTARTMENU:
+
+                            ITrayWindowImpl_DisplayProperties(ITrayWindow_from_impl(This));
+                            break;
+
                         case IDM_SEARCH:
-                        case IDM_HELPANDSUPPORT:
                             break;
 
-                        case IDM_RUN:
+                        case IDM_HELPANDSUPPORT:
                         {
-                            HANDLE hShell32;
-                            RUNFILEDLG RunFileDlg;
+                            /* TODO: Implement properly */
 
-                            hShell32 = GetModuleHandle(TEXT("SHELL32.DLL"));
-                            RunFileDlg = (RUNFILEDLG)GetProcAddress(hShell32, (LPCSTR)61);
+                            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];
 
-                            RunFileDlg(hwnd, NULL, NULL, NULL, NULL, RFF_CALCDIRECTORY);
+                            /* 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:
+                        {
+                            ITrayWindowImpl_DisplayRunFileDlg(This);
                             break;
                         }
 
@@ -2414,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;
         }
@@ -2469,7 +3051,7 @@ CreateTrayWindowContextMenu(IN HWND hWndOwner,
                                                         CMF_NORMAL,
                                                         &pcm)))
             {
-                DbgPrint("ITrayBandSite::AddContextMenus succeeded!\n");
+                TRACE("ITrayBandSite::AddContextMenus succeeded!\n");
                 *(IContextMenu **)ppcmContext = pcm;
             }
         }
@@ -2574,6 +3156,8 @@ CreateTrayWindow(VOID)
 
         ITrayWindowImpl_Open(TrayWindow);
 
+        g_TrayWindow = This;
+
         return TrayWindow;
     }
 
@@ -2622,24 +3206,31 @@ TrayMessageLoop(IN OUT ITrayWindow *Tray)
 
     while (1)
     {
-        Ret = (GetMessage(&Msg,
-                          NULL,
-                          0,
-                          0) != 0);
+        Ret = GetMessage(&Msg,
+                         NULL,
+                         0,
+                         0);
 
-        if (Ret != -1)
-        {
-            if (!Ret)
-                break;
+        if (!Ret || Ret == -1)
+            break;
 
-            if (This->StartMenuBand == NULL ||
-                IMenuBand_IsMenuMessage(This->StartMenuBand,
-                                        &Msg) != S_OK)
+        if (Msg.message == WM_HOTKEY)
+        {
+            switch (Msg.wParam)
             {
-                TranslateMessage(&Msg);
-                DispatchMessage(&Msg);
+                case IDHK_RUN: /* Win+R */
+                    ITrayWindowImpl_DisplayRunFileDlg(This);
+                    break;
             }
         }
+
+        if (This->StartMenuBand == NULL ||
+            IMenuBand_IsMenuMessage(This->StartMenuBand,
+                                    &Msg) != S_OK)
+        {
+            TranslateMessage(&Msg);
+            DispatchMessage(&Msg);
+        }
     }
 }
 
@@ -2661,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);
@@ -2673,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);
 }
 
@@ -2683,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);
 }
 
@@ -2691,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;
 }
 
@@ -2700,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;
 }
@@ -2710,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;
@@ -2721,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;
 }
 
@@ -2737,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