[EXPLORER] -Implement the minimum taskbar size for the vertical position.
[reactos.git] / reactos / base / shell / explorer / traywnd.cpp
index 702e292..bb2b6ae 100644 (file)
@@ -53,9 +53,7 @@ HRESULT TrayWindowCtxMenuCreator(ITrayWindow * TrayWnd, IN HWND hWndOwner, ICont
 #define IDHK_DESKTOP 0x1fe
 #define IDHK_PAGER 0x1ff
 
-static LONG TrayWndCount = 0;
-
-static const WCHAR szTrayWndClass [] = TEXT("Shell_TrayWnd");
+static const WCHAR szTrayWndClass[] = L"Shell_TrayWnd";
 
 /*
  * ITrayWindow
@@ -64,16 +62,19 @@ static const WCHAR szTrayWndClass [] = TEXT("Shell_TrayWnd");
 const GUID IID_IShellDesktopTray = { 0x213e2df9, 0x9a14, 0x4328, { 0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9 } };
 
 class CStartButton
-    : public CContainedWindow
+    : public CWindowImpl<CStartButton>
 {
     HIMAGELIST m_ImageList;
     SIZE       m_Size;
     HFONT      m_Font;
 
 public:
-    CStartButton(CMessageMap *pObject, DWORD dwMsgMapID)
-        : CContainedWindow(pObject, dwMsgMapID)
+    CStartButton()
+        : m_ImageList(NULL),
+          m_Font(NULL)
     {
+        m_Size.cx = 0;
+        m_Size.cy = 0;
     }
 
     virtual ~CStartButton()
@@ -85,268 +86,102 @@ public:
             DeleteObject(m_Font);
     }
 
-    HFONT GetFont()
-    {
-        return m_Font;
-    }
-
     SIZE GetSize()
     {
         return m_Size;
     }
 
-    VOID UpdateSize(IN HBITMAP hbmStart = NULL)
+    VOID UpdateSize()
     {
         SIZE Size = { 0, 0 };
 
         if (m_ImageList == NULL ||
             !SendMessageW(BCM_GETIDEALSIZE, 0, (LPARAM) &Size))
         {
-            Size.cx = 2 * GetSystemMetrics(SM_CXEDGE);
-            Size.cy = 2 * GetSystemMetrics(SM_CYEDGE);
-
-            if (hbmStart == NULL)
-            {
-                hbmStart = (HBITMAP) SendMessageW(BM_GETIMAGE, IMAGE_BITMAP, 0);
-            }
-
-            if (hbmStart != NULL)
-            {
-                BITMAP bmp;
-
-                if (GetObject(hbmStart, sizeof(bmp), &bmp) != 0)
-                {
-                    Size.cx += bmp.bmWidth;
-                    Size.cy += max(bmp.bmHeight, GetSystemMetrics(SM_CYCAPTION));
-                }
-                else
-                {
-                    /* Huh?! Shouldn't happen... */
-                    goto DefSize;
-                }
-            }
-            else
-            {
-DefSize:
-                Size.cx += GetSystemMetrics(SM_CXMINIMIZED);
-                Size.cy += GetSystemMetrics(SM_CYCAPTION);
-            }
+            Size.cx = 2 * GetSystemMetrics(SM_CXEDGE) + GetSystemMetrics(SM_CYCAPTION) * 3;
         }
 
+        Size.cy = max(Size.cy, GetSystemMetrics(SM_CYCAPTION));
+
         /* Save the size of the start button */
         m_Size = Size;
     }
 
-    BOOL CreateImageList()
+    VOID UpdateFont()
     {
-        HICON hIconStart;
-        SIZE IconSize;
-
-        if (m_ImageList != NULL)
-            return TRUE;
-
-        IconSize.cx = GetSystemMetrics(SM_CXSMICON);
-        IconSize.cy = GetSystemMetrics(SM_CYSMICON);
+        /* Get the system fonts, we use the caption font, always bold, though. */
+        NONCLIENTMETRICS ncm = {sizeof(ncm)};
+        if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, FALSE))
+            return;
 
-        /* Load the start button icon and create a image list for it */
-        hIconStart = (HICON) LoadImage(hExplorerInstance,
-                                       MAKEINTRESOURCE(IDI_START),
-                                       IMAGE_ICON,
-                                       IconSize.cx,
-                                       IconSize.cy,
-                                       LR_SHARED | LR_DEFAULTCOLOR);
+        if (m_Font)
+            DeleteObject(m_Font);
 
-        if (hIconStart == NULL)
-            return FALSE;
+        ncm.lfCaptionFont.lfWeight = FW_BOLD;
+        m_Font = CreateFontIndirect(&ncm.lfCaptionFont);
 
-        m_ImageList = ImageList_Create(IconSize.cx,
-                                        IconSize.cy,
-                                        ILC_COLOR32 | ILC_MASK,
-                                        1, 1);
-        if (m_ImageList == NULL)
-            return FALSE;
+        SetFont(m_Font, FALSE);
+    }
 
-        int s = ImageList_ReplaceIcon(m_ImageList, -1, hIconStart);
-        if (s < 0)
-        {
-            /* Failed to add the icon! */
-            ImageList_Destroy(m_ImageList);
-            m_ImageList = NULL;
+    VOID Initialize()
+    {
+        SubclassWindow(m_hWnd);
+        SetWindowTheme(m_hWnd, L"Start", NULL);
 
-            return FALSE;
-        }
+        m_ImageList = ImageList_LoadImageW(hExplorerInstance,
+                                           MAKEINTRESOURCEW(IDB_START),
+                                           0, 0, 0,
+                                           IMAGE_BITMAP,
+                                           LR_LOADTRANSPARENT | LR_CREATEDIBSECTION);
 
-        return TRUE;
+        BUTTON_IMAGELIST bil = {m_ImageList, {1,1,1,1}, BUTTON_IMAGELIST_ALIGN_LEFT};
+        SendMessageW(BCM_SETIMAGELIST, 0, (LPARAM) &bil);
+        UpdateSize();
     }
 
-    HBITMAP CreateBitmap()
+    HWND Create(HWND hwndParent)
     {
         WCHAR szStartCaption[32];
-        HFONT hFontOld;
-        HDC hDC = NULL;
-        HDC hDCScreen = NULL;
-        SIZE Size, SmallIcon;
-        HBITMAP hbmpOld, hbmp = NULL;
-        HBITMAP hBitmap = NULL;
-        HICON hIconStart;
-        BOOL Ret;
-        UINT Flags;
-        RECT rcButton;
-
-        /* NOTE: this is the backwards compatibility code that is used if the
-        Common Controls Version 6.0 are not available! */
-
-        if (!LoadString(hExplorerInstance,
-            IDS_START,
-            szStartCaption,
-            sizeof(szStartCaption) / sizeof(szStartCaption[0])))
+        if (!LoadStringW(hExplorerInstance,
+                         IDS_START,
+                         szStartCaption,
+                         _countof(szStartCaption)))
         {
-            return NULL;
+            wcscpy(szStartCaption, L"Start");
         }
 
-        /* Load the start button icon */
-        SmallIcon.cx = GetSystemMetrics(SM_CXSMICON);
-        SmallIcon.cy = GetSystemMetrics(SM_CYSMICON);
-        hIconStart = (HICON) LoadImage(hExplorerInstance,
-                                       MAKEINTRESOURCE(IDI_START),
-                                       IMAGE_ICON,
-                                       SmallIcon.cx,
-                                       SmallIcon.cy,
-                                       LR_SHARED | LR_DEFAULTCOLOR);
-
-        hDCScreen = GetDC(NULL);
-        if (hDCScreen == NULL)
-            goto Cleanup;
-
-        hDC = CreateCompatibleDC(hDCScreen);
-        if (hDC == NULL)
-            goto Cleanup;
-
-        hFontOld = (HFONT) SelectObject(hDC, m_Font);
-
-        Ret = GetTextExtentPoint32(hDC,
-                                   szStartCaption,
-                                   _tcslen(szStartCaption),
-                                   &Size);
-
-        SelectObject(hDC, hFontOld);
-        if (!Ret)
-            goto Cleanup;
-
-        /* Make sure the height is at least the size of a caption icon. */
-        if (hIconStart != NULL)
-            Size.cx += SmallIcon.cx + 4;
-        Size.cy = max(Size.cy, SmallIcon.cy);
-
-        /* Create the bitmap */
-        hbmp = CreateCompatibleBitmap(hDCScreen,
-                                      Size.cx,
-                                      Size.cy);
-        if (hbmp == NULL)
-            goto Cleanup;
-
-        /* Caluclate the button rect */
-        rcButton.left = 0;
-        rcButton.top = 0;
-        rcButton.right = Size.cx;
-        rcButton.bottom = Size.cy;
+        DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | BS_PUSHBUTTON | BS_LEFT | BS_VCENTER;
 
-        /* Draw the button */
-        hbmpOld = (HBITMAP) SelectObject(hDC, hbmp);
-
-        Flags = DC_TEXT | DC_INBUTTON;
-        if (hIconStart != NULL)
-            Flags |= DC_ICON;
-
-        DrawCaptionTemp(NULL,
-                        hDC,
-                        &rcButton,
-                        m_Font,
-                        hIconStart,
-                        szStartCaption,
-                        Flags);
-
-        SelectObject(hDC, hbmpOld);
-
-        if (!Ret)
-            goto Cleanup;
-
-        /* We successfully created the bitmap! */
-        hBitmap = hbmp;
-        hbmp = NULL;
-
-Cleanup:
-        if (hDCScreen != NULL)
-        {
-            ReleaseDC(NULL, hDCScreen);
-        }
-
-        if (hbmp != NULL)
-            DeleteObject(hbmp);
+        m_hWnd = CreateWindowEx(
+            0,
+            WC_BUTTON,
+            szStartCaption,
+            dwStyle,
+            0, 0, 0, 0,
+            hwndParent,
+            (HMENU) IDC_STARTBTN,
+            hExplorerInstance,
+            NULL);
 
-        if (hDC != NULL)
-            DeleteDC(hDC);
+        if (m_hWnd)
+            Initialize();
 
-        return hBitmap;
+        return m_hWnd;
     }
 
-    VOID Initialize()
+    LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
-        NONCLIENTMETRICS ncm;
-
-        SetWindowTheme(m_hWnd, L"Start", NULL);
-
-        if (m_Font == NULL)
-        {
-            /* Get the system fonts, we use the caption font, always bold, though. */
-            ncm.cbSize = sizeof(ncm);
-            if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, FALSE))
-            {
-                ncm.lfCaptionFont.lfWeight = FW_BOLD;
-                m_Font = CreateFontIndirect(&ncm.lfCaptionFont);
-            }
-        }
-
-        SendMessage(WM_SETFONT, (WPARAM) m_Font, FALSE);
-
-        if (CreateImageList())
-        {
-            BUTTON_IMAGELIST bil;
-
-            /* Try to set the start button image. this requires the Common
-            Controls 6.0 to be present (XP and later) */
-            bil.himl = m_ImageList;
-            bil.margin.left = bil.margin.right = 1;
-            bil.margin.top = bil.margin.bottom = 1;
-            bil.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT;
-
-            if (SendMessageW(BCM_SETIMAGELIST, 0, (LPARAM) &bil))
-            {
-                /* We're using the image list, remove the BS_BITMAP style and
-                don't center it horizontally */
-                SetWindowStyle(m_hWnd, BS_BITMAP | BS_RIGHT, 0);
-
-                UpdateSize();
-                return;
-            }
-
-            /* Fall back to the deprecated method on older systems that don't
-            support Common Controls 6.0 */
-            ImageList_Destroy(m_ImageList);
-            m_ImageList = NULL;
-        }
+        if (uMsg == WM_KEYUP && wParam != VK_SPACE)
+            return 0;
 
-        HBITMAP hbmStart = CreateBitmap();
-        if (hbmStart != NULL)
-        {
-            UpdateSize(hbmStart);
+        GetParent().PostMessage(TWM_OPENSTARTMENU);
+        return 0;
+    }
 
-            HBITMAP hbmOld = (HBITMAP) SendMessageW(BM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbmStart);
+    BEGIN_MSG_MAP(CStartButton)
+        MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
+    END_MSG_MAP()
 
-            if (hbmOld != NULL)
-                DeleteObject(hbmOld);
-        }
-    }
 };
 
 class CTrayWindow :
@@ -354,16 +189,19 @@ class CTrayWindow :
     public CComObjectRootEx<CComMultiThreadModelNoCS>,
     public CWindowImpl < CTrayWindow, CWindow, CControlWinTraits >,
     public ITrayWindow,
-    public IShellDesktopTray
+    public IShellDesktopTray,
+    public IOleWindow,
+    public IContextMenu
 {
     CStartButton m_StartButton;
 
     CComPtr<IMenuBand>  m_StartMenuBand;
     CComPtr<IMenuPopup> m_StartMenuPopup;
 
+    CComPtr<IDeskBand> m_TaskBand;
+    CComPtr<IContextMenu> m_ContextMenu;
     HTHEME m_Theme;
 
-    HFONT m_CaptionFont;
     HFONT m_Font;
 
     HWND m_DesktopWnd;
@@ -414,9 +252,8 @@ public:
 
 public:
     CTrayWindow() :
-        m_StartButton(this, 1),
+        m_StartButton(),
         m_Theme(NULL),
-        m_CaptionFont(NULL),
         m_Font(NULL),
         m_DesktopWnd(NULL),
         m_Rebar(NULL),
@@ -447,12 +284,6 @@ public:
             m_ShellServices = NULL;
         }
 
-        if (m_CaptionFont != NULL)
-        {
-            DeleteObject(m_CaptionFont);
-            m_CaptionFont = NULL;
-        }
-
         if (m_Font != NULL)
         {
             DeleteObject(m_Font);
@@ -465,1706 +296,1978 @@ public:
             m_Theme = NULL;
         }
 
-        if (InterlockedDecrement(&TrayWndCount) == 0)
-            PostQuitMessage(0);
+        PostQuitMessage(0);
     }
 
-    /*
-     * ITrayWindow
-     */
 
-    BOOL UpdateNonClientMetrics()
-    {
-        NONCLIENTMETRICS ncm;
-        ncm.cbSize = sizeof(ncm);
-        if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
-        {
-            if (m_Font != NULL)
-                DeleteObject(m_Font);
 
-            m_Font = CreateFontIndirect(&ncm.lfMessageFont);
-            return TRUE;
-        }
 
-        return FALSE;
-    }
 
-    VOID SetWindowsFont()
-    {
-        if (m_TrayNotify != NULL)
-        {
-            SendMessage(m_TrayNotify, WM_SETFONT, (WPARAM) m_Font, TRUE);
-        }
-    }
+    /**********************************************************
+     *    ##### command handling #####
+     */
 
-    HMONITOR GetScreenRectFromRect(
-        IN OUT RECT *pRect,
-        IN DWORD dwFlags)
+    HRESULT ExecResourceCmd(int id)
     {
-        MONITORINFO mi;
-        HMONITOR hMon;
+        WCHAR szCommand[256];
+        WCHAR *pszParameters;
 
-        mi.cbSize = sizeof(mi);
-        hMon = MonitorFromRect(pRect,
-                               dwFlags);
-        if (hMon != NULL &&
-            GetMonitorInfo(hMon,
-            &mi))
+        if (!LoadStringW(hExplorerInstance,
+                         id,
+                         szCommand,
+                         _countof(szCommand)))
         {
-            *pRect = mi.rcMonitor;
+            return E_FAIL;
         }
-        else
-        {
-            pRect->left = 0;
-            pRect->top = 0;
-            pRect->right = GetSystemMetrics(SM_CXSCREEN);
-            pRect->bottom = GetSystemMetrics(SM_CYSCREEN);
 
-            hMon = NULL;
+        pszParameters = wcschr(szCommand, L'>');
+        if (pszParameters)
+        {
+            *pszParameters = 0;
+            pszParameters++;
         }
 
-        return hMon;
+        ShellExecuteW(m_hWnd, NULL, szCommand, pszParameters, NULL, SW_SHOWNORMAL);
+        return S_OK;
     }
 
-    HMONITOR GetMonitorFromRect(
-        IN const RECT *pRect)
+    LRESULT DoExitWindows()
     {
-        HMONITOR hMon;
+        ExitWindowsDialog(m_hWnd);
+        return 0;
+    }
 
-        /* In case the monitor sizes or saved sizes differ a bit (probably
-           not a lot, only so the tray window overlaps into another monitor
-           now), minimize the risk that we determine a wrong monitor by
-           using the center point of the tray window if we can't determine
-           it using the rectangle. */
-        hMon = MonitorFromRect(pRect,
-                               MONITOR_DEFAULTTONULL);
-        if (hMon == NULL)
-        {
-            POINT pt;
+    DWORD WINAPI RunFileDlgThread()
+    {
+        HWND hwnd;
+        RECT posRect;
 
-            pt.x = pRect->left + ((pRect->right - pRect->left) / 2);
-            pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2);
+        m_StartButton.GetWindowRect(&posRect);
 
-            /* be less error-prone, find the nearest monitor */
-            hMon = MonitorFromPoint(pt,
-                                    MONITOR_DEFAULTTONEAREST);
-        }
+        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);
 
-        return hMon;
+        m_RunFileDlgOwner = hwnd;
+
+        RunFileDlg(hwnd, NULL, NULL, NULL, NULL, RFF_CALCDIRECTORY);
+
+        m_RunFileDlgOwner = NULL;
+        ::DestroyWindow(hwnd);
+
+        return 0;
     }
 
-    HMONITOR GetScreenRect(
-        IN HMONITOR hMonitor,
-        IN OUT RECT *pRect)
+    static DWORD WINAPI s_RunFileDlgThread(IN OUT PVOID pParam)
     {
-        HMONITOR hMon = NULL;
+        CTrayWindow * This = (CTrayWindow*) pParam;
+        return This->RunFileDlgThread();
+    }
 
-        if (hMonitor != NULL)
+    void DisplayRunFileDlg()
+    {
+        HWND hRunDlg;
+        if (m_RunFileDlgOwner)
         {
-            MONITORINFO mi;
-
-            mi.cbSize = sizeof(mi);
-            if (!GetMonitorInfo(hMonitor,
-                &mi))
+            hRunDlg = ::GetLastActivePopup(m_RunFileDlgOwner);
+            if (hRunDlg != NULL &&
+                hRunDlg != m_RunFileDlgOwner)
             {
-                /* Hm, the monitor is gone? Try to find a monitor where it
-                   could be located now */
-                hMon = GetMonitorFromRect(
-                    pRect);
-                if (hMon == NULL ||
-                    !GetMonitorInfo(hMon,
-                    &mi))
-                {
-                    hMon = NULL;
-                    goto GetPrimaryRect;
-                }
+                SetForegroundWindow(hRunDlg);
+                return;
             }
-
-            *pRect = mi.rcMonitor;
-        }
-        else
-        {
-GetPrimaryRect:
-            pRect->left = 0;
-            pRect->top = 0;
-            pRect->right = GetSystemMetrics(SM_CXSCREEN);
-            pRect->bottom = GetSystemMetrics(SM_CYSCREEN);
         }
 
-        return hMon;
+        CloseHandle(CreateThread(NULL, 0, s_RunFileDlgThread, this, 0, NULL));
     }
 
-    VOID MakeTrayRectWithSize(IN DWORD Position,
-                              IN const SIZE *pTraySize,
-                              IN OUT RECT *pRect)
+    DWORD WINAPI TrayPropertiesThread()
     {
-        switch (Position)
-        {
-        case ABE_LEFT:
-            pRect->right = pRect->left + pTraySize->cx;
-            break;
+        HWND hwnd;
+        RECT posRect;
 
-        case ABE_TOP:
-            pRect->bottom = pRect->top + pTraySize->cy;
-            break;
+        m_StartButton.GetWindowRect(&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);
 
-        case ABE_RIGHT:
-            pRect->left = pRect->right - pTraySize->cx;
-            break;
+        m_TrayPropertiesOwner = hwnd;
 
-        case ABE_BOTTOM:
-        default:
-            pRect->top = pRect->bottom - pTraySize->cy;
-            break;
-        }
+        DisplayTrayProperties(hwnd);
+
+        m_TrayPropertiesOwner = NULL;
+        ::DestroyWindow(hwnd);
+
+        return 0;
     }
 
-    VOID GetTrayRectFromScreenRect(IN DWORD Position,
-                                   IN const RECT *pScreen,
-                                   IN const SIZE *pTraySize OPTIONAL,
-                                   OUT RECT *pRect)
+    static DWORD WINAPI s_TrayPropertiesThread(IN OUT PVOID pParam)
     {
-        if (pTraySize == NULL)
-            pTraySize = &m_TraySize;
-
-        *pRect = *pScreen;
-
-        /* Move the border outside of the screen */
-        InflateRect(pRect,
-                    GetSystemMetrics(SM_CXEDGE),
-                    GetSystemMetrics(SM_CYEDGE));
+        CTrayWindow *This = (CTrayWindow*) pParam;
 
-        MakeTrayRectWithSize(Position, pTraySize, pRect);
+        return This->TrayPropertiesThread();
     }
 
-    BOOL IsPosHorizontal()
+    HWND STDMETHODCALLTYPE DisplayProperties()
     {
-        return m_Position == ABE_TOP || m_Position == ABE_BOTTOM;
+        HWND hTrayProp;
+
+        if (m_TrayPropertiesOwner)
+        {
+            hTrayProp = ::GetLastActivePopup(m_TrayPropertiesOwner);
+            if (hTrayProp != NULL &&
+                hTrayProp != m_TrayPropertiesOwner)
+            {
+                SetForegroundWindow(hTrayProp);
+                return NULL;
+            }
+        }
+
+        CloseHandle(CreateThread(NULL, 0, s_TrayPropertiesThread, this, 0, NULL));
+        return NULL;
     }
 
-    HMONITOR CalculateValidSize(
-        IN DWORD Position,
-        IN OUT RECT *pRect)
+    VOID OpenCommonStartMenuDirectory(IN HWND hWndOwner, IN LPCTSTR lpOperation)
     {
-        RECT rcScreen;
-        //BOOL Horizontal;
-        HMONITOR hMon;
-        SIZE szMax, szWnd;
-
-        //Horizontal = IsPosHorizontal();
+        WCHAR szDir[MAX_PATH];
 
-        szWnd.cx = pRect->right - pRect->left;
-        szWnd.cy = pRect->bottom - pRect->top;
+        if (SHGetSpecialFolderPath(hWndOwner,
+            szDir,
+            CSIDL_COMMON_STARTMENU,
+            FALSE))
+        {
+            ShellExecute(hWndOwner,
+                         lpOperation,
+                         szDir,
+                         NULL,
+                         NULL,
+                         SW_SHOWNORMAL);
+        }
+    }
 
-        rcScreen = *pRect;
-        hMon = GetScreenRectFromRect(
-            &rcScreen,
-            MONITOR_DEFAULTTONEAREST);
+    VOID OpenTaskManager(IN HWND hWndOwner)
+    {
+        ShellExecute(hWndOwner,
+                     TEXT("open"),
+                     TEXT("taskmgr.exe"),
+                     NULL,
+                     NULL,
+                     SW_SHOWNORMAL);
+    }
 
-        /* Calculate the maximum size of the tray window and limit the window
-           size to half of the screen's size. */
-        szMax.cx = (rcScreen.right - rcScreen.left) / 2;
-        szMax.cy = (rcScreen.bottom - rcScreen.top) / 2;
-        if (szWnd.cx > szMax.cx)
-            szWnd.cx = szMax.cx;
-        if (szWnd.cy > szMax.cy)
-            szWnd.cy = szMax.cy;
+    BOOL STDMETHODCALLTYPE ExecContextMenuCmd(IN UINT uiCmd)
+    {
+        switch (uiCmd)
+        {
+        case ID_SHELL_CMD_PROPERTIES:
+            DisplayProperties();
+            break;
 
-        /* FIXME - calculate */
+        case ID_SHELL_CMD_OPEN_ALL_USERS:
+            OpenCommonStartMenuDirectory(m_hWnd,
+                                         TEXT("open"));
+            break;
 
-        GetTrayRectFromScreenRect(
-            Position,
-            &rcScreen,
-            &szWnd,
-            pRect);
+        case ID_SHELL_CMD_EXPLORE_ALL_USERS:
+            OpenCommonStartMenuDirectory(m_hWnd,
+                                         TEXT("explore"));
+            break;
 
-        return hMon;
-    }
+        case ID_LOCKTASKBAR:
+            if (SHRestricted(REST_CLASSICSHELL) == 0)
+            {
+                Lock(!Locked);
+            }
+            break;
 
-#if 0
-    VOID
-        GetMinimumWindowSize(
-        OUT RECT *pRect)
-    {
-        RECT rcMin = {0};
+        case ID_SHELL_CMD_OPEN_TASKMGR:
+            OpenTaskManager(m_hWnd);
+            break;
 
-        AdjustWindowRectEx(&rcMin,
-                           GetWindowLong(m_hWnd,
-                           GWL_STYLE),
-                           FALSE,
-                           GetWindowLong(m_hWnd,
-                           GWL_EXSTYLE));
+        case ID_SHELL_CMD_UNDO_ACTION:
+            break;
 
-        *pRect = rcMin;
-    }
-#endif
+        case ID_SHELL_CMD_SHOW_DESKTOP:
+            break;
 
+        case ID_SHELL_CMD_TILE_WND_H:
+            TileWindows(NULL, MDITILE_HORIZONTAL, NULL, 0, NULL);
+            break;
 
-    DWORD GetDraggingRectFromPt(
-        IN POINT pt,
-        OUT RECT *pRect,
-        OUT HMONITOR *phMonitor)
-    {
-        HMONITOR hMon, hMonNew;
-        DWORD PosH, PosV, Pos;
-        SIZE DeltaPt, ScreenOffset;
-        RECT rcScreen;
+        case ID_SHELL_CMD_TILE_WND_V:
+            TileWindows(NULL, MDITILE_VERTICAL, NULL, 0, NULL);
+            break;
 
-        rcScreen.left = 0;
-        rcScreen.top = 0;
+        case ID_SHELL_CMD_CASCADE_WND:
+            CascadeWindows(NULL, MDITILE_SKIPDISABLED, NULL, 0, NULL);
+            break;
 
-        /* Determine the screen rectangle */
-        hMon = MonitorFromPoint(pt,
-                                MONITOR_DEFAULTTONULL);
+        case ID_SHELL_CMD_CUST_NOTIF:
+            ShowCustomizeNotifyIcons(hExplorerInstance, m_hWnd);
+            break;
 
-        if (hMon != NULL)
-        {
-            MONITORINFO mi;
+        case ID_SHELL_CMD_ADJUST_DAT:
+            //FIXME: Use SHRunControlPanel
+            ShellExecuteW(m_hWnd, NULL, L"timedate.cpl", NULL, NULL, SW_NORMAL);
+            break;
 
-            mi.cbSize = sizeof(mi);
-            if (!GetMonitorInfo(hMon,
-                &mi))
-            {
-                hMon = NULL;
-                goto GetPrimaryScreenRect;
-            }
+        default:
+            TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd);
+            return FALSE;
+        }
 
-            /* make left top corner of the screen zero based to
-               make calculations easier */
-            pt.x -= mi.rcMonitor.left;
-            pt.y -= mi.rcMonitor.top;
+        return TRUE;
+    }
 
-            ScreenOffset.cx = mi.rcMonitor.left;
-            ScreenOffset.cy = mi.rcMonitor.top;
-            rcScreen.right = mi.rcMonitor.right - mi.rcMonitor.left;
-            rcScreen.bottom = mi.rcMonitor.bottom - mi.rcMonitor.top;
-        }
-        else
+    LRESULT HandleHotKey(DWORD id)
+    {
+        switch (id)
         {
-GetPrimaryScreenRect:
-            ScreenOffset.cx = 0;
-            ScreenOffset.cy = 0;
-            rcScreen.right = GetSystemMetrics(SM_CXSCREEN);
-            rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN);
+        case IDHK_RUN:
+            DisplayRunFileDlg();
+            break;
+        case IDHK_HELP:
+            ExecResourceCmd(IDS_HELP_COMMAND);
+            break;
+        case IDHK_EXPLORE:
+            //FIXME: We don't support this yet:
+            //ShellExecuteW(0, L"explore", NULL, NULL, NULL, 1);
+            ShellExecuteW(0, NULL, L"explorer.exe", NULL, NULL, 1); 
+            break;
+        case IDHK_FIND:
+            SHFindFiles(NULL, NULL);
+            break;
+        case IDHK_FIND_COMPUTER:
+            SHFindComputer(NULL, NULL);
+            break;
+        case IDHK_SYS_PROPERTIES:
+            //FIXME: Use SHRunControlPanel
+            ShellExecuteW(m_hWnd, NULL, L"sysdm.cpl", NULL, NULL, SW_NORMAL);
+            break;
+        case IDHK_NEXT_TASK:
+            break;
+        case IDHK_PREV_TASK:
+            break;
+        case IDHK_MINIMIZE_ALL:
+            break;
+        case IDHK_RESTORE_ALL:
+            break;
+        case IDHK_DESKTOP:
+            break;
+        case IDHK_PAGER:
+            break;
         }
 
-        /* Calculate the nearest screen border */
-        if (pt.x < rcScreen.right / 2)
-        {
-            DeltaPt.cx = pt.x;
-            PosH = ABE_LEFT;
-        }
-        else
-        {
-            DeltaPt.cx = rcScreen.right - pt.x;
-            PosH = ABE_RIGHT;
-        }
+        return 0;
+    }
 
-        if (pt.y < rcScreen.bottom / 2)
-        {
-            DeltaPt.cy = pt.y;
-            PosV = ABE_TOP;
-        }
-        else
+    LRESULT HandleCommand(UINT uCommand)
+    {
+        switch (uCommand)
         {
-            DeltaPt.cy = rcScreen.bottom - pt.y;
-            PosV = ABE_BOTTOM;
-        }
+        case IDM_TASKBARANDSTARTMENU:
+            DisplayProperties();
+            break;
 
-        Pos = (DeltaPt.cx * rcScreen.bottom < DeltaPt.cy * rcScreen.right) ? PosH : PosV;
+        case IDM_SEARCH:
+            SHFindFiles(NULL, NULL);
+            break;
 
-        /* Fix the screen origin to be relative to the primary monitor again */
-        OffsetRect(&rcScreen,
-                   ScreenOffset.cx,
-                   ScreenOffset.cy);
+        case IDM_HELPANDSUPPORT:
+            ExecResourceCmd(IDS_HELP_COMMAND);
+            break;
 
-        RECT rcPos = m_TrayRects[Pos];
+        case IDM_RUN:
+            DisplayRunFileDlg();
+            break;
 
-        hMonNew = GetMonitorFromRect(&rcPos);
-        if (hMon != hMonNew)
-        {
-            SIZE szTray;
+        /* FIXME: Handle these commands as well */
+        case IDM_SYNCHRONIZE:
+        case IDM_DISCONNECT:
+        case IDM_UNDOCKCOMPUTER:
+            break;
 
-            /* Recalculate the rectangle, we're dragging to another monitor.
-               We don't need to recalculate the rect on single monitor systems. */
-            szTray.cx = rcPos.right - rcPos.left;
-            szTray.cy = rcPos.bottom - rcPos.top;
+        case IDM_LOGOFF:
+            LogoffWindowsDialog(m_hWnd); // FIXME: Maybe handle it in a similar way as DoExitWindows?
+            break;
 
-            GetTrayRectFromScreenRect(Pos, &rcScreen, &szTray, pRect);
-            if (AutoHide)
-            {
-                pRect->left += m_AutoHideOffset.cx;
-                pRect->right += m_AutoHideOffset.cx;
-                pRect->top += m_AutoHideOffset.cy;
-                pRect->bottom += m_AutoHideOffset.cy;
-            }
-            hMon = hMonNew;
-        }
-        else
-        {
-            /* The user is dragging the tray window on the same monitor. We don't need
-               to recalculate the rectangle */
-            *pRect = rcPos;
-            if (AutoHide)
-            {
-                pRect->left += m_AutoHideOffset.cx;
-                pRect->right += m_AutoHideOffset.cx;
-                pRect->top += m_AutoHideOffset.cy;
-                pRect->bottom += m_AutoHideOffset.cy;
-            }
+        case IDM_SHUTDOWN:
+            DoExitWindows();
+            break;
         }
 
-        *phMonitor = hMon;
-
-        return Pos;
+        return FALSE;
     }
 
-    DWORD GetDraggingRectFromRect(
-        IN OUT RECT *pRect,
-        OUT HMONITOR *phMonitor)
-    {
-        POINT pt;
-
-        /* Calculate the center of the rectangle. We call
-           GetDraggingRectFromPt to calculate a valid
-           dragging rectangle */
-        pt.x = pRect->left + ((pRect->right - pRect->left) / 2);
-        pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2);
-
-        return GetDraggingRectFromPt(
-            pt,
-            pRect,
-            phMonitor);
-    }
 
-    VOID ChangingWinPos(IN OUT LPWINDOWPOS pwp)
+    UINT TrackMenu(
+        IN HMENU hMenu,
+        IN POINT *ppt OPTIONAL,
+        IN HWND hwndExclude OPTIONAL,
+        IN BOOL TrackUp,
+        IN BOOL IsContextMenu)
     {
-        RECT rcTray;
+        TPMPARAMS tmp, *ptmp = NULL;
+        POINT pt;
+        UINT cmdId;
+        UINT fuFlags;
 
-        if (IsDragging)
+        if (hwndExclude != NULL)
         {
-            rcTray.left = pwp->x;
-            rcTray.top = pwp->y;
-            rcTray.right = rcTray.left + pwp->cx;
-            rcTray.bottom = rcTray.top + pwp->cy;
-            if (AutoHide)
+            /* Get the client rectangle and map it to screen coordinates */
+            if (::GetClientRect(hwndExclude,
+                &tmp.rcExclude) &&
+                ::MapWindowPoints(hwndExclude,
+                NULL,
+                (LPPOINT) &tmp.rcExclude,
+                2) != 0)
             {
-                rcTray.left -= m_AutoHideOffset.cx;
-                rcTray.right -= m_AutoHideOffset.cx;
-                rcTray.top -= m_AutoHideOffset.cy;
-                rcTray.bottom -= m_AutoHideOffset.cy;
+                ptmp = &tmp;
             }
+        }
 
-            if (!EqualRect(&rcTray,
-                &m_TrayRects[m_DraggingPosition]))
+        if (ppt == NULL)
+        {
+            if (ptmp == NULL &&
+                GetClientRect(&tmp.rcExclude) &&
+                MapWindowPoints(
+                NULL,
+                (LPPOINT) &tmp.rcExclude,
+                2) != 0)
             {
-                /* Recalculate the rectangle, the user dragged the tray
-                   window to another monitor or the window was somehow else
-                   moved or resized */
-                m_DraggingPosition = GetDraggingRectFromRect(
-                    &rcTray,
-                    &m_DraggingMonitor);
-                //m_TrayRects[DraggingPosition] = rcTray;
+                ptmp = &tmp;
             }
 
-            //Monitor = CalculateValidSize(
-            //                                                   DraggingPosition,
-            //                                                   &rcTray);
-
-            m_Monitor = m_DraggingMonitor;
-            m_Position = m_DraggingPosition;
-            IsDragging = FALSE;
-
-            m_TrayRects[m_Position] = rcTray;
-            goto ChangePos;
-        }
-        else if (GetWindowRect(m_hWnd, &rcTray))
-        {
-            if (InSizeMove)
+            if (ptmp != NULL)
             {
-                if (!(pwp->flags & SWP_NOMOVE))
-                {
-                    rcTray.left = pwp->x;
-                    rcTray.top = pwp->y;
-                }
-
-                if (!(pwp->flags & SWP_NOSIZE))
-                {
-                    rcTray.right = rcTray.left + pwp->cx;
-                    rcTray.bottom = rcTray.top + pwp->cy;
-                }
-
-                m_Position = GetDraggingRectFromRect(&rcTray, &m_Monitor);
+                /* NOTE: TrackPopupMenuEx will eventually align the track position
+                         for us, no need to take care of it here as long as the
+                         coordinates are somewhere within the exclusion rectangle */
+                pt.x = ptmp->rcExclude.left;
+                pt.y = ptmp->rcExclude.top;
+            }
+            else
+                pt.x = pt.y = 0;
+        }
+        else
+            pt = *ppt;
 
-                if (!(pwp->flags & (SWP_NOMOVE | SWP_NOSIZE)))
-                {
-                    SIZE szWnd;
+        tmp.cbSize = sizeof(tmp);
 
-                    szWnd.cx = pwp->cx;
-                    szWnd.cy = pwp->cy;
+        fuFlags = TPM_RETURNCMD | TPM_VERTICAL;
+        fuFlags |= (TrackUp ? TPM_BOTTOMALIGN : TPM_TOPALIGN);
+        if (IsContextMenu)
+            fuFlags |= TPM_RIGHTBUTTON;
+        else
+            fuFlags |= (TrackUp ? TPM_VERNEGANIMATION : TPM_VERPOSANIMATION);
 
-                    MakeTrayRectWithSize(m_Position, &szWnd, &rcTray);
-                }
+        cmdId = TrackPopupMenuEx(hMenu,
+                                 fuFlags,
+                                 pt.x,
+                                 pt.y,
+                                 m_hWnd,
+                                 ptmp);
 
-                if (AutoHide)
-                {
-                    rcTray.left -= m_AutoHideOffset.cx;
-                    rcTray.right -= m_AutoHideOffset.cx;
-                    rcTray.top -= m_AutoHideOffset.cy;
-                    rcTray.bottom -= m_AutoHideOffset.cy;
-                }
-                m_TrayRects[m_Position] = rcTray;
-            }
-            else
-            {
-                /* If the user isn't resizing the tray window we need to make sure the
-                   new size or position is valid. this is to prevent changes to the window
-                   without user interaction. */
-                rcTray = m_TrayRects[m_Position];
-            }
+        return cmdId;
+    }
 
-ChangePos:
-            m_TraySize.cx = rcTray.right - rcTray.left;
-            m_TraySize.cy = rcTray.bottom - rcTray.top;
+    HRESULT TrackCtxMenu(
+        IN IContextMenu * contextMenu,
+        IN POINT *ppt OPTIONAL,
+        IN HWND hwndExclude OPTIONAL,
+        IN BOOL TrackUp,
+        IN PVOID Context OPTIONAL)
+    {
+        INT x = ppt->x;
+        INT y = ppt->y;
+        HRESULT hr;
+        UINT uCommand;
+        HMENU popup = CreatePopupMenu();
 
-            if (AutoHide)
-            {
-                rcTray.left += m_AutoHideOffset.cx;
-                rcTray.right += m_AutoHideOffset.cx;
-                rcTray.top += m_AutoHideOffset.cy;
-                rcTray.bottom += m_AutoHideOffset.cy;
-            }
+        if (popup == NULL)
+            return E_FAIL;
 
-            pwp->flags &= ~(SWP_NOMOVE | SWP_NOSIZE);
-            pwp->x = rcTray.left;
-            pwp->y = rcTray.top;
-            pwp->cx = m_TraySize.cx;
-            pwp->cy = m_TraySize.cy;
+        TRACE("Before Query\n");
+        hr = contextMenu->QueryContextMenu(popup, 0, 0, UINT_MAX, CMF_NORMAL);
+        if (FAILED_UNEXPECTEDLY(hr))
+        {
+            TRACE("Query failed\n");
+            DestroyMenu(popup);
+            return hr;
         }
-    }
 
-    VOID ApplyClipping(IN BOOL Clip)
-    {
-        RECT rcClip, rcWindow;
-        HRGN hClipRgn;
+        TRACE("Before Tracking\n");
+        uCommand = ::TrackPopupMenuEx(popup, TPM_RETURNCMD, x, y, m_hWnd, NULL);
 
-        if (GetWindowRect(m_hWnd, &rcWindow))
+        if (uCommand != 0)
         {
-            /* Disable clipping on systems with only one monitor */
-            if (GetSystemMetrics(SM_CMONITORS) <= 1)
-                Clip = FALSE;
+            TRACE("Before InvokeCommand\n");
+            CMINVOKECOMMANDINFO cmi = { 0 };
+            cmi.cbSize = sizeof(cmi);
+            cmi.lpVerb = MAKEINTRESOURCEA(uCommand);
+            cmi.hwnd = m_hWnd;
+            hr = contextMenu->InvokeCommand(&cmi);
+        }
+        else
+        {
+            TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand, GetLastError());
+            hr = S_FALSE;
+        }
 
-            if (Clip)
-            {
-                rcClip = rcWindow;
+        DestroyMenu(popup);
+        return hr;
+    }
 
-                GetScreenRect(m_Monitor, &rcClip);
 
-                if (!IntersectRect(&rcClip, &rcClip, &rcWindow))
-                {
-                    rcClip = rcWindow;
-                }
 
-                OffsetRect(&rcClip,
-                           -rcWindow.left,
-                           -rcWindow.top);
 
-                hClipRgn = CreateRectRgnIndirect(&rcClip);
-            }
-            else
-                hClipRgn = NULL;
 
-            /* Set the clipping region or make sure the window isn't clipped
-               by disabling it explicitly. */
-            SetWindowRgn(m_hWnd, hClipRgn, TRUE);
-        }
-    }
+    /**********************************************************
+     *    ##### moving and sizing handling #####
+     */
 
-    VOID ResizeWorkArea()
+    void UpdateFonts()
     {
-#if !WIN7_COMPAT_MODE
-        RECT rcTray, rcWorkArea;
+        /* There is nothing to do if themes are not enabled */
+        if (m_Theme)
+            return;
 
-        /* If monitor has changed then fix the previous monitors work area */
-        if (m_PreviousMonitor != m_Monitor)
+        m_StartButton.UpdateFont();
+
+        NONCLIENTMETRICS ncm = {sizeof(ncm)};
+        if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, FALSE))
         {
-            GetScreenRect(m_PreviousMonitor, &rcWorkArea);
-            SystemParametersInfo(SPI_SETWORKAREA,
-                                 1,
-                                 &rcWorkArea,
-                                 SPIF_SENDCHANGE);
+            ERR("SPI_GETNONCLIENTMETRICS failed\n");
+            return;
         }
 
-        rcTray = m_TrayRects[m_Position];
-
-        GetScreenRect(m_Monitor, &rcWorkArea);
-        m_PreviousMonitor = m_Monitor;
+        if (m_Font != NULL)
+            DeleteObject(m_Font);
 
-        /* If AutoHide is false then change the workarea to exclude the area that
-           the taskbar covers. */
-        if (!AutoHide)
+        ncm.lfCaptionFont.lfWeight = FW_NORMAL;
+        m_Font = CreateFontIndirect(&ncm.lfCaptionFont);
+        if (!m_Font)
         {
-            switch (m_Position)
-            {
-            case ABE_TOP:
-                rcWorkArea.top = rcTray.bottom;
-                break;
-            case ABE_LEFT:
-                rcWorkArea.left = rcTray.right;
-                break;
-            case ABE_RIGHT:
-                rcWorkArea.right = rcTray.left;
-                break;
-            case ABE_BOTTOM:
-                rcWorkArea.bottom = rcTray.top;
-                break;
-            }
+            ERR("CreateFontIndirect failed\n");
+            return;
         }
 
-        SystemParametersInfo(SPI_SETWORKAREA,
-                             1,
-                             &rcWorkArea,
-                             SPIF_SENDCHANGE);
-#endif
+        SendMessage(m_Rebar, WM_SETFONT, (WPARAM) m_Font, TRUE);
+        SendMessage(m_TaskSwitch, WM_SETFONT, (WPARAM) m_Font, TRUE);
+        SendMessage(m_TrayNotify, WM_SETFONT, (WPARAM) m_Font, TRUE);
     }
 
-    VOID CheckTrayWndPosition()
+    HMONITOR GetScreenRectFromRect(
+        IN OUT RECT *pRect,
+        IN DWORD dwFlags)
     {
-        RECT rcTray;
-
-        rcTray = m_TrayRects[m_Position];
+        MONITORINFO mi;
+        HMONITOR hMon;
 
-        if (AutoHide)
+        mi.cbSize = sizeof(mi);
+        hMon = MonitorFromRect(pRect, dwFlags);
+        if (hMon != NULL &&
+            GetMonitorInfo(hMon, &mi))
         {
-            rcTray.left += m_AutoHideOffset.cx;
-            rcTray.right += m_AutoHideOffset.cx;
-            rcTray.top += m_AutoHideOffset.cy;
-            rcTray.bottom += m_AutoHideOffset.cy;
+            *pRect = mi.rcMonitor;
         }
+        else
+        {
+            pRect->left = 0;
+            pRect->top = 0;
+            pRect->right = GetSystemMetrics(SM_CXSCREEN);
+            pRect->bottom = GetSystemMetrics(SM_CYSCREEN);
 
-        /* Move the tray window */
-        SetWindowPos(NULL,
-                     rcTray.left,
-                     rcTray.top,
-                     rcTray.right - rcTray.left,
-                     rcTray.bottom - rcTray.top,
-                     SWP_NOZORDER);
-
-        ResizeWorkArea();
+            hMon = NULL;
+        }
 
-        ApplyClipping(TRUE);
+        return hMon;
     }
 
-    typedef struct _TW_STUCKRECTS2
+    HMONITOR GetMonitorFromRect(
+        IN const RECT *pRect)
     {
-        DWORD cbSize;
-        LONG Unknown;
-        DWORD dwFlags;
-        DWORD Position;
-        SIZE Size;
-        RECT Rect;
-    } TW_STRUCKRECTS2, *PTW_STUCKRECTS2;
+        HMONITOR hMon;
 
-    VOID RegLoadSettings()
-    {
-        DWORD Pos;
-        TW_STRUCKRECTS2 sr;
-        RECT rcScreen;
-        SIZE WndSize, EdgeSize, DlgFrameSize;
-        DWORD cbSize = sizeof(sr);
-        SIZE StartBtnSize = m_StartButton.GetSize();
+        /* In case the monitor sizes or saved sizes differ a bit (probably
+           not a lot, only so the tray window overlaps into another monitor
+           now), minimize the risk that we determine a wrong monitor by
+           using the center point of the tray window if we can't determine
+           it using the rectangle. */
+        hMon = MonitorFromRect(pRect, MONITOR_DEFAULTTONULL);
+        if (hMon == NULL)
+        {
+            POINT pt;
 
-        EdgeSize.cx = GetSystemMetrics(SM_CXEDGE);
-        EdgeSize.cy = GetSystemMetrics(SM_CYEDGE);
-        DlgFrameSize.cx = GetSystemMetrics(SM_CXDLGFRAME);
-        DlgFrameSize.cy = GetSystemMetrics(SM_CYDLGFRAME);
+            pt.x = pRect->left + ((pRect->right - pRect->left) / 2);
+            pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2);
 
-        if (SHGetValue(hkExplorer,
-            TEXT("StuckRects2"),
-            TEXT("Settings"),
-            NULL,
-            &sr,
-            &cbSize) == ERROR_SUCCESS &&
-            sr.cbSize == sizeof(sr))
-        {
-            AutoHide = (sr.dwFlags & ABS_AUTOHIDE) != 0;
-            AlwaysOnTop = (sr.dwFlags & ABS_ALWAYSONTOP) != 0;
-            SmSmallIcons = (sr.dwFlags & 0x4) != 0;
-            HideClock = (sr.dwFlags & 0x8) != 0;
+            /* be less error-prone, find the nearest monitor */
+            hMon = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
+        }
 
-            /* FIXME: Are there more flags? */
+        return hMon;
+    }
 
-#if WIN7_COMPAT_MODE
-            m_Position = ABE_LEFT;
-#else
-            if (sr.Position > ABE_BOTTOM)
-                m_Position = ABE_BOTTOM;
-            else
-                m_Position = sr.Position;
-#endif
+    HMONITOR GetScreenRect(
+        IN HMONITOR hMonitor,
+        IN OUT RECT *pRect)
+    {
+        HMONITOR hMon = NULL;
 
-            /* Try to find out which monitor the tray window was located on last.
-               Here we're only interested in the monitor screen that we think
-               is the last one used. We're going to determine on which monitor
-               we really are after calculating the docked position. */
-            rcScreen = sr.Rect;
-            GetScreenRectFromRect(
-                &rcScreen,
-                MONITOR_DEFAULTTONEAREST);
+        if (hMonitor != NULL)
+        {
+            MONITORINFO mi;
+
+            mi.cbSize = sizeof(mi);
+            if (!GetMonitorInfo(hMonitor, &mi))
+            {
+                /* Hm, the monitor is gone? Try to find a monitor where it
+                   could be located now */
+                hMon = GetMonitorFromRect(pRect);
+                if (hMon == NULL ||
+                    !GetMonitorInfo(hMon, &mi))
+                {
+                    hMon = NULL;
+                    goto GetPrimaryRect;
+                }
+            }
+
+            *pRect = mi.rcMonitor;
         }
         else
         {
-            m_Position = ABE_BOTTOM;
-            AlwaysOnTop = TRUE;
+GetPrimaryRect:
+            pRect->left = 0;
+            pRect->top = 0;
+            pRect->right = GetSystemMetrics(SM_CXSCREEN);
+            pRect->bottom = GetSystemMetrics(SM_CYSCREEN);
+        }
 
-            /* Use the minimum size of the taskbar, we'll use the start
-               button as a minimum for now. Make sure we calculate the
-               entire window size, not just the client size. However, we
-               use a thinner border than a standard thick border, so that
-               the start button and bands are not stuck to the screen border. */
-            sr.Size.cx = StartBtnSize.cx + (2 * (EdgeSize.cx + DlgFrameSize.cx));
-            sr.Size.cy = StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy));
+        return hMon;
+    }
 
-            /* Use the primary screen by default */
-            rcScreen.left = 0;
-            rcScreen.top = 0;
-            rcScreen.right = GetSystemMetrics(SM_CXSCREEN);
-            rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN);
-            GetScreenRectFromRect(
-                &rcScreen,
-                MONITOR_DEFAULTTOPRIMARY);
+    VOID AdjustSizerRect(RECT *rc, DWORD pos)
+    {
+        int iSizerPart[4] = {TBP_SIZINGBARLEFT, TBP_SIZINGBARTOP, TBP_SIZINGBARRIGHT, TBP_SIZINGBARBOTTOM};
+        SIZE size;
+
+        if (pos > ABE_BOTTOM)
+            pos = ABE_BOTTOM;
+
+        HRESULT hr = GetThemePartSize(m_Theme, NULL, iSizerPart[pos], 0, NULL, TS_TRUE, &size);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return;
+
+        switch (pos)
+        {
+            case ABE_TOP:
+                rc->bottom -= size.cy;
+                break;
+            case ABE_BOTTOM:
+                rc->top += size.cy;
+                break;
+            case ABE_LEFT:
+                rc->right -= size.cx;
+                break;
+            case ABE_RIGHT:
+                rc->left += size.cx;
+                break;
         }
+    }
 
-        if (m_hWnd != NULL)
-            SetWindowPos(
-            AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
-            0,
-            0,
-            0,
-            0,
-            SWP_NOMOVE | SWP_NOSIZE);
+    VOID MakeTrayRectWithSize(IN DWORD Position,
+                              IN const SIZE *pTraySize,
+                              IN OUT RECT *pRect)
+    {
+        switch (Position)
+        {
+        case ABE_LEFT:
+            pRect->right = pRect->left + pTraySize->cx;
+            break;
 
-        /* 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
-           loaded from the registry are at least. The windows explorer behaves
-           the same way, it allows the user to save a zero width vertical tray
-           window, but not a zero height horizontal tray window. */
-        WndSize.cx = 2 * (EdgeSize.cx + DlgFrameSize.cx);
-        WndSize.cy = StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy));
+        case ABE_TOP:
+            pRect->bottom = pRect->top + pTraySize->cy;
+            break;
 
-        if (WndSize.cx < sr.Size.cx)
-            WndSize.cx = sr.Size.cx;
-        if (WndSize.cy < sr.Size.cy)
-            WndSize.cy = sr.Size.cy;
+        case ABE_RIGHT:
+            pRect->left = pRect->right - pTraySize->cx;
+            break;
 
-        /* Save the calculated size */
-        m_TraySize = WndSize;
+        case ABE_BOTTOM:
+        default:
+            pRect->top = pRect->bottom - pTraySize->cy;
+            break;
+        }
+    }
 
-        /* Calculate all docking rectangles. We need to do this here so they're
-           initialized and dragging the tray window to another position gives
-           usable results */
-        for (Pos = ABE_LEFT;
-             Pos <= ABE_BOTTOM;
-             Pos++)
+    VOID GetTrayRectFromScreenRect(IN DWORD Position,
+                                   IN const RECT *pScreen,
+                                   IN const SIZE *pTraySize OPTIONAL,
+                                   OUT RECT *pRect)
+    {
+        if (pTraySize == NULL)
+            pTraySize = &m_TraySize;
+
+        *pRect = *pScreen;
+
+        if(!m_Theme)
         {
-            GetTrayRectFromScreenRect(
-                Pos,
-                &rcScreen,
-                &m_TraySize,
-                &m_TrayRects[Pos]);
-            //        TRACE("m_TrayRects[%d(%d)]: %d,%d,%d,%d\n", Pos, Position, m_TrayRects[Pos].left, m_TrayRects[Pos].top, m_TrayRects[Pos].right, m_TrayRects[Pos].bottom);
+            /* Move the border outside of the screen */
+            InflateRect(pRect,
+                        GetSystemMetrics(SM_CXEDGE),
+                        GetSystemMetrics(SM_CYEDGE));
         }
 
-        /* Determine which monitor we are on. It shouldn't matter which docked
-           position rectangle we use */
-        m_Monitor = GetMonitorFromRect(&m_TrayRects[ABE_LEFT]);
+        MakeTrayRectWithSize(Position, pTraySize, pRect);
     }
 
-    UINT TrackMenu(
-        IN HMENU hMenu,
-        IN POINT *ppt OPTIONAL,
-        IN HWND hwndExclude OPTIONAL,
-        IN BOOL TrackUp,
-        IN BOOL IsContextMenu)
+    BOOL IsPosHorizontal()
     {
-        TPMPARAMS tmp, *ptmp = NULL;
-        POINT pt;
-        UINT cmdId;
-        UINT fuFlags;
+        return m_Position == ABE_TOP || m_Position == ABE_BOTTOM;
+    }
 
-        if (hwndExclude != NULL)
+    HMONITOR CalculateValidSize(
+        IN DWORD Position,
+        IN OUT RECT *pRect)
+    {
+        RECT rcScreen;
+        //BOOL Horizontal;
+        HMONITOR hMon;
+        SIZE szMax, szWnd;
+
+        //Horizontal = IsPosHorizontal();
+
+        szWnd.cx = pRect->right - pRect->left;
+        szWnd.cy = pRect->bottom - pRect->top;
+
+        rcScreen = *pRect;
+        hMon = GetScreenRectFromRect(
+            &rcScreen,
+            MONITOR_DEFAULTTONEAREST);
+
+        /* Calculate the maximum size of the tray window and limit the window
+           size to half of the screen's size. */
+        szMax.cx = (rcScreen.right - rcScreen.left) / 2;
+        szMax.cy = (rcScreen.bottom - rcScreen.top) / 2;
+        if (szWnd.cx > szMax.cx)
+            szWnd.cx = szMax.cx;
+        if (szWnd.cy > szMax.cy)
+            szWnd.cy = szMax.cy;
+
+        /* FIXME - calculate */
+
+        GetTrayRectFromScreenRect(Position,
+                                  &rcScreen,
+                                  &szWnd,
+                                  pRect);
+
+        return hMon;
+    }
+
+#if 0
+    VOID
+        GetMinimumWindowSize(
+        OUT RECT *pRect)
+    {
+        RECT rcMin = {0};
+
+        AdjustWindowRectEx(&rcMin,
+                           GetWindowLong(m_hWnd,
+                           GWL_STYLE),
+                           FALSE,
+                           GetWindowLong(m_hWnd,
+                           GWL_EXSTYLE));
+
+        *pRect = rcMin;
+    }
+#endif
+
+
+    DWORD GetDraggingRectFromPt(
+        IN POINT pt,
+        OUT RECT *pRect,
+        OUT HMONITOR *phMonitor)
+    {
+        HMONITOR hMon, hMonNew;
+        DWORD PosH, PosV, Pos;
+        SIZE DeltaPt, ScreenOffset;
+        RECT rcScreen;
+
+        rcScreen.left = 0;
+        rcScreen.top = 0;
+
+        /* Determine the screen rectangle */
+        hMon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);
+        if (hMon != NULL)
         {
-            /* Get the client rectangle and map it to screen coordinates */
-            if (::GetClientRect(hwndExclude,
-                &tmp.rcExclude) &&
-                MapWindowPoints(hwndExclude,
-                NULL,
-                (LPPOINT) &tmp.rcExclude,
-                2) != 0)
+            MONITORINFO mi;
+
+            mi.cbSize = sizeof(mi);
+            if (!GetMonitorInfo(hMon, &mi))
             {
-                ptmp = &tmp;
+                hMon = NULL;
+                goto GetPrimaryScreenRect;
             }
+
+            /* make left top corner of the screen zero based to
+               make calculations easier */
+            pt.x -= mi.rcMonitor.left;
+            pt.y -= mi.rcMonitor.top;
+
+            ScreenOffset.cx = mi.rcMonitor.left;
+            ScreenOffset.cy = mi.rcMonitor.top;
+            rcScreen.right = mi.rcMonitor.right - mi.rcMonitor.left;
+            rcScreen.bottom = mi.rcMonitor.bottom - mi.rcMonitor.top;
+        }
+        else
+        {
+GetPrimaryScreenRect:
+            ScreenOffset.cx = 0;
+            ScreenOffset.cy = 0;
+            rcScreen.right = GetSystemMetrics(SM_CXSCREEN);
+            rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN);
         }
 
-        if (ppt == NULL)
+        /* Calculate the nearest screen border */
+        if (pt.x < rcScreen.right / 2)
         {
-            if (ptmp == NULL &&
-                GetClientRect(&tmp.rcExclude) &&
-                MapWindowPoints(m_hWnd,
-                NULL,
-                (LPPOINT) &tmp.rcExclude,
-                2) != 0)
-            {
-                ptmp = &tmp;
-            }
+            DeltaPt.cx = pt.x;
+            PosH = ABE_LEFT;
+        }
+        else
+        {
+            DeltaPt.cx = rcScreen.right - pt.x;
+            PosH = ABE_RIGHT;
+        }
 
-            if (ptmp != NULL)
-            {
-                /* NOTE: TrackPopupMenuEx will eventually align the track position
-                         for us, no need to take care of it here as long as the
-                         coordinates are somewhere within the exclusion rectangle */
-                pt.x = ptmp->rcExclude.left;
-                pt.y = ptmp->rcExclude.top;
-            }
-            else
-                pt.x = pt.y = 0;
+        if (pt.y < rcScreen.bottom / 2)
+        {
+            DeltaPt.cy = pt.y;
+            PosV = ABE_TOP;
         }
         else
-            pt = *ppt;
+        {
+            DeltaPt.cy = rcScreen.bottom - pt.y;
+            PosV = ABE_BOTTOM;
+        }
 
-        tmp.cbSize = sizeof(tmp);
+        Pos = (DeltaPt.cx * rcScreen.bottom < DeltaPt.cy * rcScreen.right) ? PosH : PosV;
 
-        fuFlags = TPM_RETURNCMD | TPM_VERTICAL;
-        fuFlags |= (TrackUp ? TPM_BOTTOMALIGN : TPM_TOPALIGN);
-        if (IsContextMenu)
-            fuFlags |= TPM_RIGHTBUTTON;
+        /* Fix the screen origin to be relative to the primary monitor again */
+        OffsetRect(&rcScreen,
+                   ScreenOffset.cx,
+                   ScreenOffset.cy);
+
+        RECT rcPos = m_TrayRects[Pos];
+
+        hMonNew = GetMonitorFromRect(&rcPos);
+        if (hMon != hMonNew)
+        {
+            SIZE szTray;
+
+            /* Recalculate the rectangle, we're dragging to another monitor.
+               We don't need to recalculate the rect on single monitor systems. */
+            szTray.cx = rcPos.right - rcPos.left;
+            szTray.cy = rcPos.bottom - rcPos.top;
+
+            GetTrayRectFromScreenRect(Pos, &rcScreen, &szTray, pRect);
+            if (AutoHide)
+            {
+                pRect->left += m_AutoHideOffset.cx;
+                pRect->right += m_AutoHideOffset.cx;
+                pRect->top += m_AutoHideOffset.cy;
+                pRect->bottom += m_AutoHideOffset.cy;
+            }
+            hMon = hMonNew;
+        }
         else
-            fuFlags |= (TrackUp ? TPM_VERNEGANIMATION : TPM_VERPOSANIMATION);
+        {
+            /* The user is dragging the tray window on the same monitor. We don't need
+               to recalculate the rectangle */
+            *pRect = rcPos;
+            if (AutoHide)
+            {
+                pRect->left += m_AutoHideOffset.cx;
+                pRect->right += m_AutoHideOffset.cx;
+                pRect->top += m_AutoHideOffset.cy;
+                pRect->bottom += m_AutoHideOffset.cy;
+            }
+        }
 
-        cmdId = TrackPopupMenuEx(hMenu,
-                                 fuFlags,
-                                 pt.x,
-                                 pt.y,
-                                 m_hWnd,
-                                 ptmp);
+        *phMonitor = hMon;
 
-        return cmdId;
+        return Pos;
     }
 
-    HRESULT TrackCtxMenu(
-        IN IContextMenu * contextMenu,
-        IN POINT *ppt OPTIONAL,
-        IN HWND hwndExclude OPTIONAL,
-        IN BOOL TrackUp,
-        IN PVOID Context OPTIONAL)
+    DWORD GetDraggingRectFromRect(
+        IN OUT RECT *pRect,
+        OUT HMONITOR *phMonitor)
     {
-        INT x = ppt->x;
-        INT y = ppt->y;
-        HRESULT hr;
-        UINT uCommand;
-        HMENU popup = CreatePopupMenu();
+        POINT pt;
 
-        if (popup == NULL)
-            return E_FAIL;
+        /* Calculate the center of the rectangle. We call
+           GetDraggingRectFromPt to calculate a valid
+           dragging rectangle */
+        pt.x = pRect->left + ((pRect->right - pRect->left) / 2);
+        pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2);
 
-        TRACE("Before Query\n");
-        hr = contextMenu->QueryContextMenu(popup, 0, 0, UINT_MAX, CMF_NORMAL);
-        if (FAILED_UNEXPECTEDLY(hr))
-        {
-            TRACE("Query failed\n");
-            DestroyMenu(popup);
-            return hr;
-        }
-        
-        TRACE("Before Tracking\n");
-        uCommand = ::TrackPopupMenuEx(popup, TPM_RETURNCMD, x, y, m_hWnd, NULL);
+        return GetDraggingRectFromPt(
+            pt,
+            pRect,
+            phMonitor);
+    }
 
-        if (uCommand != 0)
+    VOID ChangingWinPos(IN OUT LPWINDOWPOS pwp)
+    {
+        RECT rcTray;
+
+        if (IsDragging)
         {
-            TRACE("Before InvokeCommand\n");
-            CMINVOKECOMMANDINFO cmi = { 0 };
-            cmi.cbSize = sizeof(cmi);
-            cmi.lpVerb = MAKEINTRESOURCEA(uCommand);
-            cmi.hwnd = m_hWnd;
-            hr = contextMenu->InvokeCommand(&cmi);
+            rcTray.left = pwp->x;
+            rcTray.top = pwp->y;
+            rcTray.right = rcTray.left + pwp->cx;
+            rcTray.bottom = rcTray.top + pwp->cy;
+            if (AutoHide)
+            {
+                rcTray.left -= m_AutoHideOffset.cx;
+                rcTray.right -= m_AutoHideOffset.cx;
+                rcTray.top -= m_AutoHideOffset.cy;
+                rcTray.bottom -= m_AutoHideOffset.cy;
+            }
+
+            if (!EqualRect(&rcTray,
+                &m_TrayRects[m_DraggingPosition]))
+            {
+                /* Recalculate the rectangle, the user dragged the tray
+                   window to another monitor or the window was somehow else
+                   moved or resized */
+                m_DraggingPosition = GetDraggingRectFromRect(
+                    &rcTray,
+                    &m_DraggingMonitor);
+                //m_TrayRects[DraggingPosition] = rcTray;
+            }
+
+            //Monitor = CalculateValidSize(DraggingPosition,
+            //                             &rcTray);
+
+            m_Monitor = m_DraggingMonitor;
+            m_Position = m_DraggingPosition;
+            IsDragging = FALSE;
+
+            m_TrayRects[m_Position] = rcTray;
+            goto ChangePos;
         }
-        else
+        else if (GetWindowRect(&rcTray))
         {
-            TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand, GetLastError());
-            hr = S_FALSE;
-        }
+            if (InSizeMove)
+            {
+                if (!(pwp->flags & SWP_NOMOVE))
+                {
+                    rcTray.left = pwp->x;
+                    rcTray.top = pwp->y;
+                }
 
-        DestroyMenu(popup);
-        return hr;
+                if (!(pwp->flags & SWP_NOSIZE))
+                {
+                    rcTray.right = rcTray.left + pwp->cx;
+                    rcTray.bottom = rcTray.top + pwp->cy;
+                }
+
+                m_Position = GetDraggingRectFromRect(&rcTray, &m_Monitor);
+
+                if (!(pwp->flags & (SWP_NOMOVE | SWP_NOSIZE)))
+                {
+                    SIZE szWnd;
+
+                    szWnd.cx = pwp->cx;
+                    szWnd.cy = pwp->cy;
+
+                    MakeTrayRectWithSize(m_Position, &szWnd, &rcTray);
+                }
+
+                if (AutoHide)
+                {
+                    rcTray.left -= m_AutoHideOffset.cx;
+                    rcTray.right -= m_AutoHideOffset.cx;
+                    rcTray.top -= m_AutoHideOffset.cy;
+                    rcTray.bottom -= m_AutoHideOffset.cy;
+                }
+                m_TrayRects[m_Position] = rcTray;
+            }
+            else
+            {
+                /* If the user isn't resizing the tray window we need to make sure the
+                   new size or position is valid. this is to prevent changes to the window
+                   without user interaction. */
+                rcTray = m_TrayRects[m_Position];
+            }
+
+ChangePos:
+            m_TraySize.cx = rcTray.right - rcTray.left;
+            m_TraySize.cy = rcTray.bottom - rcTray.top;
+
+            if (AutoHide)
+            {
+                rcTray.left += m_AutoHideOffset.cx;
+                rcTray.right += m_AutoHideOffset.cx;
+                rcTray.top += m_AutoHideOffset.cy;
+                rcTray.bottom += m_AutoHideOffset.cy;
+            }
+
+            pwp->flags &= ~(SWP_NOMOVE | SWP_NOSIZE);
+            pwp->x = rcTray.left;
+            pwp->y = rcTray.top;
+            pwp->cx = m_TraySize.cx;
+            pwp->cy = m_TraySize.cy;
+        }
     }
 
-    VOID AlignControls(IN PRECT prcClient OPTIONAL)
+    VOID ApplyClipping(IN BOOL Clip)
     {
-        RECT rcClient;
-        SIZE TraySize, StartSize;
-        POINT ptTrayNotify = { 0, 0 };
-        BOOL Horizontal;
-        HDWP dwp;
+        RECT rcClip, rcWindow;
+        HRGN hClipRgn;
 
-        m_StartButton.UpdateSize();
-        if (prcClient != NULL)
-        {
-            rcClient = *prcClient;
-        }
-        else
+        if (GetWindowRect(&rcWindow))
         {
-            if (!GetClientRect(&rcClient))
+            /* Disable clipping on systems with only one monitor */
+            if (GetSystemMetrics(SM_CMONITORS) <= 1)
+                Clip = FALSE;
+
+            if (Clip)
             {
-                return;
-            }
-        }
+                rcClip = rcWindow;
 
-        Horizontal = IsPosHorizontal();
+                GetScreenRect(m_Monitor, &rcClip);
 
-        /* We're about to resize/move the start button, the rebar control and
-           the tray notification control */
-        dwp = BeginDeferWindowPos(3);
-        if (dwp == NULL)
-            return;
+                if (!IntersectRect(&rcClip, &rcClip, &rcWindow))
+                {
+                    rcClip = rcWindow;
+                }
 
-        /* Limit the Start button width to the client width, if neccessary */
-        StartSize = m_StartButton.GetSize();
-        if (StartSize.cx > rcClient.right)
-            StartSize.cx = rcClient.right;
+                OffsetRect(&rcClip,
+                           -rcWindow.left,
+                           -rcWindow.top);
 
-        if (m_StartButton.m_hWnd != NULL)
-        {
-            /* Resize and reposition the button */
-            dwp = DeferWindowPos(dwp,
-                                 m_StartButton.m_hWnd,
-                                 NULL,
-                                 0,
-                                 0,
-                                 StartSize.cx,
-                                 StartSize.cy,
-                                 SWP_NOZORDER | SWP_NOACTIVATE);
-            if (dwp == NULL)
-                return;
-        }
+                hClipRgn = CreateRectRgnIndirect(&rcClip);
+            }
+            else
+                hClipRgn = NULL;
 
-        /* Determine the size that the tray notification window needs */
-        if (Horizontal)
-        {
-            TraySize.cx = 0;
-            TraySize.cy = rcClient.bottom;
-        }
-        else
-        {
-            TraySize.cx = rcClient.right;
-            TraySize.cy = 0;
+            /* Set the clipping region or make sure the window isn't clipped
+               by disabling it explicitly. */
+            SetWindowRgn(hClipRgn, TRUE);
         }
+    }
 
-        if (m_TrayNotify != NULL &&
-            SendMessage(m_TrayNotify,
-            TNWM_GETMINIMUMSIZE,
-            (WPARAM) Horizontal,
-            (LPARAM) &TraySize))
-        {
-            /* Move the tray notification window to the desired location */
-            if (Horizontal)
-                ptTrayNotify.x = rcClient.right - TraySize.cx;
-            else
-                ptTrayNotify.y = rcClient.bottom - TraySize.cy;
+    VOID ResizeWorkArea()
+    {
+#if !WIN7_DEBUG_MODE
+        RECT rcTray, rcWorkArea;
 
-            dwp = DeferWindowPos(dwp,
-                                 m_TrayNotify,
-                                 NULL,
-                                 ptTrayNotify.x,
-                                 ptTrayNotify.y,
-                                 TraySize.cx,
-                                 TraySize.cy,
-                                 SWP_NOZORDER | SWP_NOACTIVATE);
-            if (dwp == NULL)
-                return;
+        /* If monitor has changed then fix the previous monitors work area */
+        if (m_PreviousMonitor != m_Monitor)
+        {
+            GetScreenRect(m_PreviousMonitor, &rcWorkArea);
+            SystemParametersInfoW(SPI_SETWORKAREA,
+                                  1,
+                                  &rcWorkArea,
+                                  SPIF_SENDCHANGE);
         }
 
-        /* Resize/Move the rebar control */
-        if (m_Rebar != NULL)
-        {
-            POINT ptRebar = { 0, 0 };
-            SIZE szRebar;
+        rcTray = m_TrayRects[m_Position];
 
-            SetWindowStyle(m_Rebar, CCS_VERT, Horizontal ? 0 : CCS_VERT);
+        GetScreenRect(m_Monitor, &rcWorkArea);
+        m_PreviousMonitor = m_Monitor;
 
-            if (Horizontal)
-            {
-                ptRebar.x = StartSize.cx + GetSystemMetrics(SM_CXSIZEFRAME);
-                szRebar.cx = ptTrayNotify.x - ptRebar.x;
-                szRebar.cy = rcClient.bottom;
-            }
-            else
+        /* If AutoHide is false then change the workarea to exclude
+           the area that the taskbar covers. */
+        if (!AutoHide)
+        {
+            switch (m_Position)
             {
-                ptRebar.y = StartSize.cy + GetSystemMetrics(SM_CYSIZEFRAME);
-                szRebar.cx = rcClient.right;
-                szRebar.cy = ptTrayNotify.y - ptRebar.y;
+            case ABE_TOP:
+                rcWorkArea.top = rcTray.bottom;
+                break;
+            case ABE_LEFT:
+                rcWorkArea.left = rcTray.right;
+                break;
+            case ABE_RIGHT:
+                rcWorkArea.right = rcTray.left;
+                break;
+            case ABE_BOTTOM:
+                rcWorkArea.bottom = rcTray.top;
+                break;
             }
-
-            dwp = DeferWindowPos(dwp,
-                                 m_Rebar,
-                                 NULL,
-                                 ptRebar.x,
-                                 ptRebar.y,
-                                 szRebar.cx,
-                                 szRebar.cy,
-                                 SWP_NOZORDER | SWP_NOACTIVATE);
         }
 
-        if (dwp != NULL)
-            EndDeferWindowPos(dwp);
-
-        if (m_TaskSwitch != NULL)
-        {
-            /* Update the task switch window configuration */
-            SendMessage(m_TaskSwitch, TSWM_UPDATETASKBARPOS, 0, 0);
-        }
+        /*
+         * Resize the current monitor work area. Win32k will also send
+         * a WM_SIZE message to automatically resize the desktop.
+         */
+        SystemParametersInfoW(SPI_SETWORKAREA,
+                              1,
+                              &rcWorkArea,
+                              SPIF_SENDCHANGE);
+#endif
     }
 
-    LRESULT OnThemeChanged()
+    VOID CheckTrayWndPosition()
     {
-        if (m_Theme)
-            CloseThemeData(m_Theme);
+        RECT rcTray;
 
-        if (IsThemeActive())
-            m_Theme = OpenThemeData(m_hWnd, L"TaskBar");
-        else
-            m_Theme = NULL;
+        rcTray = m_TrayRects[m_Position];
 
-        if (m_Theme)
-        {
-            SetWindowStyle(m_hWnd, WS_THICKFRAME | WS_BORDER, 0);
-        }
-        else
+        if (AutoHide)
         {
-            SetWindowStyle(m_hWnd, WS_THICKFRAME | WS_BORDER, WS_THICKFRAME | WS_BORDER);
+            rcTray.left += m_AutoHideOffset.cx;
+            rcTray.right += m_AutoHideOffset.cx;
+            rcTray.top += m_AutoHideOffset.cy;
+            rcTray.bottom += m_AutoHideOffset.cy;
         }
 
-        return TRUE;
+        IUnknown_Exec(m_TrayBandSite,
+                      IID_IDeskBand,
+                      DBID_BANDINFOCHANGED,
+                      0,
+                      NULL,
+                      NULL);
+
+        FitToRebar(&rcTray);
+        m_TrayRects[m_Position] = rcTray;
+
+        /* Move the tray window */
+        SetWindowPos(NULL,
+                     rcTray.left,
+                     rcTray.top,
+                     rcTray.right - rcTray.left,
+                     rcTray.bottom - rcTray.top,
+                     SWP_NOZORDER | SWP_NOACTIVATE);
+
+        ResizeWorkArea();
+
+        ApplyClipping(TRUE);
     }
 
-    LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    typedef struct _TW_STUCKRECTS2
     {
-        return OnThemeChanged();
-    }
+        DWORD cbSize;
+        LONG Unknown;
+        DWORD dwFlags;
+        DWORD Position;
+        SIZE Size;
+        RECT Rect;
+    } TW_STRUCKRECTS2, *PTW_STUCKRECTS2;
 
-    LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    VOID RegLoadSettings()
     {
-        WCHAR szStartCaption[32];
+        DWORD Pos;
+        TW_STRUCKRECTS2 sr;
+        RECT rcScreen;
+        SIZE WndSize, EdgeSize, DlgFrameSize;
+        DWORD cbSize = sizeof(sr);
+        SIZE StartBtnSize = m_StartButton.GetSize();
 
-        ((ITrayWindow*)this)->AddRef();
+        EdgeSize.cx = GetSystemMetrics(SM_CXEDGE);
+        EdgeSize.cy = GetSystemMetrics(SM_CYEDGE);
+        DlgFrameSize.cx = GetSystemMetrics(SM_CXDLGFRAME);
+        DlgFrameSize.cy = GetSystemMetrics(SM_CYDLGFRAME);
 
-        SetWindowTheme(m_hWnd, L"TaskBar", NULL);
-        OnThemeChanged();
+        if (SHGetValue(hkExplorer,
+            TEXT("StuckRects2"),
+            TEXT("Settings"),
+            NULL,
+            &sr,
+            &cbSize) == ERROR_SUCCESS &&
+            sr.cbSize == sizeof(sr))
+        {
+            AutoHide = (sr.dwFlags & ABS_AUTOHIDE) != 0;
+            AlwaysOnTop = (sr.dwFlags & ABS_ALWAYSONTOP) != 0;
+            SmSmallIcons = (sr.dwFlags & 0x4) != 0;
+            HideClock = (sr.dwFlags & 0x8) != 0;
 
-        InterlockedIncrement(&TrayWndCount);
+            /* FIXME: Are there more flags? */
 
-        if (!LoadString(hExplorerInstance,
-            IDS_START,
-            szStartCaption,
-            sizeof(szStartCaption) / sizeof(szStartCaption[0])))
-        {
-            szStartCaption[0] = TEXT('\0');
-        }
+#if WIN7_DEBUG_MODE
+            m_Position = ABE_LEFT;
+#else
+            if (sr.Position > ABE_BOTTOM)
+                m_Position = ABE_BOTTOM;
+            else
+                m_Position = sr.Position;
+#endif
 
-        if (m_CaptionFont == NULL)
+            /* Try to find out which monitor the tray window was located on last.
+               Here we're only interested in the monitor screen that we think
+               is the last one used. We're going to determine on which monitor
+               we really are after calculating the docked position. */
+            rcScreen = sr.Rect;
+            GetScreenRectFromRect(
+                &rcScreen,
+                MONITOR_DEFAULTTONEAREST);
+        }
+        else
         {
-            NONCLIENTMETRICS ncm;
+            m_Position = ABE_BOTTOM;
+            AlwaysOnTop = TRUE;
 
-            /* Get the system fonts, we use the caption font,
-               always bold, though. */
-            ncm.cbSize = sizeof(ncm);
-            if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, FALSE))
+            /* Use the minimum size of the taskbar, we'll use the start
+               button as a minimum for now. Make sure we calculate the
+               entire window size, not just the client size. However, we
+               use a thinner border than a standard thick border, so that
+               the start button and bands are not stuck to the screen border. */
+            if(!m_Theme)
             {
-                if (m_CaptionFont == NULL)
-                {
-                    ncm.lfCaptionFont.lfWeight = FW_NORMAL;
-                    m_CaptionFont = CreateFontIndirect(&ncm.lfCaptionFont);
-                }
+                sr.Size.cx = StartBtnSize.cx + (2 * (EdgeSize.cx + DlgFrameSize.cx));
+                sr.Size.cy = StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy));
+            }
+            else
+            {
+                sr.Size.cx = StartBtnSize.cx - EdgeSize.cx;
+                sr.Size.cy = StartBtnSize.cy - EdgeSize.cy;
+                if(!Locked)
+                    sr.Size.cy += GetSystemMetrics(SM_CYSIZEFRAME);
             }
-        }
-        
-        /* Create the Start button */
-        m_StartButton.SubclassWindow(CreateWindowEx(
-            0,
-            WC_BUTTON,
-            szStartCaption,
-            WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS |
-            BS_PUSHBUTTON | BS_CENTER | BS_VCENTER | BS_BITMAP,
-            0,
-            0,
-            0,
-            0,
-            m_hWnd,
-            (HMENU) IDC_STARTBTN,
-            hExplorerInstance,
-            NULL));
 
-        if (m_StartButton.m_hWnd)
-        {
-            m_StartButton.Initialize();
+            /* Use the primary screen by default */
+            rcScreen.left = 0;
+            rcScreen.top = 0;
+            rcScreen.right = GetSystemMetrics(SM_CXSCREEN);
+            rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN);
+            GetScreenRectFromRect(
+                &rcScreen,
+                MONITOR_DEFAULTTOPRIMARY);
         }
 
-        /* Load the saved tray window settings */
-        RegLoadSettings();
-
-        /* Create and initialize the start menu */
-        HBITMAP hbmBanner = LoadBitmap(hExplorerInstance, MAKEINTRESOURCE(IDB_STARTMENU));
-        m_StartMenuPopup = CreateStartMenu(this, &m_StartMenuBand, hbmBanner, 0);
+        if (m_hWnd != NULL)
+            SetWindowPos(
+            AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
+            0,
+            0,
+            0,
+            0,
+            SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
 
-        /* Load the tray band site */
-        if (m_TrayBandSite != NULL)
+        /* 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
+           loaded from the registry are at least. The windows explorer behaves
+           the same way, it allows the user to save a zero width vertical tray
+           window, but not a zero height horizontal tray window. */
+        if(!m_Theme)
         {
-            m_TrayBandSite.Release();
+            WndSize.cx = 2 * (EdgeSize.cx + DlgFrameSize.cx);
+            WndSize.cy = StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy));
         }
-
-        m_TrayBandSite = CreateTrayBandSite(this, &m_Rebar, &m_TaskSwitch);
-        SetWindowTheme(m_Rebar, L"TaskBar", NULL);
-
-        /* Create the tray notification window */
-        m_TrayNotify = CreateTrayNotifyWnd(this, HideClock, &m_TrayNotifyInstance);
-
-        if (UpdateNonClientMetrics())
+        else
         {
-            SetWindowsFont();
+            WndSize.cx = StartBtnSize.cx;
+            WndSize.cy = StartBtnSize.cy - EdgeSize.cx;
         }
 
-        /* Move the tray window to the right position and resize it if neccessary */
-        CheckTrayWndPosition();
-
-        /* Align all controls on the tray window */
-        AlignControls(NULL);
+        if (WndSize.cx < sr.Size.cx)
+            WndSize.cx = sr.Size.cx;
+        if (WndSize.cy < sr.Size.cy)
+            WndSize.cy = sr.Size.cy;
 
-        InitShellServices(&(m_ShellServices));
+        /* Save the calculated size */
+        m_TraySize = WndSize;
 
-        if (AutoHide)
+        /* Calculate all docking rectangles. We need to do this here so they're
+           initialized and dragging the tray window to another position gives
+           usable results */
+        for (Pos = ABE_LEFT; Pos <= ABE_BOTTOM; Pos++)
         {
-            m_AutoHideState = AUTOHIDE_HIDING;
-            SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL);
+            GetTrayRectFromScreenRect(Pos,
+                                      &rcScreen,
+                                      &m_TraySize,
+                                      &m_TrayRects[Pos]);
+            // TRACE("m_TrayRects[%d(%d)]: %d,%d,%d,%d\n", Pos, Position, m_TrayRects[Pos].left, m_TrayRects[Pos].top, m_TrayRects[Pos].right, m_TrayRects[Pos].bottom);
         }
 
-        RegisterHotKey(m_hWnd, IDHK_RUN, MOD_WIN, 'R');
-        RegisterHotKey(m_hWnd, IDHK_MINIMIZE_ALL, MOD_WIN, 'M');
-        RegisterHotKey(m_hWnd, IDHK_RESTORE_ALL, MOD_WIN|MOD_SHIFT, 'M');
-        RegisterHotKey(m_hWnd, IDHK_HELP, MOD_WIN, VK_F1);
-        RegisterHotKey(m_hWnd, IDHK_EXPLORE, MOD_WIN, 'E');
-        RegisterHotKey(m_hWnd, IDHK_FIND, MOD_WIN, 'F');
-        RegisterHotKey(m_hWnd, IDHK_FIND_COMPUTER, MOD_WIN|MOD_CONTROL, 'F');
-        RegisterHotKey(m_hWnd, IDHK_NEXT_TASK, MOD_WIN, VK_TAB);
-        RegisterHotKey(m_hWnd, IDHK_PREV_TASK, MOD_WIN|MOD_SHIFT, VK_TAB);
-        RegisterHotKey(m_hWnd, IDHK_SYS_PROPERTIES, MOD_WIN, VK_PAUSE);
-        RegisterHotKey(m_hWnd, IDHK_DESKTOP, MOD_WIN, 'D');
-        RegisterHotKey(m_hWnd, IDHK_PAGER, MOD_WIN, 'B');
-
-        return TRUE;
+        /* Determine which monitor we are on. It shouldn't matter which docked
+           position rectangle we use */
+        m_Monitor = GetMonitorFromRect(&m_TrayRects[ABE_LEFT]);
     }
 
-    HRESULT STDMETHODCALLTYPE Open()
+    VOID AlignControls(IN PRECT prcClient OPTIONAL)
     {
-        RECT rcWnd;
+        RECT rcClient;
+        SIZE TraySize, StartSize;
+        POINT ptTrayNotify = { 0, 0 };
+        BOOL Horizontal;
+        HDWP dwp;
 
-        /* Check if there's already a window created and try to show it.
-           If it was somehow destroyed just create a new tray window. */
-        if (m_hWnd != NULL && IsWindow())
+        m_StartButton.UpdateSize();
+        if (prcClient != NULL)
+        {
+            rcClient = *prcClient;
+        }
+        else
         {
-            if (!IsWindowVisible(m_hWnd))
+            if (!GetClientRect(&rcClient))
             {
-                CheckTrayWndPosition();
-
-                ShowWindow(SW_SHOW);
+                ERR("Could not get client rect lastErr=%d\n", GetLastError());
+                return;
             }
-
-            return S_OK;
         }
 
-        DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE;
-        if (AlwaysOnTop)
-            dwExStyle |= WS_EX_TOPMOST;
-
-        DWORD dwStyle = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
-            WS_BORDER | WS_THICKFRAME;
-
-        ZeroMemory(&rcWnd, sizeof(rcWnd));
-        if (m_Position != (DWORD) -1)
-            rcWnd = m_TrayRects[m_Position];
-
-        if (!Create(NULL, rcWnd, NULL, dwStyle, dwExStyle))
-            return E_FAIL;
+        Horizontal = IsPosHorizontal();
 
-        return S_OK;
-    }
+        IUnknown_Exec(m_TrayBandSite,
+                      IID_IDeskBand,
+                      DBID_BANDINFOCHANGED,
+                      0,
+                      NULL,
+                      NULL);
 
-    HRESULT STDMETHODCALLTYPE Close()
-    {
-        if (m_hWnd != NULL)
+        /* We're about to resize/move the start button, the rebar control and
+           the tray notification control */
+        dwp = BeginDeferWindowPos(3);
+        if (dwp == NULL)
         {
-            SendMessage(m_hWnd,
-                        WM_APP_TRAYDESTROY,
-                        0,
-                        0);
+            ERR("BeginDeferWindowPos failed. lastErr=%d\n", GetLastError());
+            return;
         }
 
-        return S_OK;
-    }
-
-    HWND STDMETHODCALLTYPE GetHWND()
-    {
-        return m_hWnd;
-    }
-
-    BOOL STDMETHODCALLTYPE IsSpecialHWND(IN HWND hWnd)
-    {
-        return (m_hWnd == hWnd ||
-                (m_DesktopWnd != NULL && m_hWnd == m_DesktopWnd));
-    }
-
-    BOOL STDMETHODCALLTYPE
-        IsHorizontal()
-    {
-        return IsPosHorizontal();
-    }
-
-    HFONT STDMETHODCALLTYPE GetCaptionFonts(OUT HFONT *phBoldCaption OPTIONAL)
-    {
-        if (phBoldCaption != NULL)
-            *phBoldCaption = m_StartButton.GetFont();
-
-        return m_CaptionFont;
-    }
-
-    DWORD WINAPI TrayPropertiesThread()
-    {
-        HWND hwnd;
-        RECT posRect;
-
-        GetWindowRect(m_StartButton.m_hWnd, &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);
-
-        m_TrayPropertiesOwner = hwnd;
-
-        DisplayTrayProperties(hwnd);
-
-        m_TrayPropertiesOwner = NULL;
-        DestroyWindow();
-
-        return 0;
-    }
-
-    static DWORD WINAPI s_TrayPropertiesThread(IN OUT PVOID pParam)
-    {
-        CTrayWindow *This = (CTrayWindow*) pParam;
-
-        return This->TrayPropertiesThread();
-    }
-
-    HWND STDMETHODCALLTYPE DisplayProperties()
-    {
-        HWND hTrayProp;
+        /* Limit the Start button width to the client width, if necessary */
+        StartSize = m_StartButton.GetSize();
+        if (StartSize.cx > rcClient.right)
+            StartSize.cx = rcClient.right;
 
-        if (m_TrayPropertiesOwner)
+        if (!m_Theme)
         {
-            hTrayProp = GetLastActivePopup(m_TrayPropertiesOwner);
-            if (hTrayProp != NULL &&
-                hTrayProp != m_TrayPropertiesOwner)
+            HWND hwndTaskToolbar = ::GetWindow(m_TaskSwitch, GW_CHILD);
+            if (hwndTaskToolbar)
             {
-                SetForegroundWindow(hTrayProp);
-                return NULL;
+                DWORD size = SendMessageW(hwndTaskToolbar, TB_GETBUTTONSIZE, 0, 0);
+                StartSize.cy = HIWORD(size);
             }
         }
 
-        CloseHandle(CreateThread(NULL, 0, s_TrayPropertiesThread, this, 0, NULL));
-        return NULL;
-    }
-
-    VOID OpenCommonStartMenuDirectory(IN HWND hWndOwner, IN LPCTSTR lpOperation)
-    {
-        WCHAR szDir[MAX_PATH];
+        if (m_StartButton.m_hWnd != NULL)
+        {
+            /* Resize and reposition the button */
+            dwp = m_StartButton.DeferWindowPos(dwp,
+                                               NULL,
+                                               0,
+                                               0,
+                                               StartSize.cx,
+                                               StartSize.cy,
+                                               SWP_NOZORDER | SWP_NOACTIVATE);
+            if (dwp == NULL)
+            {
+                ERR("DeferWindowPos for start button failed. lastErr=%d\n", GetLastError());
+                return;
+            }
+        }
 
-        if (SHGetSpecialFolderPath(hWndOwner,
-            szDir,
-            CSIDL_COMMON_STARTMENU,
-            FALSE))
+        /* Determine the size that the tray notification window needs */
+        if (Horizontal)
         {
-            ShellExecute(hWndOwner,
-                         lpOperation,
-                         NULL,
-                         NULL,
-                         szDir,
-                         SW_SHOWNORMAL);
+            TraySize.cx = 0;
+            TraySize.cy = rcClient.bottom;
+        }
+        else
+        {
+            TraySize.cx = rcClient.right;
+            TraySize.cy = 0;
         }
-    }
 
-    VOID OpenTaskManager(IN HWND hWndOwner)
-    {
-        ShellExecute(hWndOwner,
-                     TEXT("open"),
-                     TEXT("taskmgr.exe"),
-                     NULL,
-                     NULL,
-                     SW_SHOWNORMAL);
-    }
+        if (m_TrayNotify != NULL &&
+            SendMessage(m_TrayNotify,
+                        TNWM_GETMINIMUMSIZE,
+                        (WPARAM)Horizontal,
+                        (LPARAM)&TraySize))
+        {
+            /* Move the tray notification window to the desired location */
+            if (Horizontal)
+                ptTrayNotify.x = rcClient.right - TraySize.cx;
+            else
+                ptTrayNotify.y = rcClient.bottom - TraySize.cy;
 
-    BOOL STDMETHODCALLTYPE ExecContextMenuCmd(IN UINT uiCmd)
-    {
-        BOOL bHandled = TRUE;
+            dwp = ::DeferWindowPos(dwp,
+                                   m_TrayNotify,
+                                   NULL,
+                                   ptTrayNotify.x,
+                                   ptTrayNotify.y,
+                                   TraySize.cx,
+                                   TraySize.cy,
+                                   SWP_NOZORDER | SWP_NOACTIVATE);
+            if (dwp == NULL)
+            {
+                ERR("DeferWindowPos for notification area failed. lastErr=%d\n", GetLastError());
+                return;
+            }
+        }
 
-        switch (uiCmd)
+        /* Resize/Move the rebar control */
+        if (m_Rebar != NULL)
         {
-        case ID_SHELL_CMD_PROPERTIES:
-            DisplayProperties();
-            break;
-
-        case ID_SHELL_CMD_OPEN_ALL_USERS:
-            OpenCommonStartMenuDirectory(m_hWnd,
-                                         TEXT("open"));
-            break;
+            POINT ptRebar = { 0, 0 };
+            SIZE szRebar;
 
-        case ID_SHELL_CMD_EXPLORE_ALL_USERS:
-            OpenCommonStartMenuDirectory(m_hWnd,
-                                         TEXT("explore"));
-            break;
+            SetWindowStyle(m_Rebar, CCS_VERT, Horizontal ? 0 : CCS_VERT);
 
-        case ID_LOCKTASKBAR:
-            if (SHRestricted(REST_CLASSICSHELL) == 0)
+            if (Horizontal)
             {
-                Lock(!Locked);
+                ptRebar.x = StartSize.cx + GetSystemMetrics(SM_CXSIZEFRAME);
+                szRebar.cx = ptTrayNotify.x - ptRebar.x;
+                szRebar.cy = rcClient.bottom;
+            }
+            else
+            {
+                ptRebar.y = StartSize.cy + GetSystemMetrics(SM_CYSIZEFRAME);
+                szRebar.cx = rcClient.right;
+                szRebar.cy = ptTrayNotify.y - ptRebar.y;
             }
-            break;
 
-        case ID_SHELL_CMD_OPEN_TASKMGR:
-            OpenTaskManager(m_hWnd);
-            break;
+            dwp = ::DeferWindowPos(dwp,
+                                   m_Rebar,
+                                   NULL,
+                                   ptRebar.x,
+                                   ptRebar.y,
+                                   szRebar.cx,
+                                   szRebar.cy,
+                                   SWP_NOZORDER | SWP_NOACTIVATE);
+        }
 
-        case ID_SHELL_CMD_UNDO_ACTION:
-            break;
+        if (dwp != NULL)
+            EndDeferWindowPos(dwp);
 
-        case ID_SHELL_CMD_SHOW_DESKTOP:
-            break;
+        if (m_TaskSwitch != NULL)
+        {
+            /* Update the task switch window configuration */
+            SendMessage(m_TaskSwitch, TSWM_UPDATETASKBARPOS, 0, 0);
+        }
+    }
 
-        case ID_SHELL_CMD_TILE_WND_H:
-            TileWindows(NULL, MDITILE_HORIZONTAL, NULL, 0, NULL);
-            break;
+    void FitToRebar(PRECT pRect)
+    {
+        /* Get the rect of the rebar */
+        RECT rebarRect, taskbarRect, clientRect;
+        ::GetWindowRect(m_Rebar, &rebarRect);
+        ::GetWindowRect(m_hWnd, &taskbarRect);
+        ::GetClientRect(m_hWnd, &clientRect);
+        OffsetRect(&rebarRect, -taskbarRect.left, -taskbarRect.top);
 
-        case ID_SHELL_CMD_TILE_WND_V:
-            TileWindows(NULL, MDITILE_VERTICAL, NULL, 0, NULL);
-            break;
+        /* Calculate the difference of size of the taskbar and the rebar */
+        SIZE margins;
+        margins.cx = taskbarRect.right - taskbarRect.left - clientRect.right + clientRect.left;
+        margins.cy = taskbarRect.bottom - taskbarRect.top - clientRect.bottom + clientRect.top;
 
-        case ID_SHELL_CMD_CASCADE_WND:
-            CascadeWindows(NULL, MDITILE_SKIPDISABLED, NULL, 0, NULL);
+        /* Calculate the new size of the rebar and make it resize, then change the new taskbar size */
+        switch (m_Position)
+        {
+        case ABE_TOP:
+            rebarRect.bottom = rebarRect.top + pRect->bottom - pRect->top - margins.cy;
+            ::SendMessageW(m_Rebar, RB_SIZETORECT, RBSTR_CHANGERECT,  (LPARAM)&rebarRect);
+            pRect->bottom = pRect->top + rebarRect.bottom - rebarRect.top + margins.cy;
             break;
-
-        case ID_SHELL_CMD_CUST_NOTIF:
+        case ABE_BOTTOM:
+            rebarRect.top = rebarRect.bottom - (pRect->bottom - pRect->top - margins.cy);
+            ::SendMessageW(m_Rebar, RB_SIZETORECT, RBSTR_CHANGERECT,  (LPARAM)&rebarRect);
+            pRect->top = pRect->bottom - (rebarRect.bottom - rebarRect.top + margins.cy);
             break;
-
-        case ID_SHELL_CMD_ADJUST_DAT:
-            //FIXME: Use SHRunControlPanel
-            ShellExecuteW(m_hWnd, NULL, L"timedate.cpl", NULL, NULL, SW_NORMAL);
+        case ABE_LEFT:
+            rebarRect.right = rebarRect.left + (pRect->right - pRect->left - margins.cx);
+            ::SendMessageW(m_Rebar, RB_SIZETORECT, RBSTR_CHANGERECT,  (LPARAM)&rebarRect);
+            pRect->right = pRect->left + (rebarRect.right - rebarRect.left + margins.cx);
             break;
-
-        default:
-            TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd);
-            bHandled = FALSE;
+        case ABE_RIGHT:
+            rebarRect.left = rebarRect.right - (pRect->right - pRect->left - margins.cx);
+            ::SendMessageW(m_Rebar, RB_SIZETORECT, RBSTR_CHANGERECT,  (LPARAM)&rebarRect);
+            pRect->left = pRect->right - (rebarRect.right - rebarRect.left + margins.cx);
             break;
         }
 
-        return bHandled;
+        CalculateValidSize(m_Position, pRect);
     }
 
-    BOOL STDMETHODCALLTYPE Lock(IN BOOL bLock)
+    void PopupStartMenu()
     {
-        BOOL bPrevLock;
-
-        bPrevLock = Locked;
-        if (Locked != bLock)
+        if (m_StartMenuPopup != NULL)
         {
-            Locked = bLock;
+            POINTL pt;
+            RECTL rcExclude;
+            DWORD dwFlags = 0;
 
-            if (m_TrayBandSite != NULL)
+            if (m_StartButton.GetWindowRect((RECT*) &rcExclude))
             {
-                if (!SUCCEEDED(m_TrayBandSite->Lock(bLock)))
+                switch (m_Position)
                 {
-                    /* Reset?? */
-                    Locked = bPrevLock;
+                case ABE_BOTTOM:
+                    pt.x = rcExclude.left;
+                    pt.y = rcExclude.top;
+                    dwFlags |= MPPF_TOP;
+                    break;
+                case ABE_TOP:
+                    pt.x = rcExclude.left;
+                    pt.y = rcExclude.bottom;
+                    dwFlags |= MPPF_BOTTOM;
+                    break;
+                case ABE_LEFT:
+                    pt.x = rcExclude.right;
+                    pt.y = rcExclude.top;
+                    dwFlags |= MPPF_RIGHT;
+                    break;
+                case ABE_RIGHT:
+                    pt.x = rcExclude.left;
+                    pt.y = rcExclude.top;
+                    dwFlags |= MPPF_LEFT;
+                    break;
                 }
+
+                m_StartMenuPopup->Popup(&pt, &rcExclude, dwFlags);
+
+                m_StartButton.SendMessageW(BM_SETSTATE, TRUE, 0);
             }
         }
-
-        return bPrevLock;
     }
 
+    void ProcessMouseTracking()
+    {
+        RECT rcCurrent;
+        POINT pt;
+        BOOL over;
+        UINT state = m_AutoHideState;
+
+        GetCursorPos(&pt);
+        GetWindowRect(&rcCurrent);
+        over = PtInRect(&rcCurrent, pt);
+
+        if (m_StartButton.SendMessage( BM_GETSTATE, 0, 0) != BST_UNCHECKED)
+        {
+            over = TRUE;
+        }
+
+        if (over)
+        {
+            if (state == AUTOHIDE_HIDING)
+            {
+                TRACE("AutoHide cancelling hide.\n");
+                m_AutoHideState = AUTOHIDE_SHOWING;
+                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
+            }
+            else if (state == AUTOHIDE_HIDDEN)
+            {
+                TRACE("AutoHide starting show.\n");
+                m_AutoHideState = AUTOHIDE_SHOWING;
+                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_SHOW, NULL);
+            }
+        }
+        else
+        {
+            if (state == AUTOHIDE_SHOWING)
+            {
+                TRACE("AutoHide cancelling show.\n");
+                m_AutoHideState = AUTOHIDE_HIDING;
+                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
+            }
+            else if (state == AUTOHIDE_SHOWN)
+            {
+                TRACE("AutoHide starting hide.\n");
+                m_AutoHideState = AUTOHIDE_HIDING;
+                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL);
+            }
+
+            KillTimer(TIMER_ID_MOUSETRACK);
+        }
+    }
 
-    LRESULT DrawBackground(HDC hdc)
+    void ProcessAutoHide()
     {
-        RECT rect;
-        int partId;
+        RECT rc = m_TrayRects[m_Position];
+        INT w = m_TraySize.cx - GetSystemMetrics(SM_CXBORDER) * 2 - 1;
+        INT h = m_TraySize.cy - GetSystemMetrics(SM_CYBORDER) * 2 - 1;
 
-        GetClientRect(&rect);
+        TRACE("AutoHide Timer received for %u, rc=(%d, %d, %d, %d), w=%d, h=%d.\n", m_AutoHideState, rc.left, rc.top, rc.right, rc.bottom, w, h);
 
-        if (m_Theme)
+        switch (m_AutoHideState)
         {
-            GetClientRect(&rect);
+        case AUTOHIDE_HIDING:
             switch (m_Position)
             {
             case ABE_LEFT:
-                partId = TBP_BACKGROUNDLEFT;
+                m_AutoHideOffset.cy = 0;
+                m_AutoHideOffset.cx -= AUTOHIDE_SPEED_HIDE;
+                if (m_AutoHideOffset.cx < -w)
+                    m_AutoHideOffset.cx = -w;
                 break;
             case ABE_TOP:
-                partId = TBP_BACKGROUNDTOP;
+                m_AutoHideOffset.cx = 0;
+                m_AutoHideOffset.cy -= AUTOHIDE_SPEED_HIDE;
+                if (m_AutoHideOffset.cy < -h)
+                    m_AutoHideOffset.cy = -h;
                 break;
             case ABE_RIGHT:
-                partId = TBP_BACKGROUNDRIGHT;
+                m_AutoHideOffset.cy = 0;
+                m_AutoHideOffset.cx += AUTOHIDE_SPEED_HIDE;
+                if (m_AutoHideOffset.cx > w)
+                    m_AutoHideOffset.cx = w;
                 break;
             case ABE_BOTTOM:
-            default:
-                partId = TBP_BACKGROUNDBOTTOM;
+                m_AutoHideOffset.cx = 0;
+                m_AutoHideOffset.cy += AUTOHIDE_SPEED_HIDE;
+                if (m_AutoHideOffset.cy > h)
+                    m_AutoHideOffset.cy = h;
+                break;
+            }
+
+            if (m_AutoHideOffset.cx != w && m_AutoHideOffset.cy != h)
+            {
+                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
+                break;
+            }
+
+            /* fallthrough */
+        case AUTOHIDE_HIDDEN:
+
+            switch (m_Position)
+            {
+            case ABE_LEFT:
+                m_AutoHideOffset.cx = -w;
+                m_AutoHideOffset.cy = 0;
+                break;
+            case ABE_TOP:
+                m_AutoHideOffset.cx = 0;
+                m_AutoHideOffset.cy = -h;
+                break;
+            case ABE_RIGHT:
+                m_AutoHideOffset.cx = w;
+                m_AutoHideOffset.cy = 0;
+                break;
+            case ABE_BOTTOM:
+                m_AutoHideOffset.cx = 0;
+                m_AutoHideOffset.cy = h;
+                break;
+            }
+
+            KillTimer(TIMER_ID_AUTOHIDE);
+            m_AutoHideState = AUTOHIDE_HIDDEN;
+            break;
+
+        case AUTOHIDE_SHOWING:
+            if (m_AutoHideOffset.cx >= AUTOHIDE_SPEED_SHOW)
+            {
+                m_AutoHideOffset.cx -= AUTOHIDE_SPEED_SHOW;
+            }
+            else if (m_AutoHideOffset.cx <= -AUTOHIDE_SPEED_SHOW)
+            {
+                m_AutoHideOffset.cx += AUTOHIDE_SPEED_SHOW;
+            }
+            else
+            {
+                m_AutoHideOffset.cx = 0;
+            }
+
+            if (m_AutoHideOffset.cy >= AUTOHIDE_SPEED_SHOW)
+            {
+                m_AutoHideOffset.cy -= AUTOHIDE_SPEED_SHOW;
+            }
+            else if (m_AutoHideOffset.cy <= -AUTOHIDE_SPEED_SHOW)
+            {
+                m_AutoHideOffset.cy += AUTOHIDE_SPEED_SHOW;
+            }
+            else
+            {
+                m_AutoHideOffset.cy = 0;
+            }
+
+            if (m_AutoHideOffset.cx != 0 || m_AutoHideOffset.cy != 0)
+            {
+                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
                 break;
             }
 
-            DrawThemeBackground(m_Theme, hdc, partId, 0, &rect, 0);
+            /* fallthrough */
+        case AUTOHIDE_SHOWN:
+
+            KillTimer(TIMER_ID_AUTOHIDE);
+            m_AutoHideState = AUTOHIDE_SHOWN;
+            break;
         }
 
-        return TRUE;
+        rc.left += m_AutoHideOffset.cx;
+        rc.right += m_AutoHideOffset.cx;
+        rc.top += m_AutoHideOffset.cy;
+        rc.bottom += m_AutoHideOffset.cy;
+
+        TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc.left, rc.top, rc.right, rc.bottom, m_AutoHideState);
+        SetWindowPos(NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE | SWP_NOZORDER);
     }
 
-    LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+
+
+
+
+    /**********************************************************
+     *    ##### taskbar drawing #####
+     */
+
+    LRESULT EraseBackgroundWithTheme(HDC hdc)
     {
-        HDC hdc = (HDC) wParam;
+        RECT rect;
+        int iSBkgndPart[4] = {TBP_BACKGROUNDLEFT, TBP_BACKGROUNDTOP, TBP_BACKGROUNDRIGHT, TBP_BACKGROUNDBOTTOM};
 
-        if (!m_Theme)
+        ASSERT(m_Position <= ABE_BOTTOM);
+
+        if (m_Theme)
         {
-            bHandled = FALSE;
-            return 0;
+            GetClientRect(&rect);
+            DrawThemeBackground(m_Theme, hdc, iSBkgndPart[m_Position], 0, &rect, 0);
         }
 
-        return DrawBackground(hdc);
+        return 0;
     }
 
-    int DrawSizer(IN HRGN hRgn)
+    int DrawSizerWithTheme(IN HRGN hRgn)
     {
         HDC hdc;
         RECT rect;
-        int backoundPart;
+        int iSizerPart[4] = {TBP_SIZINGBARLEFT, TBP_SIZINGBARTOP, TBP_SIZINGBARRIGHT, TBP_SIZINGBARBOTTOM};
+        SIZE size;
+
+        ASSERT(m_Position <= ABE_BOTTOM);
+
+        HRESULT hr = GetThemePartSize(m_Theme, NULL, iSizerPart[m_Position], 0, NULL, TS_TRUE, &size);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return 0;
 
-        GetWindowRect(m_hWnd, &rect);
+        GetWindowRect(&rect);
         OffsetRect(&rect, -rect.left, -rect.top);
 
-        hdc = GetDCEx(m_hWnd, hRgn, DCX_WINDOW | DCX_INTERSECTRGN | DCX_PARENTCLIP);
+        hdc = GetWindowDC();
 
         switch (m_Position)
         {
         case ABE_LEFT:
-            backoundPart = TBP_SIZINGBARLEFT;
-            rect.left = rect.right - GetSystemMetrics(SM_CXSIZEFRAME);
+            rect.left = rect.right - size.cx;
             break;
         case ABE_TOP:
-            backoundPart = TBP_SIZINGBARTOP;
-            rect.top = rect.bottom - GetSystemMetrics(SM_CYSIZEFRAME);
+            rect.top = rect.bottom - size.cy;
             break;
         case ABE_RIGHT:
-            backoundPart = TBP_SIZINGBARRIGHT;
-            rect.right = rect.left + GetSystemMetrics(SM_CXSIZEFRAME);
+            rect.right = rect.left + size.cx;
             break;
         case ABE_BOTTOM:
         default:
-            backoundPart = TBP_SIZINGBARBOTTOM;
-            rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZEFRAME);
+            rect.bottom = rect.top + size.cy;
             break;
         }
 
-        DrawThemeBackground(m_Theme, hdc, backoundPart, 0, &rect, 0);
+        DrawThemeBackground(m_Theme, hdc, iSizerPart[m_Position], 0, &rect, 0);
 
-        ReleaseDC(m_hWnd, hdc);
+        ReleaseDC(hdc);
         return 0;
     }
 
-    DWORD WINAPI RunFileDlgThread()
+
+
+
+
+    /*
+     * ITrayWindow
+     */
+    HRESULT STDMETHODCALLTYPE Open()
     {
-        HWND hwnd;
-        RECT posRect;
+        RECT rcWnd;
 
-        GetWindowRect(m_StartButton.m_hWnd, &posRect);
+        /* Check if there's already a window created and try to show it.
+           If it was somehow destroyed just create a new tray window. */
+        if (m_hWnd != NULL && IsWindow())
+        {
+            return S_OK;
+        }
 
-        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);
+        DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE;
+        if (AlwaysOnTop)
+            dwExStyle |= WS_EX_TOPMOST;
 
-        m_RunFileDlgOwner = hwnd;
+        DWORD dwStyle = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
+        if(!m_Theme)
+        {
+            dwStyle |= WS_THICKFRAME | WS_BORDER;
+        }
 
-        RunFileDlg(hwnd, NULL, NULL, NULL, NULL, RFF_CALCDIRECTORY);
+        ZeroMemory(&rcWnd, sizeof(rcWnd));
+        if (m_Position != (DWORD) -1)
+            rcWnd = m_TrayRects[m_Position];
 
-        m_RunFileDlgOwner = NULL;
-        ::DestroyWindow(hwnd);
+        if (!Create(NULL, rcWnd, NULL, dwStyle, dwExStyle))
+            return E_FAIL;
 
-        return 0;
-    }
+        /* Align all controls on the tray window */
+        AlignControls(NULL);
 
-    static DWORD WINAPI s_RunFileDlgThread(IN OUT PVOID pParam)
-    {
-        CTrayWindow * This = (CTrayWindow*) pParam;
-        return This->RunFileDlgThread();
+        /* Move the tray window to the right position and resize it if necessary */
+        CheckTrayWndPosition();
+
+        return S_OK;
     }
 
-    void DisplayRunFileDlg()
+    HRESULT STDMETHODCALLTYPE Close()
     {
-        HWND hRunDlg;
-        if (m_RunFileDlgOwner)
+        if (m_hWnd != NULL)
         {
-            hRunDlg = GetLastActivePopup(m_RunFileDlgOwner);
-            if (hRunDlg != NULL &&
-                hRunDlg != m_RunFileDlgOwner)
-            {
-                SetForegroundWindow(hRunDlg);
-                return;
-            }
+            SendMessage(m_hWnd,
+                        WM_APP_TRAYDESTROY,
+                        0,
+                        0);
         }
 
-        CloseHandle(CreateThread(NULL, 0, s_RunFileDlgThread, this, 0, NULL));
+        return S_OK;
     }
 
-    void PopupStartMenu()
+    HWND STDMETHODCALLTYPE GetHWND()
     {
-        if (m_StartMenuPopup != NULL)
-        {
-            POINTL pt;
-            RECTL rcExclude;
-            DWORD dwFlags = 0;
-
-            if (GetWindowRect(m_StartButton.m_hWnd, (RECT*) &rcExclude))
-            {
-                switch (m_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;
-                }
-
-                m_StartMenuPopup->Popup(&pt, &rcExclude, dwFlags);
+        return m_hWnd;
+    }
 
-                m_StartButton.SendMessageW(BM_SETSTATE, TRUE, 0);
-            }
-        }
+    BOOL STDMETHODCALLTYPE IsSpecialHWND(IN HWND hWnd)
+    {
+        return (m_hWnd == hWnd ||
+                (m_DesktopWnd != NULL && m_hWnd == m_DesktopWnd));
     }
 
-    void ProcessMouseTracking()
+    BOOL STDMETHODCALLTYPE IsHorizontal()
     {
-        RECT rcCurrent;
-        POINT pt;
-        BOOL over;
-        UINT state = m_AutoHideState;
+        return IsPosHorizontal();
+    }
 
-        GetCursorPos(&pt);
-        GetWindowRect(m_hWnd, &rcCurrent);
-        over = PtInRect(&rcCurrent, pt);
+    BOOL STDMETHODCALLTYPE Lock(IN BOOL bLock)
+    {
+        BOOL bPrevLock = Locked;
 
-        if (m_StartButton.SendMessage( BM_GETSTATE, 0, 0) != BST_UNCHECKED)
+        if (Locked != bLock)
         {
-            over = TRUE;
-        }
+            Locked = bLock;
 
-        if (over)
-        {
-            if (state == AUTOHIDE_HIDING)
+            if (m_TrayBandSite != NULL)
             {
-                TRACE("AutoHide cancelling hide.\n");
-                m_AutoHideState = AUTOHIDE_SHOWING;
-                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
+                if (!SUCCEEDED(m_TrayBandSite->Lock(bLock)))
+                {
+                    /* Reset?? */
+                    Locked = bPrevLock;
+                    return bPrevLock;
+                }
             }
-            else if (state == AUTOHIDE_HIDDEN)
+
+            if (m_Theme)
             {
-                TRACE("AutoHide starting show.\n");
-                m_AutoHideState = AUTOHIDE_SHOWING;
-                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_SHOW, NULL);
+                /* Update cached tray sizes */
+                for(DWORD Pos = ABE_LEFT; Pos <= ABE_BOTTOM; Pos++)
+                {
+                    RECT rcGripper = {0};
+                    AdjustSizerRect(&rcGripper, Pos);
+
+                    if(Locked)
+                    {
+                        m_TrayRects[Pos].top += rcGripper.top;
+                        m_TrayRects[Pos].left += rcGripper.left;
+                        m_TrayRects[Pos].bottom += rcGripper.bottom;
+                        m_TrayRects[Pos].right += rcGripper.right;
+                    }
+                    else
+                    {
+                        m_TrayRects[Pos].top -= rcGripper.top;
+                        m_TrayRects[Pos].left -= rcGripper.left;
+                        m_TrayRects[Pos].bottom -= rcGripper.bottom;
+                        m_TrayRects[Pos].right -= rcGripper.right;
+                    }
+                }
             }
+            SetWindowPos(NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER);
+            ResizeWorkArea();
+            ApplyClipping(TRUE);
         }
-        else
-        {
-            if (state == AUTOHIDE_SHOWING)
-            {
-                TRACE("AutoHide cancelling show.\n");
-                m_AutoHideState = AUTOHIDE_HIDING;
-                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
-            }
-            else if (state == AUTOHIDE_SHOWN)
-            {
-                TRACE("AutoHide starting hide.\n");
-                m_AutoHideState = AUTOHIDE_HIDING;
-                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL);
-            }
 
-            KillTimer(TIMER_ID_MOUSETRACK);
+        return bPrevLock;
+    }
+
+
+    /*
+     *  IContextMenu
+     */
+    HRESULT STDMETHODCALLTYPE QueryContextMenu(HMENU hPopup,
+                                               UINT indexMenu,
+                                               UINT idCmdFirst,
+                                               UINT idCmdLast,
+                                               UINT uFlags)
+    {
+        if (!m_ContextMenu)
+        {
+            HRESULT hr = TrayWindowCtxMenuCreator(this, m_hWnd, &m_ContextMenu);
+            if (FAILED_UNEXPECTEDLY(hr))
+                return hr;
         }
+
+        return m_ContextMenu->QueryContextMenu(hPopup, indexMenu, idCmdFirst, idCmdLast, uFlags);
     }
 
-    void ProcessAutoHide()
+    HRESULT STDMETHODCALLTYPE InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
     {
-        RECT rc = m_TrayRects[m_Position];
-        INT w = m_TraySize.cx - GetSystemMetrics(SM_CXBORDER) * 2 - 1;
-        INT h = m_TraySize.cy - GetSystemMetrics(SM_CYBORDER) * 2 - 1;
+        if (!m_ContextMenu)
+            return E_INVALIDARG;
 
-        TRACE("AutoHide Timer received for %u, rc=(%d, %d, %d, %d), w=%d, h=%d.\n", m_AutoHideState, rc.left, rc.top, rc.right, rc.bottom, w, h);
+        return m_ContextMenu->InvokeCommand(lpici);
+    }
 
-        switch (m_AutoHideState)
+    HRESULT STDMETHODCALLTYPE GetCommandString(UINT_PTR idCmd,
+                                               UINT uType,
+                                               UINT *pwReserved,
+                                               LPSTR pszName,
+                                               UINT cchMax)
+    {
+        if (!m_ContextMenu)
+            return E_INVALIDARG;
+
+        return m_ContextMenu->GetCommandString(idCmd, uType, pwReserved, pszName, cchMax);        
+    }
+
+
+    /**********************************************************
+     *    ##### message handling #####
+     */
+
+    LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        HRESULT hRet;
+
+        ((ITrayWindow*)this)->AddRef();
+
+        SetWindowTheme(m_hWnd, L"TaskBar", NULL);
+
+        /* Create the Start button */
+        m_StartButton.Create(m_hWnd);
+
+        /* Load the saved tray window settings */
+        RegLoadSettings();
+
+        /* Create and initialize the start menu */
+        HBITMAP hbmBanner = LoadBitmapW(hExplorerInstance, MAKEINTRESOURCEW(IDB_STARTMENU));
+        m_StartMenuPopup = CreateStartMenu(this, &m_StartMenuBand, hbmBanner, 0);
+
+        /* Create the task band */
+        hRet = CTaskBand_CreateInstance(this, m_StartButton.m_hWnd, IID_PPV_ARG(IDeskBand, &m_TaskBand));
+        if (FAILED_UNEXPECTEDLY(hRet))
+            return FALSE;
+
+        /* Create the rebar band site. This actually creates the rebar and the tasks toolbar. */
+        hRet = CTrayBandSite_CreateInstance(this, m_TaskBand, &m_TrayBandSite);
+        if (FAILED_UNEXPECTEDLY(hRet))
+            return FALSE;
+
+        /* Get the hwnd of the rebar */
+        hRet = IUnknown_GetWindow(m_TrayBandSite, &m_Rebar);
+        if (FAILED_UNEXPECTEDLY(hRet))
+            return FALSE;
+
+        /* Get the hwnd of the tasks toolbar */
+        hRet = IUnknown_GetWindow(m_TaskBand, &m_TaskSwitch);
+        if (FAILED_UNEXPECTEDLY(hRet))
+            return FALSE;
+
+        SetWindowTheme(m_Rebar, L"TaskBar", NULL);
+
+        /* Create the tray notification window */
+        m_TrayNotify = CreateTrayNotifyWnd(this, HideClock, &m_TrayNotifyInstance);
+
+        UpdateFonts();
+
+        InitShellServices(&m_ShellServices);
+
+        if (AutoHide)
         {
-        case AUTOHIDE_HIDING:
-            switch (m_Position)
-            {
-            case ABE_LEFT:
-                m_AutoHideOffset.cy = 0;
-                m_AutoHideOffset.cx -= AUTOHIDE_SPEED_HIDE;
-                if (m_AutoHideOffset.cx < -w)
-                    m_AutoHideOffset.cx = -w;
-                break;
-            case ABE_TOP:
-                m_AutoHideOffset.cx = 0;
-                m_AutoHideOffset.cy -= AUTOHIDE_SPEED_HIDE;
-                if (m_AutoHideOffset.cy < -h)
-                    m_AutoHideOffset.cy = -h;
-                break;
-            case ABE_RIGHT:
-                m_AutoHideOffset.cy = 0;
-                m_AutoHideOffset.cx += AUTOHIDE_SPEED_HIDE;
-                if (m_AutoHideOffset.cx > w)
-                    m_AutoHideOffset.cx = w;
-                break;
-            case ABE_BOTTOM:
-                m_AutoHideOffset.cx = 0;
-                m_AutoHideOffset.cy += AUTOHIDE_SPEED_HIDE;
-                if (m_AutoHideOffset.cy > h)
-                    m_AutoHideOffset.cy = h;
-                break;
-            }
+            m_AutoHideState = AUTOHIDE_HIDING;
+            SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL);
+        }
+
+        RegisterHotKey(m_hWnd, IDHK_RUN, MOD_WIN, 'R');
+        RegisterHotKey(m_hWnd, IDHK_MINIMIZE_ALL, MOD_WIN, 'M');
+        RegisterHotKey(m_hWnd, IDHK_RESTORE_ALL, MOD_WIN|MOD_SHIFT, 'M');
+        RegisterHotKey(m_hWnd, IDHK_HELP, MOD_WIN, VK_F1);
+        RegisterHotKey(m_hWnd, IDHK_EXPLORE, MOD_WIN, 'E');
+        RegisterHotKey(m_hWnd, IDHK_FIND, MOD_WIN, 'F');
+        RegisterHotKey(m_hWnd, IDHK_FIND_COMPUTER, MOD_WIN|MOD_CONTROL, 'F');
+        RegisterHotKey(m_hWnd, IDHK_NEXT_TASK, MOD_WIN, VK_TAB);
+        RegisterHotKey(m_hWnd, IDHK_PREV_TASK, MOD_WIN|MOD_SHIFT, VK_TAB);
+        RegisterHotKey(m_hWnd, IDHK_SYS_PROPERTIES, MOD_WIN, VK_PAUSE);
+        RegisterHotKey(m_hWnd, IDHK_DESKTOP, MOD_WIN, 'D');
+        RegisterHotKey(m_hWnd, IDHK_PAGER, MOD_WIN, 'B');
 
-            if (m_AutoHideOffset.cx != w && m_AutoHideOffset.cy != h)
-            {
-                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
-                break;
-            }
+        return TRUE;
+    }
 
-            /* fallthrough */
-        case AUTOHIDE_HIDDEN:
+    LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        if (m_Theme)
+            CloseThemeData(m_Theme);
 
-            switch (m_Position)
-            {
-            case ABE_LEFT:
-                m_AutoHideOffset.cx = -w;
-                m_AutoHideOffset.cy = 0;
-                break;
-            case ABE_TOP:
-                m_AutoHideOffset.cx = 0;
-                m_AutoHideOffset.cy = -h;
-                break;
-            case ABE_RIGHT:
-                m_AutoHideOffset.cx = w;
-                m_AutoHideOffset.cy = 0;
-                break;
-            case ABE_BOTTOM:
-                m_AutoHideOffset.cx = 0;
-                m_AutoHideOffset.cy = h;
-                break;
-            }
+        m_Theme = OpenThemeData(m_hWnd, L"TaskBar");
 
-            KillTimer(TIMER_ID_AUTOHIDE);
-            m_AutoHideState = AUTOHIDE_HIDDEN;
-            break;
+        if (m_Theme)
+        {
+            SetWindowStyle(m_hWnd, WS_THICKFRAME | WS_BORDER, 0);
+        }
+        else
+        {
+            SetWindowStyle(m_hWnd, WS_THICKFRAME | WS_BORDER, WS_THICKFRAME | WS_BORDER);
+        }
+        SetWindowPos(NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
 
-        case AUTOHIDE_SHOWING:
-            if (m_AutoHideOffset.cx >= AUTOHIDE_SPEED_SHOW)
-            {
-                m_AutoHideOffset.cx -= AUTOHIDE_SPEED_SHOW;
-            }
-            else if (m_AutoHideOffset.cx <= -AUTOHIDE_SPEED_SHOW)
-            {
-                m_AutoHideOffset.cx += AUTOHIDE_SPEED_SHOW;
-            }
-            else
-            {
-                m_AutoHideOffset.cx = 0;
-            }
+        return TRUE;
+    }
 
-            if (m_AutoHideOffset.cy >= AUTOHIDE_SPEED_SHOW)
-            {
-                m_AutoHideOffset.cy -= AUTOHIDE_SPEED_SHOW;
-            }
-            else if (m_AutoHideOffset.cy <= -AUTOHIDE_SPEED_SHOW)
-            {
-                m_AutoHideOffset.cy += AUTOHIDE_SPEED_SHOW;
-            }
-            else
-            {
-                m_AutoHideOffset.cy = 0;
-            }
+    LRESULT OnSettingChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        if (wParam == SPI_SETNONCLIENTMETRICS)
+        {
+            SendMessage(m_TaskSwitch, uMsg, wParam, lParam);
+            UpdateFonts();
+            AlignControls(NULL);
+            CheckTrayWndPosition();
+        }
 
-            if (m_AutoHideOffset.cx != 0 || m_AutoHideOffset.cy != 0)
-            {
-                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
-                break;
-            }
+        return 0;
+    }
 
-            /* fallthrough */
-        case AUTOHIDE_SHOWN:
+    LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        HDC hdc = (HDC) wParam;
 
-            KillTimer(TIMER_ID_AUTOHIDE);
-            m_AutoHideState = AUTOHIDE_SHOWN;
-            break;
+        if (!m_Theme)
+        {
+            bHandled = FALSE;
+            return 0;
         }
 
-        rc.left += m_AutoHideOffset.cx;
-        rc.right += m_AutoHideOffset.cx;
-        rc.top += m_AutoHideOffset.cy;
-        rc.bottom += m_AutoHideOffset.cy;
-
-        TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc.left, rc.top, rc.right, rc.bottom, m_AutoHideState);
-        SetWindowPos(NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE | SWP_NOZORDER);
+        return EraseBackgroundWithTheme(hdc);
     }
 
     LRESULT OnDisplayChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
-        /* Load the saved tray window settings */
-        RegLoadSettings();
-
-        /* Move the tray window to the right position and resize it if neccessary */
+        /* Move the tray window to the right position and resize it if necessary */
         CheckTrayWndPosition();
 
-        /* Align all controls on the tray window */
-        AlignControls(NULL);
-
         return TRUE;
     }
 
@@ -2172,7 +2275,8 @@ ChangePos:
     {
         if (m_TrayNotify)
         {
-            TrayNotify_NotifyMsg(m_TrayNotifyInstance, wParam, lParam);
+            TRACE("WM_COPYDATA notify message received. Handling...\n");
+            return TrayNotify_NotifyIconCmd(m_TrayNotifyInstance, wParam, lParam);
         }
         return TRUE;
     }
@@ -2185,7 +2289,7 @@ ChangePos:
             return 0;
         }
 
-        return DrawSizer((HRGN) wParam);
+        return DrawSizerWithTheme((HRGN) wParam);
     }
 
     LRESULT OnCtlColorBtn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
@@ -2209,7 +2313,7 @@ ChangePos:
 
         SetLastError(ERROR_SUCCESS);
         if (GetClientRect(&rcClient) &&
-            (MapWindowPoints(m_hWnd, NULL, (LPPOINT) &rcClient, 2) != 0 || GetLastError() == ERROR_SUCCESS))
+            (MapWindowPoints(NULL, (LPPOINT) &rcClient, 2) != 0 || GetLastError() == ERROR_SUCCESS))
         {
             pt.x = (SHORT) LOWORD(lParam);
             pt.y = (SHORT) HIWORD(lParam);
@@ -2284,7 +2388,7 @@ ChangePos:
 
         if (!Locked)
         {
-            CalculateValidSize(m_Position, pRect);
+            FitToRebar(pRect);
         }
         else
         {
@@ -2310,7 +2414,6 @@ ChangePos:
     LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
         RECT rcClient;
-        InvalidateRect(NULL, TRUE);
         if (wParam == SIZE_RESTORED && lParam == 0)
         {
             ResizeWorkArea();
@@ -2352,7 +2455,7 @@ ChangePos:
         if (!Locked)
         {
             /* Apply clipping */
-            PostMessage(m_hWnd, WM_SIZE, SIZE_RESTORED, 0);
+            PostMessage(WM_SIZE, SIZE_RESTORED, 0);
         }
         return TRUE;
     }
@@ -2375,17 +2478,16 @@ ChangePos:
                 SC_MINIMIZE,
             };
             HMENU hSysMenu;
-            INT i;
-            UINT uId;
+            UINT i, uId;
 
             /* temporarily enable the system menu */
             SetWindowStyle(m_hWnd, WS_SYSMENU, WS_SYSMENU);
 
-            hSysMenu = GetSystemMenu(m_hWnd, FALSE);
+            hSysMenu = GetSystemMenu(FALSE);
             if (hSysMenu != NULL)
             {
                 /* Disable all items that are not relevant */
-                for (i = 0; i != sizeof(uidDisableItem) / sizeof(uidDisableItem[0]); i++)
+                for (i = 0; i < _countof(uidDisableItem); i++)
                 {
                     EnableMenuItem(hSysMenu,
                                    uidDisableItem[i],
@@ -2421,6 +2523,63 @@ ChangePos:
         return TRUE;
     }
 
+    LRESULT OnNcLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        /* This handler implements the trick that makes  the start button to 
+           get pressed when the user clicked left or below the button */
+
+        POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
+        WINDOWINFO wi = {sizeof(WINDOWINFO)};
+        RECT rcStartBtn;
+
+        bHandled = FALSE;
+
+        m_StartButton.GetWindowRect(&rcStartBtn);
+        GetWindowInfo(m_hWnd, &wi);
+
+        switch (m_Position)
+        {
+            case ABE_TOP:
+            case ABE_LEFT:
+            {
+                if (pt.x > rcStartBtn.right || pt.y > rcStartBtn.bottom)
+                    return 0;
+                break;
+            }
+            case ABE_RIGHT:
+            {
+                if (pt.x < rcStartBtn.left || pt.y > rcStartBtn.bottom)
+                    return 0;
+
+                if (rcStartBtn.right + (int)wi.cxWindowBorders * 2 + 1 < wi.rcWindow.right &&
+                    pt.x > rcStartBtn.right)
+                {
+                    return 0;
+                }
+                break;
+            }
+            case ABE_BOTTOM:
+            {
+                if (pt.x > rcStartBtn.right || pt.y < rcStartBtn.top)
+                {
+                    return 0;
+                }
+
+                if (rcStartBtn.bottom + (int)wi.cyWindowBorders * 2 + 1 < wi.rcWindow.bottom &&
+                    pt.y > rcStartBtn.bottom)
+                {
+                    return 0;
+                }
+
+                break;
+            }
+        }
+
+        bHandled = TRUE;
+        PopupStartMenu();
+        return 0;
+    }
+
     LRESULT OnNcRButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
         /* We want the user to be able to get a context menu even on the nonclient
@@ -2469,17 +2628,17 @@ ChangePos:
                 POINT ptClient = *ppt;
 
                 /* Convert the coordinates to client-coordinates */
-                MapWindowPoints(NULL, m_hWnd, &ptClient, 1);
+                ::MapWindowPoints(NULL, m_hWnd, &ptClient, 1);
 
-                hWndAtPt = ChildWindowFromPoint(m_hWnd, ptClient);
+                hWndAtPt = ChildWindowFromPoint(ptClient);
                 if (hWndAtPt != NULL &&
-                    (hWndAtPt == m_Rebar || IsChild(m_Rebar, hWndAtPt)))
+                    (hWndAtPt == m_Rebar || ::IsChild(m_Rebar, hWndAtPt)))
                 {
                     /* Check if the user clicked on the task switch window */
                     ptClient = *ppt;
-                    MapWindowPoints(NULL, m_Rebar, &ptClient, 1);
+                    ::MapWindowPoints(NULL, m_Rebar, &ptClient, 1);
 
-                    hWndAtPt = ChildWindowFromPointEx(m_Rebar, ptClient, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED);
+                    hWndAtPt = ::ChildWindowFromPointEx(m_Rebar, ptClient, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED);
                     if (hWndAtPt == m_TaskSwitch)
                         goto HandleTrayContextMenu;
 
@@ -2493,9 +2652,7 @@ ChangePos:
             {
 HandleTrayContextMenu:
                 /* Tray the default tray window context menu */
-                CComPtr<IContextMenu> ctxMenu;
-                TrayWindowCtxMenuCreator(this, m_hWnd, &ctxMenu);
-                TrackCtxMenu(ctxMenu, ppt, NULL, FALSE, this);
+                TrackCtxMenu(this, ppt, NULL, FALSE, this);
             }
         }
         return Ret;
@@ -2527,7 +2684,7 @@ HandleTrayContextMenu:
                 {
                 case NTNWM_REALIGN:
                     /* Cause all controls to be aligned */
-                    PostMessage(m_hWnd, WM_SIZE, SIZE_RESTORED, 0);
+                    PostMessage(WM_SIZE, SIZE_RESTORED, 0);
                     break;
                 }
             }
@@ -2570,7 +2727,7 @@ HandleTrayContextMenu:
         if (FAILED_UNEXPECTEDLY(hr))
             return FALSE;
 
-        if (IsWindowVisible(hwndStartMenu))
+        if (::IsWindowVisible(hwndStartMenu))
         {
             m_StartMenuPopup->OnSelect(MPOS_CANCELLEVEL);
         }
@@ -2582,17 +2739,12 @@ HandleTrayContextMenu:
         return TRUE;
     }
 
-    LRESULT DoExitWindows()
-    {
-        ExitWindowsDialog(m_hWnd);
-        return 0;
-    }
-
     LRESULT OnDoExitWindows(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
-        /* 
-         * TWM_DOEXITWINDOWS is send by the CDesktopBrowserr to us to 
-         * show the shutdown dialog
+        /*
+         * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us
+         * to show the shutdown dialog. Also a WM_CLOSE message sent
+         * by apps should show the dialog.
          */
         return DoExitWindows();
     }
@@ -2608,68 +2760,9 @@ HandleTrayContextMenu:
         return TRUE;
     }
 
-    HRESULT ExecResourceCmd(int id)
-    {
-        WCHAR szCommand[256];
-        WCHAR *pszParameters;
-
-        if (!LoadString(hExplorerInstance,
-                        id,
-                        szCommand,
-                        sizeof(szCommand) / sizeof(szCommand[0])))
-        {
-            return E_FAIL;
-        }
-
-        pszParameters = wcschr(szCommand, L'>');
-        if (!pszParameters)
-            return E_FAIL;
-
-        *pszParameters = 0;
-        pszParameters++;
-
-        ShellExecuteW(m_hWnd, NULL, szCommand, pszParameters, NULL, 0);
-        return S_OK;
-    }
-
     LRESULT OnHotkey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
-        switch (wParam)
-        {
-        case IDHK_RUN:
-            DisplayRunFileDlg();
-            break;
-        case IDHK_HELP:
-            ExecResourceCmd(IDS_HELP_COMMAND);
-            break;
-        case IDHK_EXPLORE:
-            ShellExecuteW(0, L"explore", NULL, NULL, NULL, 1); 
-            break;
-        case IDHK_FIND:
-            SHFindFiles(NULL, NULL);
-            break;
-        case IDHK_FIND_COMPUTER:
-            SHFindComputer(NULL, NULL);
-            break;
-        case IDHK_SYS_PROPERTIES:
-            //FIXME: Use SHRunControlPanel
-            ShellExecuteW(m_hWnd, NULL, L"sysdm.cpl", NULL, NULL, SW_NORMAL);
-            break;
-        case IDHK_NEXT_TASK:
-            break;
-        case IDHK_PREV_TASK:
-            break;
-        case IDHK_MINIMIZE_ALL:
-            break;
-        case IDHK_RESTORE_ALL:
-            break;
-        case IDHK_DESKTOP:
-            break;
-        case IDHK_PAGER:
-            break;
-        }
-
-        return 0;
+        return HandleHotKey(wParam);
     }
 
     LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
@@ -2678,42 +2771,12 @@ HandleTrayContextMenu:
 
         if ((HWND) lParam == m_StartButton.m_hWnd)
         {
-            PopupStartMenu();
             return FALSE;
         }
 
         if (m_TrayBandSite == NULL || FAILED_UNEXPECTEDLY(m_TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret)))
         {
-            switch (LOWORD(wParam))
-            {
-                /* FIXME: Handle these commands as well */
-            case IDM_TASKBARANDSTARTMENU:
-                DisplayProperties();
-                break;
-
-            case IDM_SEARCH:
-                SHFindFiles(NULL, NULL);
-                break;
-
-            case IDM_HELPANDSUPPORT:
-                ExecResourceCmd(IDS_HELP_COMMAND);
-                break;
-
-            case IDM_RUN:
-                DisplayRunFileDlg();
-                break;
-
-                /* FIXME: Handle these commands as well */
-            case IDM_SYNCHRONIZE:
-            case IDM_LOGOFF:
-            case IDM_DISCONNECT:
-            case IDM_UNDOCKCOMPUTER:
-                break;
-
-            case IDM_SHUTDOWN:
-                DoExitWindows();
-                break;
-            }
+            return HandleCommand(LOWORD(wParam));
         }
         return Ret;
     }
@@ -2743,6 +2806,35 @@ HandleTrayContextMenu:
         return TRUE;
     }
 
+    LRESULT OnNcCalcSize(INT code, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        RECT *rc = NULL;
+        /* Ignore WM_NCCALCSIZE if we are not themed or locked */
+        if(!m_Theme || Locked)
+        {
+            bHandled = FALSE;
+            return 0;
+        }
+        if(!wParam)
+        {
+            rc = (RECT*)wParam;
+        }
+        else
+        {
+            NCCALCSIZE_PARAMS *prms = (NCCALCSIZE_PARAMS*)lParam;
+            if(prms->lppos->flags & SWP_NOSENDCHANGING)
+            {
+                bHandled = FALSE;
+                return 0;
+            }
+            rc = &prms->rgrc[0];
+        }
+
+        AdjustSizerRect(rc, m_Position);
+
+        return 0;
+    }
+
     LRESULT OnRebarAutoSize(INT code, LPNMHDR nmhdr, BOOL& bHandled)
     {
 #if 0
@@ -2816,6 +2908,7 @@ HandleTrayContextMenu:
             lParam = Msg.lParam;
         }
         MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged)
+        MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChanged)
         NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnRebarAutoSize) // Doesn't quite work ;P
         MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
         MESSAGE_HANDLER(WM_SIZE, OnSize)
@@ -2836,6 +2929,7 @@ HandleTrayContextMenu:
         MESSAGE_HANDLER(WM_WINDOWPOSCHANGING, OnWindowPosChange)
         MESSAGE_HANDLER(WM_ENTERSIZEMOVE, OnEnterSizeMove)
         MESSAGE_HANDLER(WM_EXITSIZEMOVE, OnExitSizeMove)
+        MESSAGE_HANDLER(WM_NCLBUTTONDOWN, OnNcLButtonDown)
         MESSAGE_HANDLER(WM_SYSCHAR, OnSysChar)
         MESSAGE_HANDLER(WM_NCRBUTTONUP, OnNcRButtonUp)
         MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblClick)
@@ -2844,7 +2938,9 @@ HandleTrayContextMenu:
         MESSAGE_HANDLER(WM_APP_TRAYDESTROY, OnAppTrayDestroy)
         MESSAGE_HANDLER(TWM_OPENSTARTMENU, OnOpenStartMenu)
         MESSAGE_HANDLER(TWM_DOEXITWINDOWS, OnDoExitWindows)
+        MESSAGE_HANDLER(WM_CLOSE, OnDoExitWindows)
         MESSAGE_HANDLER(WM_HOTKEY, OnHotkey)
+        MESSAGE_HANDLER(WM_NCCALCSIZE, OnNcCalcSize)
     ALT_MSG_MAP(1)
     END_MSG_MAP()
 
@@ -2937,6 +3033,19 @@ HandleTrayContextMenu:
         return S_OK;
     }
 
+    HRESULT WINAPI GetWindow(HWND* phwnd)
+    {
+        if (!phwnd)
+            return E_INVALIDARG;
+        *phwnd = m_hWnd;
+        return S_OK;
+    }
+
+    HRESULT WINAPI ContextSensitiveHelp(BOOL fEnterMode)
+    {
+        return E_NOTIMPL;
+    }
+
     void _Init()
     {
         m_Position = (DWORD) -1;
@@ -2948,6 +3057,8 @@ HandleTrayContextMenu:
     BEGIN_COM_MAP(CTrayWindow)
         /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
         COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray, IShellDesktopTray)
+        COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
+        COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
     END_COM_MAP()
 };
 
@@ -2959,12 +3070,14 @@ class CTrayWindowCtxMenu :
     HWND hWndOwner;
     CComPtr<CTrayWindow> TrayWnd;
     CComPtr<IContextMenu> pcm;
+    UINT m_idCmdCmFirst;
 
 public:
     HRESULT Initialize(ITrayWindow * pTrayWnd, IN HWND hWndOwner)
     {
         this->TrayWnd = (CTrayWindow *) pTrayWnd;
         this->hWndOwner = hWndOwner;
+        this->m_idCmdCmFirst = 0;
         return S_OK;
     }
 
@@ -2975,34 +3088,10 @@ public:
                          UINT idCmdLast,
                          UINT uFlags)
     {
-        HMENU menubase = LoadPopupMenu(hExplorerInstance, MAKEINTRESOURCE(IDM_TRAYWND));
-
+        HMENU menubase = LoadPopupMenu(hExplorerInstance, MAKEINTRESOURCEW(IDM_TRAYWND));
         if (!menubase)
             return HRESULT_FROM_WIN32(GetLastError());
 
-        int count = ::GetMenuItemCount(menubase);
-
-        for (int i = 0; i < count; i++)
-        {
-            WCHAR label[128];
-
-            MENUITEMINFOW mii = { 0 };
-            mii.cbSize = sizeof(mii);
-            mii.fMask = MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS 
-                | MIIM_DATA | MIIM_STRING | MIIM_BITMAP | MIIM_FTYPE;
-            mii.dwTypeData = label;
-            mii.cch = _countof(label);
-            ::GetMenuItemInfoW(menubase, i, TRUE, &mii);
-
-            TRACE("Adding item %d label %S type %d\n", mii.wID, mii.dwTypeData, mii.fType);
-
-            mii.fType |= MFT_RADIOCHECK;
-
-            ::InsertMenuItemW(hPopup, i + 1, TRUE, &mii);
-        }
-
-        ::DestroyMenu(menubase);
-
         if (SHRestricted(REST_CLASSICSHELL) != 0)
         {
             DeleteMenu(hPopup,
@@ -3014,13 +3103,19 @@ public:
                       ID_LOCKTASKBAR,
                       MF_BYCOMMAND | (TrayWnd->Locked ? MF_CHECKED : MF_UNCHECKED));
 
+        UINT idCmdNext;
+        idCmdNext = Shell_MergeMenus(hPopup, menubase, indexMenu, idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS | MM_ADDSEPARATOR);
+        m_idCmdCmFirst = idCmdNext - idCmdFirst;
+
+        ::DestroyMenu(menubase);
+
         if (TrayWnd->m_TrayBandSite != NULL)
         {
             if (FAILED(TrayWnd->m_TrayBandSite->AddContextMenus(
                 hPopup,
-                0,
-                ID_SHELL_CMD_FIRST,
-                ID_SHELL_CMD_LAST,
+                indexMenu,
+                idCmdNext,
+                idCmdLast,
                 CMF_NORMAL,
                 &pcm)))
             {
@@ -3038,7 +3133,7 @@ public:
         UINT uiCmdId = (UINT) lpici->lpVerb;
         if (uiCmdId != 0)
         {
-            if (uiCmdId >= ID_SHELL_CMD_FIRST && uiCmdId <= ID_SHELL_CMD_LAST)
+            if (uiCmdId >= m_idCmdCmFirst)
             {
                 CMINVOKECOMMANDINFO cmici = { 0 };
 
@@ -3047,7 +3142,7 @@ public:
                     /* Setup and invoke the shell command */
                     cmici.cbSize = sizeof(cmici);
                     cmici.hwnd = hWndOwner;
-                    cmici.lpVerb = (LPCSTR) MAKEINTRESOURCE(uiCmdId - ID_SHELL_CMD_FIRST);
+                    cmici.lpVerb = (LPCSTR) MAKEINTRESOURCEW(uiCmdId - m_idCmdCmFirst);
                     cmici.nShow = SW_NORMAL;
 
                     pcm->InvokeCommand(&cmici);