[EXPLORER][SHELL32][USER32] Implement 'Show the Desktop' action of Task Bar (#668)
[reactos.git] / base / shell / explorer / traywnd.cpp
index 74a9068..8fd6c55 100644 (file)
@@ -2,6 +2,7 @@
  * ReactOS Explorer
  *
  * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
+ * Copyright 2018 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
  *
  * this library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,6 +21,7 @@
 
 #include "precomp.h"
 #include <commoncontrols.h>
+#include <traycmd.h>
 
 HRESULT TrayWindowCtxMenuCreator(ITrayWindow * TrayWnd, IN HWND hWndOwner, IContextMenu ** ppCtxMenu);
 
@@ -53,9 +55,79 @@ HRESULT TrayWindowCtxMenuCreator(ITrayWindow * TrayWnd, IN HWND hWndOwner, ICont
 #define IDHK_DESKTOP 0x1fe
 #define IDHK_PAGER 0x1ff
 
-static LONG TrayWndCount = 0;
+static const WCHAR szTrayWndClass[] = L"Shell_TrayWnd";
 
-static const WCHAR szTrayWndClass [] = TEXT("Shell_TrayWnd");
+struct EFFECTIVE_INFO
+{
+    HWND hwndFound;
+    HWND hwndDesktop;
+    HWND hwndProgman;
+    HWND hTrayWnd;
+    BOOL bMustBeInMonitor;
+};
+
+static BOOL CALLBACK
+FindEffectiveProc(HWND hwnd, LPARAM lParam)
+{
+    EFFECTIVE_INFO *pei = (EFFECTIVE_INFO *)lParam;
+
+    if (!IsWindowVisible(hwnd) || IsIconic(hwnd))
+        return TRUE;    // continue
+
+    if (pei->hTrayWnd == hwnd || pei->hwndDesktop == hwnd ||
+        pei->hwndProgman == hwnd)
+    {
+        return TRUE;    // continue
+    }
+
+    if (pei->bMustBeInMonitor)
+    {
+        // is the window in the nearest monitor?
+        HMONITOR hMon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
+        if (hMon)
+        {
+            MONITORINFO info;
+            ZeroMemory(&info, sizeof(info));
+            info.cbSize = sizeof(info);
+            if (GetMonitorInfoW(hMon, &info))
+            {
+                RECT rcWindow, rcMonitor, rcIntersect;
+                rcMonitor = info.rcMonitor;
+
+                GetWindowRect(hwnd, &rcWindow);
+
+                if (!IntersectRect(&rcIntersect, &rcMonitor, &rcWindow))
+                    return TRUE;    // continue
+            }
+        }
+    }
+
+    pei->hwndFound = hwnd;
+    return FALSE;   // stop if found
+}
+
+static BOOL
+IsThereAnyEffectiveWindow(BOOL bMustBeInMonitor)
+{
+    EFFECTIVE_INFO ei;
+    ei.hwndFound = NULL;
+    ei.hwndDesktop = GetDesktopWindow();
+    ei.hTrayWnd = FindWindowW(L"Shell_TrayWnd", NULL);
+    ei.hwndProgman = FindWindowW(L"Progman", NULL);
+    ei.bMustBeInMonitor = bMustBeInMonitor;
+
+    EnumWindows(FindEffectiveProc, (LPARAM)&ei);
+    if (ei.hwndFound && FALSE)
+    {
+        WCHAR szClass[64], szText[64];
+        GetClassNameW(ei.hwndFound, szClass, _countof(szClass));
+        GetWindowTextW(ei.hwndFound, szText, _countof(szText));
+        MessageBoxW(NULL, szText, szClass, 0);
+    }
+    return ei.hwndFound != NULL;
+}
+
+CSimpleArray<HWND>  g_MinimizedAll;
 
 /*
  * ITrayWindow
@@ -63,66 +135,182 @@ 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 CWindowImpl<CStartButton>
+{
+    HIMAGELIST m_ImageList;
+    SIZE       m_Size;
+    HFONT      m_Font;
+
+public:
+    CStartButton()
+        : m_ImageList(NULL),
+          m_Font(NULL)
+    {
+        m_Size.cx = 0;
+        m_Size.cy = 0;
+    }
+
+    virtual ~CStartButton()
+    {
+        if (m_ImageList != NULL)
+            ImageList_Destroy(m_ImageList);
+
+        if (m_Font != NULL)
+            DeleteObject(m_Font);
+    }
+
+    SIZE GetSize()
+    {
+        return m_Size;
+    }
+
+    VOID UpdateSize()
+    {
+        SIZE Size = { 0, 0 };
+
+        if (m_ImageList == NULL ||
+            !SendMessageW(BCM_GETIDEALSIZE, 0, (LPARAM) &Size))
+        {
+            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;
+    }
+
+    VOID UpdateFont()
+    {
+        /* 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;
+
+        if (m_Font)
+            DeleteObject(m_Font);
+
+        ncm.lfCaptionFont.lfWeight = FW_BOLD;
+        m_Font = CreateFontIndirect(&ncm.lfCaptionFont);
+
+        SetFont(m_Font, FALSE);
+    }
+
+    VOID Initialize()
+    {
+        SubclassWindow(m_hWnd);
+        SetWindowTheme(m_hWnd, L"Start", NULL);
+
+        m_ImageList = ImageList_LoadImageW(hExplorerInstance,
+                                           MAKEINTRESOURCEW(IDB_START),
+                                           0, 0, 0,
+                                           IMAGE_BITMAP,
+                                           LR_LOADTRANSPARENT | LR_CREATEDIBSECTION);
+
+        BUTTON_IMAGELIST bil = {m_ImageList, {1,1,1,1}, BUTTON_IMAGELIST_ALIGN_LEFT};
+        SendMessageW(BCM_SETIMAGELIST, 0, (LPARAM) &bil);
+        UpdateSize();
+    }
+
+    HWND Create(HWND hwndParent)
+    {
+        WCHAR szStartCaption[32];
+        if (!LoadStringW(hExplorerInstance,
+                         IDS_START,
+                         szStartCaption,
+                         _countof(szStartCaption)))
+        {
+            wcscpy(szStartCaption, L"Start");
+        }
+
+        DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | BS_PUSHBUTTON | BS_LEFT | BS_VCENTER;
+
+        m_hWnd = CreateWindowEx(
+            0,
+            WC_BUTTON,
+            szStartCaption,
+            dwStyle,
+            0, 0, 0, 0,
+            hwndParent,
+            (HMENU) IDC_STARTBTN,
+            hExplorerInstance,
+            NULL);
+
+        if (m_hWnd)
+            Initialize();
+
+        return m_hWnd;
+    }
+
+    LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        if (uMsg == WM_KEYUP && wParam != VK_SPACE)
+            return 0;
+
+        GetParent().PostMessage(TWM_OPENSTARTMENU);
+        return 0;
+    }
+
+    BEGIN_MSG_MAP(CStartButton)
+        MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
+    END_MSG_MAP()
+
+};
+
 class CTrayWindow :
     public CComCoClass<CTrayWindow>,
     public CComObjectRootEx<CComMultiThreadModelNoCS>,
     public CWindowImpl < CTrayWindow, CWindow, CControlWinTraits >,
     public ITrayWindow,
-    public IShellDesktopTray
+    public IShellDesktopTray,
+    public IOleWindow,
+    public IContextMenu
 {
-    CContainedWindow StartButton;
+    CStartButton m_StartButton;
 
-    HTHEME TaskbarTheme;
-    HWND hWndDesktop;
+    CComPtr<IMenuBand>  m_StartMenuBand;
+    CComPtr<IMenuPopup> m_StartMenuPopup;
 
-    IImageList * himlStartBtn;
-    SIZE StartBtnSize;
-    HFONT hStartBtnFont;
-    HFONT hCaptionFont;
+    CComPtr<IDeskBand> m_TaskBand;
+    CComPtr<IContextMenu> m_ContextMenu;
+    HTHEME m_Theme;
 
-    HWND hwndRebar;
-    HWND hwndTaskSwitch;
-    HWND hwndTrayNotify;
+    HFONT m_Font;
 
-    DWORD Position;
-    HMONITOR Monitor;
-    HMONITOR PreviousMonitor;
-    DWORD DraggingPosition;
-    HMONITOR DraggingMonitor;
+    HWND m_DesktopWnd;
+    HWND m_Rebar;
+    HWND m_TaskSwitch;
+    HWND m_TrayNotify;
 
-    RECT rcTrayWnd[4];
-    RECT rcNewPosSize;
-    SIZE TraySize;
+    CComPtr<IUnknown> m_TrayNotifyInstance;
 
-    NONCLIENTMETRICS ncm;
-    HFONT hFont;
+    DWORD    m_Position;
+    HMONITOR m_Monitor;
+    HMONITOR m_PreviousMonitor;
+    DWORD    m_DraggingPosition;
+    HMONITOR m_DraggingMonitor;
 
-    CComPtr<IMenuBand> StartMenuBand;
-    CComPtr<IMenuPopup> StartMenuPopup;
-    HBITMAP hbmStartMenu;
+    RECT m_TrayRects[4];
+    SIZE m_TraySize;
 
-    HWND hwndTrayPropertiesOwner;
-    HWND hwndRunFileDlgOwner;
+    HWND m_TrayPropertiesOwner;
+    HWND m_RunFileDlgOwner;
 
-    UINT AutoHideState;
-    SIZE AutoHideOffset;
-    TRACKMOUSEEVENT MouseTrackingInfo;
+    UINT m_AutoHideState;
+    SIZE m_AutoHideOffset;
+    TRACKMOUSEEVENT m_MouseTrackingInfo;
 
-    HDPA hdpaShellServices;
+    HDPA m_ShellServices;
 
 public:
-    CComPtr<ITrayBandSite> TrayBandSite;
+    CComPtr<ITrayBandSite> m_TrayBandSite;
+
     union
     {
         DWORD Flags;
         struct
         {
-            DWORD AutoHide : 1;
-            DWORD AlwaysOnTop : 1;
-            DWORD SmSmallIcons : 1;
-            DWORD HideClock : 1;
-            DWORD Locked : 1;
-
             /* UI Status */
             DWORD InSizeMove : 1;
             DWORD IsDragging : 1;
@@ -132,820 +320,456 @@ public:
 
 public:
     CTrayWindow() :
-        StartButton(this, 1),
-        TaskbarTheme(NULL),
-        hWndDesktop(NULL),
-        himlStartBtn(NULL),
-        hStartBtnFont(NULL),
-        hCaptionFont(NULL),
-        hwndRebar(NULL),
-        hwndTaskSwitch(NULL),
-        hwndTrayNotify(NULL),
-        Position(0),
-        Monitor(NULL),
-        PreviousMonitor(NULL),
-        DraggingPosition(0),
-        DraggingMonitor(NULL),
-        hFont(NULL),
-        hbmStartMenu(NULL),
-        hwndTrayPropertiesOwner(NULL),
-        hwndRunFileDlgOwner(NULL),
-        AutoHideState(NULL),
-        hdpaShellServices(NULL),
+        m_StartButton(),
+        m_Theme(NULL),
+        m_Font(NULL),
+        m_DesktopWnd(NULL),
+        m_Rebar(NULL),
+        m_TaskSwitch(NULL),
+        m_TrayNotify(NULL),
+        m_Position(0),
+        m_Monitor(NULL),
+        m_PreviousMonitor(NULL),
+        m_DraggingPosition(0),
+        m_DraggingMonitor(NULL),
+        m_TrayPropertiesOwner(NULL),
+        m_RunFileDlgOwner(NULL),
+        m_AutoHideState(NULL),
+        m_ShellServices(NULL),
         Flags(0)
     {
-        ZeroMemory(&StartBtnSize, sizeof(StartBtnSize));
-        ZeroMemory(&rcTrayWnd, sizeof(rcTrayWnd));
-        ZeroMemory(&rcNewPosSize, sizeof(rcNewPosSize));
-        ZeroMemory(&TraySize, sizeof(TraySize));
-        ZeroMemory(&ncm, sizeof(ncm));
-        ZeroMemory(&AutoHideOffset, sizeof(AutoHideOffset));
-        ZeroMemory(&MouseTrackingInfo, sizeof(MouseTrackingInfo));
+        ZeroMemory(&m_TrayRects, sizeof(m_TrayRects));
+        ZeroMemory(&m_TraySize, sizeof(m_TraySize));
+        ZeroMemory(&m_AutoHideOffset, sizeof(m_AutoHideOffset));
+        ZeroMemory(&m_MouseTrackingInfo, sizeof(m_MouseTrackingInfo));
     }
 
     virtual ~CTrayWindow()
     {
-        (void) InterlockedExchangePointer((PVOID*) &m_hWnd, NULL);
-
-
-        if (hdpaShellServices != NULL)
+        if (m_ShellServices != NULL)
         {
-            ShutdownShellServices(hdpaShellServices);
-            hdpaShellServices = NULL;
+            ShutdownShellServices(m_ShellServices);
+            m_ShellServices = NULL;
         }
 
-        if (himlStartBtn != NULL)
+        if (m_Font != NULL)
         {
-            himlStartBtn->Release();
-            himlStartBtn = NULL;
+            DeleteObject(m_Font);
+            m_Font = NULL;
         }
 
-        if (hCaptionFont != NULL)
+        if (m_Theme)
         {
-            DeleteObject(hCaptionFont);
-            hCaptionFont = NULL;
+            CloseThemeData(m_Theme);
+            m_Theme = NULL;
         }
 
-        if (hStartBtnFont != NULL)
-        {
-            DeleteObject(hStartBtnFont);
-            hStartBtnFont = NULL;
-        }
+        PostQuitMessage(0);
+    }
 
-        if (hFont != NULL)
-        {
-            DeleteObject(hFont);
-            hFont = NULL;
-        }
 
-        if (hbmStartMenu != NULL)
-        {
-            DeleteObject(hbmStartMenu);
-            hbmStartMenu = NULL;
-        }
 
-        if (TaskbarTheme)
-        {
-            CloseThemeData(TaskbarTheme);
-            TaskbarTheme = NULL;
-        }
 
-        if (InterlockedDecrement(&TrayWndCount) == 0)
-            PostQuitMessage(0);
-    }
 
-    /*
-     * ITrayWindow
+    /**********************************************************
+     *    ##### command handling #####
      */
 
-    BOOL UpdateNonClientMetrics()
+    HRESULT ExecResourceCmd(int id)
     {
-        ncm.cbSize = sizeof(ncm);
-        if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
+        WCHAR szCommand[256];
+        WCHAR *pszParameters;
+
+        if (!LoadStringW(hExplorerInstance,
+                         id,
+                         szCommand,
+                         _countof(szCommand)))
         {
-            if (hFont != NULL)
-                DeleteObject(hFont);
+            return E_FAIL;
+        }
 
-            hFont = CreateFontIndirect(&ncm.lfMessageFont);
-            return TRUE;
+        pszParameters = wcschr(szCommand, L'>');
+        if (pszParameters)
+        {
+            *pszParameters = 0;
+            pszParameters++;
         }
 
-        return FALSE;
+        ShellExecuteW(m_hWnd, NULL, szCommand, pszParameters, NULL, SW_SHOWNORMAL);
+        return S_OK;
     }
 
-    VOID SetWindowsFont()
+    LRESULT DoExitWindows()
     {
-        if (hwndTrayNotify != NULL)
+        /* Display the ReactOS Shutdown Dialog */
+        ExitWindowsDialog(m_hWnd);
+
+        /*
+         * If the user presses CTRL+ALT+SHIFT while exiting
+         * the shutdown dialog, exit the shell cleanly.
+         */
+        if ((GetKeyState(VK_CONTROL) & 0x8000) &&
+            (GetKeyState(VK_SHIFT)   & 0x8000) &&
+            (GetKeyState(VK_MENU)    & 0x8000))
         {
-            SendMessage(hwndTrayNotify, WM_SETFONT, (WPARAM) hFont, TRUE);
+            PostMessage(WM_QUIT, 0, 0);
         }
+        return 0;
     }
 
-    HMONITOR GetScreenRectFromRect(
-        IN OUT RECT *pRect,
-        IN DWORD dwFlags)
+    DWORD WINAPI RunFileDlgThread()
     {
-        MONITORINFO mi;
-        HMONITOR hMon;
-
-        mi.cbSize = sizeof(mi);
-        hMon = MonitorFromRect(pRect,
-                               dwFlags);
-        if (hMon != NULL &&
-            GetMonitorInfo(hMon,
-            &mi))
-        {
-            *pRect = mi.rcMonitor;
-        }
-        else
-        {
-            pRect->left = 0;
-            pRect->top = 0;
-            pRect->right = GetSystemMetrics(SM_CXSCREEN);
-            pRect->bottom = GetSystemMetrics(SM_CYSCREEN);
+        HWND hwnd;
+        RECT posRect;
 
-            hMon = NULL;
-        }
+        m_StartButton.GetWindowRect(&posRect);
 
-        return hMon;
-    }
+        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);
 
-    HMONITOR GetMonitorFromRect(
-        IN const RECT *pRect)
-    {
-        HMONITOR hMon;
+        m_RunFileDlgOwner = hwnd;
 
-        /* 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;
+        // build the default directory from two environment variables
+        CStringW strDefaultDir, strHomePath;
+        strDefaultDir.GetEnvironmentVariable(L"HOMEDRIVE");
+        strHomePath.GetEnvironmentVariable(L"HOMEPATH");
+        strDefaultDir += strHomePath;
 
-            pt.x = pRect->left + ((pRect->right - pRect->left) / 2);
-            pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2);
+        RunFileDlg(hwnd, NULL, (LPCWSTR)strDefaultDir, NULL, NULL, RFF_CALCDIRECTORY);
 
-            /* be less error-prone, find the nearest monitor */
-            hMon = MonitorFromPoint(pt,
-                                    MONITOR_DEFAULTTONEAREST);
-        }
+        m_RunFileDlgOwner = NULL;
+        ::DestroyWindow(hwnd);
 
-        return hMon;
+        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_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 = &TraySize;
+        CTrayWindow *This = (CTrayWindow*) pParam;
 
-        *pRect = *pScreen;
-
-        /* Move the border outside of the screen */
-        InflateRect(pRect,
-                    GetSystemMetrics(SM_CXEDGE),
-                    GetSystemMetrics(SM_CYEDGE));
-
-        MakeTrayRectWithSize(Position, pTraySize, pRect);
-    }
-
-    BOOL
-        IsPosHorizontal()
-    {
-        return Position == ABE_TOP || Position == ABE_BOTTOM;
-    }
-
-    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;
+        return This->TrayPropertiesThread();
     }
-#endif
-
 
-    DWORD
-        GetDraggingRectFromPt(
-        IN POINT pt,
-        OUT RECT *pRect,
-        OUT HMONITOR *phMonitor)
+    HWND STDMETHODCALLTYPE DisplayProperties()
     {
-        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);
+        HWND hTrayProp;
 
-        if (hMon != NULL)
+        if (m_TrayPropertiesOwner)
         {
-            MONITORINFO mi;
-
-            mi.cbSize = sizeof(mi);
-            if (!GetMonitorInfo(hMon,
-                &mi))
+            hTrayProp = ::GetLastActivePopup(m_TrayPropertiesOwner);
+            if (hTrayProp != NULL &&
+                hTrayProp != m_TrayPropertiesOwner)
             {
-                hMon = NULL;
-                goto GetPrimaryScreenRect;
+                SetForegroundWindow(hTrayProp);
+                return NULL;
             }
-
-            /* 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);
         }
 
-        /* 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;
-        }
-
-        if (pt.y < rcScreen.bottom / 2)
-        {
-            DeltaPt.cy = pt.y;
-            PosV = ABE_TOP;
-        }
-        else
-        {
-            DeltaPt.cy = rcScreen.bottom - pt.y;
-            PosV = ABE_BOTTOM;
-        }
-
-        Pos = (DeltaPt.cx * rcScreen.bottom < DeltaPt.cy * rcScreen.right) ? PosH : PosV;
-
-        /* Fix the screen origin to be relative to the primary monitor again */
-        OffsetRect(&rcScreen,
-                   ScreenOffset.cx,
-                   ScreenOffset.cy);
+        CloseHandle(CreateThread(NULL, 0, s_TrayPropertiesThread, this, 0, NULL));
+        return NULL;
+    }
 
-        hMonNew = GetMonitorFromRect(
-            &rcTrayWnd[Pos]);
-        if (hMon != hMonNew)
-        {
-            SIZE szTray;
+    VOID OpenCommonStartMenuDirectory(IN HWND hWndOwner, IN LPCTSTR lpOperation)
+    {
+        WCHAR szDir[MAX_PATH];
 
-            /* Recalculate the rectangle, we're dragging to another monitor.
-               We don't need to recalculate the rect on single monitor systems. */
-            szTray.cx = rcTrayWnd[Pos].right - rcTrayWnd[Pos].left;
-            szTray.cy = rcTrayWnd[Pos].bottom - rcTrayWnd[Pos].top;
-
-            GetTrayRectFromScreenRect(
-                Pos,
-                &rcScreen,
-                &szTray,
-                pRect);
-            if (AutoHide)
-            {
-                pRect->left += AutoHideOffset.cx;
-                pRect->right += AutoHideOffset.cx;
-                pRect->top += AutoHideOffset.cy;
-                pRect->bottom += AutoHideOffset.cy;
-            }
-            hMon = hMonNew;
-        }
-        else
+        if (SHGetSpecialFolderPath(hWndOwner,
+            szDir,
+            CSIDL_COMMON_STARTMENU,
+            FALSE))
         {
-            /* The user is dragging the tray window on the same monitor. We don't need
-               to recalculate the rectangle */
-            *pRect = rcTrayWnd[Pos];
-            if (AutoHide)
-            {
-                pRect->left += AutoHideOffset.cx;
-                pRect->right += AutoHideOffset.cx;
-                pRect->top += AutoHideOffset.cy;
-                pRect->bottom += AutoHideOffset.cy;
-            }
+            ShellExecute(hWndOwner,
+                         lpOperation,
+                         szDir,
+                         NULL,
+                         NULL,
+                         SW_SHOWNORMAL);
         }
-
-        *phMonitor = hMon;
-
-        return Pos;
     }
 
-    DWORD
-        GetDraggingRectFromRect(
-        IN OUT RECT *pRect,
-        OUT HMONITOR *phMonitor)
+    VOID OpenTaskManager(IN HWND hWndOwner)
     {
-        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);
+        ShellExecute(hWndOwner,
+                     TEXT("open"),
+                     TEXT("taskmgr.exe"),
+                     NULL,
+                     NULL,
+                     SW_SHOWNORMAL);
     }
 
-    VOID
-        ChangingWinPos(
-        IN OUT LPWINDOWPOS pwp)
+    VOID ToggleDesktop()
     {
-        RECT rcTray;
-
-        if (IsDragging)
+        if (::IsThereAnyEffectiveWindow(TRUE))
         {
-            rcTray.left = pwp->x;
-            rcTray.top = pwp->y;
-            rcTray.right = rcTray.left + pwp->cx;
-            rcTray.bottom = rcTray.top + pwp->cy;
-            if (AutoHide)
-            {
-                rcTray.left -= AutoHideOffset.cx;
-                rcTray.right -= AutoHideOffset.cx;
-                rcTray.top -= AutoHideOffset.cy;
-                rcTray.bottom -= AutoHideOffset.cy;
-            }
-
-            if (!EqualRect(&rcTray,
-                &rcTrayWnd[DraggingPosition]))
-            {
-                /* Recalculate the rectangle, the user dragged the tray
-                   window to another monitor or the window was somehow else
-                   moved or resized */
-                DraggingPosition = GetDraggingRectFromRect(
-                    &rcTray,
-                    &DraggingMonitor);
-                //rcTrayWnd[DraggingPosition] = rcTray;
-            }
-
-            //Monitor = CalculateValidSize(
-            //                                                   DraggingPosition,
-            //                                                   &rcTray);
-
-            Monitor = DraggingMonitor;
-            Position = DraggingPosition;
-            IsDragging = FALSE;
-
-            rcTrayWnd[Position] = rcTray;
-            goto ChangePos;
+            ShowDesktop();
         }
-        else if (GetWindowRect(m_hWnd, &rcTray))
+        else
         {
-            if (InSizeMove)
-            {
-                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;
-                }
-
-                Position = GetDraggingRectFromRect(
-                    &rcTray,
-                    &Monitor);
-
-                if (!(pwp->flags & (SWP_NOMOVE | SWP_NOSIZE)))
-                {
-                    SIZE szWnd;
-
-                    szWnd.cx = pwp->cx;
-                    szWnd.cy = pwp->cy;
-
-                    MakeTrayRectWithSize(Position, &szWnd, &rcTray);
-                }
-
-                if (AutoHide)
-                {
-                    rcTray.left -= AutoHideOffset.cx;
-                    rcTray.right -= AutoHideOffset.cx;
-                    rcTray.top -= AutoHideOffset.cy;
-                    rcTray.bottom -= AutoHideOffset.cy;
-                }
-                rcTrayWnd[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 = rcTrayWnd[Position];
-            }
-
-ChangePos:
-            TraySize.cx = rcTray.right - rcTray.left;
-            TraySize.cy = rcTray.bottom - rcTray.top;
-
-            if (AutoHide)
-            {
-                rcTray.left += AutoHideOffset.cx;
-                rcTray.right += AutoHideOffset.cx;
-                rcTray.top += AutoHideOffset.cy;
-                rcTray.bottom += AutoHideOffset.cy;
-            }
-
-            pwp->flags &= ~(SWP_NOMOVE | SWP_NOSIZE);
-            pwp->x = rcTray.left;
-            pwp->y = rcTray.top;
-            pwp->cx = TraySize.cx;
-            pwp->cy = TraySize.cy;
+            RestoreAll();
         }
     }
 
-    VOID
-        ApplyClipping(IN BOOL Clip)
+    BOOL STDMETHODCALLTYPE ExecContextMenuCmd(IN UINT uiCmd)
     {
-        RECT rcClip, rcWindow;
-        HRGN hClipRgn;
-
-        if (GetWindowRect(m_hWnd, &rcWindow))
+        switch (uiCmd)
         {
-            /* Disable clipping on systems with only one monitor */
-            if (GetSystemMetrics(SM_CMONITORS) <= 1)
-                Clip = FALSE;
-
-            if (Clip)
-            {
-                rcClip = rcWindow;
-
-                GetScreenRect(Monitor, &rcClip);
+        case ID_SHELL_CMD_PROPERTIES:
+            DisplayProperties();
+            break;
 
-                if (!IntersectRect(&rcClip, &rcClip, &rcWindow))
-                {
-                    rcClip = rcWindow;
-                }
+        case ID_SHELL_CMD_OPEN_ALL_USERS:
+            OpenCommonStartMenuDirectory(m_hWnd,
+                                         TEXT("open"));
+            break;
 
-                OffsetRect(&rcClip,
-                           -rcWindow.left,
-                           -rcWindow.top);
+        case ID_SHELL_CMD_EXPLORE_ALL_USERS:
+            OpenCommonStartMenuDirectory(m_hWnd,
+                                         TEXT("explore"));
+            break;
 
-                hClipRgn = CreateRectRgnIndirect(&rcClip);
+        case ID_LOCKTASKBAR:
+            if (SHRestricted(REST_CLASSICSHELL) == 0)
+            {
+                Lock(!g_TaskbarSettings.bLock);
             }
-            else
-                hClipRgn = NULL;
+            break;
 
-            /* Set the clipping region or make sure the window isn't clipped
-               by disabling it explicitly. */
-            SetWindowRgn(m_hWnd, hClipRgn, TRUE);
-        }
-    }
+        case ID_SHELL_CMD_OPEN_TASKMGR:
+            OpenTaskManager(m_hWnd);
+            break;
 
-    VOID ResizeWorkArea()
-    {
-#if !WIN7_COMPAT_MODE
-        RECT rcTray, rcWorkArea;
+        case ID_SHELL_CMD_UNDO_ACTION:
+            break;
 
-        /* If monitor has changed then fix the previous monitors work area */
-        if (PreviousMonitor != Monitor)
-        {
-            GetScreenRect(
-                PreviousMonitor,
-                &rcWorkArea);
-            SystemParametersInfo(SPI_SETWORKAREA,
-                                 1,
-                                 &rcWorkArea,
-                                 SPIF_SENDCHANGE);
-        }
+        case ID_SHELL_CMD_SHOW_DESKTOP:
+            ShowDesktop();
+            break;
 
-        rcTray = rcTrayWnd[Position];
+        case ID_SHELL_CMD_TILE_WND_H:
+            TileWindows(NULL, MDITILE_HORIZONTAL, NULL, 0, NULL);
+            break;
 
-        GetScreenRect(
-            Monitor,
-            &rcWorkArea);
-        PreviousMonitor = Monitor;
+        case ID_SHELL_CMD_TILE_WND_V:
+            TileWindows(NULL, MDITILE_VERTICAL, NULL, 0, NULL);
+            break;
 
-        /* If AutoHide is false then change the workarea to exclude the area that
-           the taskbar covers. */
-        if (!AutoHide)
-        {
-            switch (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;
-            }
-        }
+        case ID_SHELL_CMD_CASCADE_WND:
+            CascadeWindows(NULL, MDITILE_SKIPDISABLED, NULL, 0, NULL);
+            break;
 
-        SystemParametersInfo(SPI_SETWORKAREA,
-                             1,
-                             &rcWorkArea,
-                             SPIF_SENDCHANGE);
-#endif
-    }
+        case ID_SHELL_CMD_CUST_NOTIF:
+            ShowCustomizeNotifyIcons(hExplorerInstance, m_hWnd);
+            break;
 
-    VOID CheckTrayWndPosition()
-    {
-        RECT rcTray;
+        case ID_SHELL_CMD_ADJUST_DAT:
+            //FIXME: Use SHRunControlPanel
+            ShellExecuteW(m_hWnd, NULL, L"timedate.cpl", NULL, NULL, SW_NORMAL);
+            break;
 
-        rcTray = rcTrayWnd[Position];
+        case ID_SHELL_CMD_RESTORE_ALL:
+            RestoreAll();
+            break;
 
-        if (AutoHide)
-        {
-            rcTray.left += AutoHideOffset.cx;
-            rcTray.right += AutoHideOffset.cx;
-            rcTray.top += AutoHideOffset.cy;
-            rcTray.bottom += AutoHideOffset.cy;
+        default:
+            TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd);
+            return FALSE;
         }
 
-        //    TRACE("CheckTray: %d: %d,%d,%d,%d\n", Position, rcTray.left, rcTray.top, rcTray.right, rcTray.bottom);
-
-        /* Move the tray window */
-        SetWindowPos(NULL,
-                     rcTray.left,
-                     rcTray.top,
-                     rcTray.right - rcTray.left,
-                     rcTray.bottom - rcTray.top,
-                     SWP_NOZORDER);
-
-        ResizeWorkArea();
-
-        ApplyClipping(TRUE);
+        return TRUE;
     }
 
-    typedef struct _TW_STUCKRECTS2
+    LRESULT HandleHotKey(DWORD id)
     {
-        DWORD cbSize;
-        LONG Unknown;
-        DWORD dwFlags;
-        DWORD Position;
-        SIZE Size;
-        RECT Rect;
-    } TW_STRUCKRECTS2, *PTW_STUCKRECTS2;
-
-    VOID
-        RegLoadSettings()
-    {
-        DWORD Pos;
-        TW_STRUCKRECTS2 sr;
-        RECT rcScreen;
-        SIZE WndSize, EdgeSize, DlgFrameSize;
-        DWORD cbSize = sizeof(sr);
-
-        EdgeSize.cx = GetSystemMetrics(SM_CXEDGE);
-        EdgeSize.cy = GetSystemMetrics(SM_CYEDGE);
-        DlgFrameSize.cx = GetSystemMetrics(SM_CXDLGFRAME);
-        DlgFrameSize.cy = GetSystemMetrics(SM_CYDLGFRAME);
-
-        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;
-
-            /* FIXME: Are there more flags? */
-
-#if WIN7_COMPAT_MODE
-            Position = ABE_LEFT;
-#else
-            if (sr.Position > ABE_BOTTOM)
-                Position = ABE_BOTTOM;
-            else
-                Position = sr.Position;
-#endif
-
-            /* 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
+        switch (id)
         {
-            Position = ABE_BOTTOM;
-            AlwaysOnTop = TRUE;
-
-            /* Use the minimum size of the taskbar, we'll use the start
-               button as a minimum for now. Make sure we calculate the
-               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));
-
-            /* 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);
+        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", L"/e ,", 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:
+            MinimizeAll();
+            break;
+        case IDHK_RESTORE_ALL:
+            RestoreAll();
+            break;
+        case IDHK_DESKTOP:
+            ToggleDesktop();
+            break;
+        case IDHK_PAGER:
+            break;
         }
 
-        if (m_hWnd != NULL)
-            SetWindowPos(
-            AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
-            0,
-            0,
-            0,
-            0,
-            SWP_NOMOVE | SWP_NOSIZE);
-
-        /* Determine a minimum tray window rectangle. The "client" height is
-           zero here since we cannot determine an optimal minimum width when
-           loaded as a vertical tray window. We just need to make sure the values
-           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));
-
-        if (WndSize.cx < sr.Size.cx)
-            WndSize.cx = sr.Size.cx;
-        if (WndSize.cy < sr.Size.cy)
-            WndSize.cy = sr.Size.cy;
-
-        /* Save the calculated size */
-        TraySize = WndSize;
+        return 0;
+    }
 
-        /* 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++)
+    LRESULT HandleCommand(UINT uCommand)
+    {
+        switch (uCommand)
         {
-            GetTrayRectFromScreenRect(
-                Pos,
-                &rcScreen,
-                &TraySize,
-                &rcTrayWnd[Pos]);
-            //        TRACE("rcTrayWnd[%d(%d)]: %d,%d,%d,%d\n", Pos, Position, rcTrayWnd[Pos].left, rcTrayWnd[Pos].top, rcTrayWnd[Pos].right, rcTrayWnd[Pos].bottom);
+            case TRAYCMD_STARTMENU:
+                // TODO:
+                break;
+            case TRAYCMD_RUN_DIALOG:
+                DisplayRunFileDlg();
+                break;
+            case TRAYCMD_LOGOFF_DIALOG:
+                LogoffWindowsDialog(m_hWnd); // FIXME: Maybe handle it in a similar way as DoExitWindows?
+                break;
+            case TRAYCMD_CASCADE:
+                CascadeWindows(NULL, MDITILE_SKIPDISABLED, NULL, 0, NULL);
+                break;
+            case TRAYCMD_TILE_H:
+                TileWindows(NULL, MDITILE_HORIZONTAL, NULL, 0, NULL);
+                break;
+            case TRAYCMD_TILE_V:
+                TileWindows(NULL, MDITILE_VERTICAL, NULL, 0, NULL);
+                break;
+            case TRAYCMD_TOGGLE_DESKTOP:
+                ToggleDesktop();
+                break;
+            case TRAYCMD_DATE_AND_TIME:
+                ShellExecuteW(m_hWnd, NULL, L"timedate.cpl", NULL, NULL, SW_NORMAL);
+                break;
+            case TRAYCMD_TASKBAR_PROPERTIES:
+                DisplayProperties();
+                break;
+            case TRAYCMD_MINIMIZE_ALL:
+                MinimizeAll();
+                break;
+            case TRAYCMD_RESTORE_ALL:
+                RestoreAll();
+                break;
+            case TRAYCMD_SHOW_DESKTOP:
+                ShowDesktop();
+                break;
+            case TRAYCMD_SHOW_TASK_MGR:
+                OpenTaskManager(m_hWnd);
+                break;
+            case TRAYCMD_CUSTOMIZE_TASKBAR:
+                break;
+            case TRAYCMD_LOCK_TASKBAR:
+                if (SHRestricted(REST_CLASSICSHELL) == 0)
+                {
+                    Lock(!g_TaskbarSettings.bLock);
+                }
+                break;
+            case TRAYCMD_HELP_AND_SUPPORT:
+                ExecResourceCmd(IDS_HELP_COMMAND);
+                break;
+            case TRAYCMD_CONTROL_PANEL:
+                // TODO:
+                break;
+            case TRAYCMD_SHUTDOWN_DIALOG:
+                DoExitWindows();
+                break;
+            case TRAYCMD_PRINTERS_AND_FAXES:
+                // TODO:
+                break;
+            case TRAYCMD_LOCK_DESKTOP:
+                // TODO:
+                break;
+            case TRAYCMD_SWITCH_USER_DIALOG:
+                // TODO:
+                break;
+            case TRAYCMD_SEARCH_FILES:
+                SHFindFiles(NULL, NULL);
+                break;
+            case TRAYCMD_SEARCH_COMPUTERS:
+                SHFindComputer(NULL, NULL);
+                break;
+
+            default:
+                break;
         }
 
-        /* Determine which monitor we are on. It shouldn't matter which docked
-           position rectangle we use */
-        Monitor = GetMonitorFromRect(
-            &rcTrayWnd[ABE_LEFT]);
+        return FALSE;
     }
 
-    UINT
-        TrackMenu(
+
+    UINT TrackMenu(
         IN HMENU hMenu,
         IN POINT *ppt OPTIONAL,
         IN HWND hwndExclude OPTIONAL,
@@ -962,7 +786,7 @@ ChangePos:
             /* Get the client rectangle and map it to screen coordinates */
             if (::GetClientRect(hwndExclude,
                 &tmp.rcExclude) &&
-                MapWindowPoints(hwndExclude,
+                ::MapWindowPoints(hwndExclude,
                 NULL,
                 (LPPOINT) &tmp.rcExclude,
                 2) != 0)
@@ -975,7 +799,7 @@ ChangePos:
         {
             if (ptmp == NULL &&
                 GetClientRect(&tmp.rcExclude) &&
-                MapWindowPoints(m_hWnd,
+                MapWindowPoints(
                 NULL,
                 (LPPOINT) &tmp.rcExclude,
                 2) != 0)
@@ -999,1025 +823,985 @@ ChangePos:
 
         tmp.cbSize = sizeof(tmp);
 
-        fuFlags = TPM_RETURNCMD | TPM_VERTICAL;
-        fuFlags |= (TrackUp ? TPM_BOTTOMALIGN : TPM_TOPALIGN);
-        if (IsContextMenu)
-            fuFlags |= TPM_RIGHTBUTTON;
-        else
-            fuFlags |= (TrackUp ? TPM_VERNEGANIMATION : TPM_VERPOSANIMATION);
-
-        cmdId = TrackPopupMenuEx(hMenu,
-                                 fuFlags,
-                                 pt.x,
-                                 pt.y,
-                                 m_hWnd,
-                                 ptmp);
-
-        return cmdId;
-    }
-
-    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 (popup == NULL)
-            return E_FAIL;
-
-        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);
-
-        if (uCommand != 0)
-        {
-            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;
-        }
-
-        DestroyMenu(popup);
-        return hr;
-    }
-
-
-    VOID UpdateStartButton(IN HBITMAP hbmStart OPTIONAL)
-    {
-        SIZE Size = { 0, 0 };
-
-        if (himlStartBtn == NULL ||
-            !StartButton.SendMessage(BCM_GETIDEALSIZE, 0, (LPARAM) &Size))
-        {
-            Size.cx = GetSystemMetrics(SM_CXEDGE);
-            Size.cy = GetSystemMetrics(SM_CYEDGE);
-
-            if (hbmStart == NULL)
-            {
-                hbmStart = (HBITMAP) StartButton.SendMessage(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);
-            }
-        }
-
-        /* Save the size of the start button */
-        StartBtnSize = Size;
-    }
-
-    VOID
-        AlignControls(IN PRECT prcClient OPTIONAL)
-    {
-        RECT rcClient;
-        SIZE TraySize, StartSize;
-        POINT ptTrayNotify = { 0, 0 };
-        BOOL Horizontal;
-        HDWP dwp;
-
-        UpdateStartButton(NULL);
-        if (prcClient != NULL)
-        {
-            rcClient = *prcClient;
-        }
-        else
-        {
-            if (!GetClientRect(&rcClient))
-            {
-                return;
-            }
-        }
-
-        Horizontal = IsPosHorizontal();
-
-        /* We're about to resize/move the start button, the rebar control and
-           the tray notification control */
-        dwp = BeginDeferWindowPos(3);
-        if (dwp == NULL)
-            return;
-
-        /* Limit the Start button width to the client width, if neccessary */
-        StartSize = StartBtnSize;
-        if (StartSize.cx > rcClient.right)
-            StartSize.cx = rcClient.right;
-
-        if (StartButton.m_hWnd != NULL)
-        {
-            /* Resize and reposition the button */
-            dwp = DeferWindowPos(dwp,
-                                 StartButton.m_hWnd,
-                                 NULL,
-                                 0,
-                                 0,
-                                 StartSize.cx,
-                                 StartSize.cy,
-                                 SWP_NOZORDER | SWP_NOACTIVATE);
-            if (dwp == NULL)
-                return;
-        }
-
-        /* 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;
-        }
-
-        if (hwndTrayNotify != NULL &&
-            SendMessage(hwndTrayNotify,
-            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;
-
-            dwp = DeferWindowPos(dwp,
-                                 hwndTrayNotify,
-                                 NULL,
-                                 ptTrayNotify.x,
-                                 ptTrayNotify.y,
-                                 TraySize.cx,
-                                 TraySize.cy,
-                                 SWP_NOZORDER | SWP_NOACTIVATE);
-            if (dwp == NULL)
-                return;
-        }
-
-        /* Resize/Move the rebar control */
-        if (hwndRebar != NULL)
-        {
-            POINT ptRebar = { 0, 0 };
-            SIZE szRebar;
-
-            SetWindowStyle(hwndRebar, CCS_VERT, Horizontal ? 0 : CCS_VERT);
-
-            if (Horizontal)
-            {
-                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;
-            }
-
-            dwp = DeferWindowPos(dwp,
-                                 hwndRebar,
-                                 NULL,
-                                 ptRebar.x,
-                                 ptRebar.y,
-                                 szRebar.cx,
-                                 szRebar.cy,
-                                 SWP_NOZORDER | SWP_NOACTIVATE);
-        }
-
-        if (dwp != NULL)
-            EndDeferWindowPos(dwp);
-
-        if (hwndTaskSwitch != NULL)
-        {
-            /* Update the task switch window configuration */
-            SendMessage(hwndTaskSwitch,
-                        TSWM_UPDATETASKBARPOS,
-                        0,
-                        0);
-        }
-    }
-
-    BOOL
-        CreateStartBtnImageList()
-    {
-        HICON hIconStart;
-        SIZE IconSize;
-
-        if (himlStartBtn != NULL)
-            return TRUE;
-
-        IconSize.cx = GetSystemMetrics(SM_CXSMICON);
-        IconSize.cy = GetSystemMetrics(SM_CYSMICON);
-
-        /* 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 (hIconStart != NULL)
-        {
-            himlStartBtn = (IImageList*) ImageList_Create(IconSize.cx,
-                                                          IconSize.cy,
-                                                          ILC_COLOR32 | ILC_MASK,
-                                                          1,
-                                                          1);
-            if (himlStartBtn != NULL)
-            {
-                int s;
-                himlStartBtn->ReplaceIcon(-1, hIconStart, &s);
-                if (s >= 0)
-                {
-                    return TRUE;
-                }
-
-                /* Failed to add the icon! */
-                himlStartBtn->Release();
-                himlStartBtn = NULL;
-            }
-        }
+        fuFlags = TPM_RETURNCMD | TPM_VERTICAL;
+        fuFlags |= (TrackUp ? TPM_BOTTOMALIGN : TPM_TOPALIGN);
+        if (IsContextMenu)
+            fuFlags |= TPM_RIGHTBUTTON;
+        else
+            fuFlags |= (TrackUp ? TPM_VERNEGANIMATION : TPM_VERPOSANIMATION);
 
-        return FALSE;
+        cmdId = TrackPopupMenuEx(hMenu,
+                                 fuFlags,
+                                 pt.x,
+                                 pt.y,
+                                 m_hWnd,
+                                 ptmp);
+
+        return cmdId;
     }
 
-    HBITMAP CreateStartButtonBitmap()
+    HRESULT TrackCtxMenu(
+        IN IContextMenu * contextMenu,
+        IN POINT *ppt OPTIONAL,
+        IN HWND hwndExclude OPTIONAL,
+        IN BOOL TrackUp,
+        IN PVOID Context OPTIONAL)
     {
-        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;
+        POINT pt;
+        TPMPARAMS params;
+        RECT rc;
+        HRESULT hr;
+        UINT uCommand;
+        HMENU popup = CreatePopupMenu();
 
-        /* NOTE: this is the backwards compatibility code that is used if the
-                 Common Controls Version 6.0 are not available! */
+        if (popup == NULL)
+            return E_FAIL;
 
-        if (!LoadString(hExplorerInstance,
-            IDS_START,
-            szStartCaption,
-            sizeof(szStartCaption) / sizeof(szStartCaption[0])))
+        if (ppt)
+        {
+            pt = *ppt;
+        }
+        else
         {
-            return NULL;
+            ::GetWindowRect(m_hWnd, &rc);
+            pt.x = rc.left;
+            pt.y = rc.top;
         }
 
-        /* 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);
+        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;
+        }
 
-        hDCScreen = GetDC(NULL);
-        if (hDCScreen == NULL)
-            goto Cleanup;
+        TRACE("Before Tracking\n");
+        ::SetForegroundWindow(m_hWnd);
+        if (hwndExclude)
+        {
+            ::GetWindowRect(hwndExclude, &rc);
+            ZeroMemory(&params, sizeof(params));
+            params.cbSize = sizeof(params);
+            params.rcExclude = rc;
+            uCommand = ::TrackPopupMenuEx(popup, TPM_RETURNCMD, pt.x, pt.y, m_hWnd, &params);
+        }
+        else
+        {
+            uCommand = ::TrackPopupMenuEx(popup, TPM_RETURNCMD, pt.x, pt.y, m_hWnd, NULL);
+        }
+        ::PostMessage(m_hWnd, WM_NULL, 0, 0);
 
-        hDC = CreateCompatibleDC(hDCScreen);
-        if (hDC == NULL)
-            goto Cleanup;
+        if (uCommand != 0)
+        {
+            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;
+        }
 
-        hFontOld = (HFONT) SelectObject(hDC, hStartBtnFont);
+        DestroyMenu(popup);
+        return hr;
+    }
 
-        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;
+    /**********************************************************
+     *    ##### moving and sizing handling #####
+     */
 
-        /* Draw the button */
-        hbmpOld = (HBITMAP) SelectObject(hDC, hbmp);
+    void UpdateFonts()
+    {
+        /* There is nothing to do if themes are enabled */
+        if (m_Theme)
+            return;
 
-        Flags = DC_TEXT | DC_INBUTTON;
-        if (hIconStart != NULL)
-            Flags |= DC_ICON;
+        m_StartButton.UpdateFont();
 
-        if (DrawCapTemp != NULL)
+        NONCLIENTMETRICS ncm = {sizeof(ncm)};
+        if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, FALSE))
         {
-            Ret = DrawCapTemp(NULL,
-                              hDC,
-                              &rcButton,
-                              hStartBtnFont,
-                              hIconStart,
-                              szStartCaption,
-                              Flags);
+            ERR("SPI_GETNONCLIENTMETRICS failed\n");
+            return;
         }
 
-        SelectObject(hDC,
-                     hbmpOld);
+        if (m_Font != NULL)
+            DeleteObject(m_Font);
 
-        if (!Ret)
-            goto Cleanup;
-
-        /* We successfully created the bitmap! */
-        hBitmap = hbmp;
-        hbmp = NULL;
-
-Cleanup:
-        if (hDCScreen != NULL)
+        ncm.lfCaptionFont.lfWeight = FW_NORMAL;
+        m_Font = CreateFontIndirect(&ncm.lfCaptionFont);
+        if (!m_Font)
         {
-            ReleaseDC(NULL,
-                      hDCScreen);
+            ERR("CreateFontIndirect failed\n");
+            return;
         }
 
-        if (hbmp != NULL)
-            DeleteObject(hbmp);
-
-        if (hDC != NULL)
-            DeleteDC(hDC);
-
-        return hBitmap;
+        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);
     }
 
-    LRESULT OnThemeChanged()
+    HMONITOR GetScreenRectFromRect(
+        IN OUT RECT *pRect,
+        IN DWORD dwFlags)
     {
-        if (TaskbarTheme)
-            CloseThemeData(TaskbarTheme);
-
-        if (IsThemeActive())
-            TaskbarTheme = OpenThemeData(m_hWnd, L"TaskBar");
-        else
-            TaskbarTheme = NULL;
+        MONITORINFO mi;
+        HMONITOR hMon;
 
-        if (TaskbarTheme)
+        mi.cbSize = sizeof(mi);
+        hMon = MonitorFromRect(pRect, dwFlags);
+        if (hMon != NULL &&
+            GetMonitorInfo(hMon, &mi))
         {
-            SetWindowStyle(m_hWnd, WS_THICKFRAME | WS_BORDER, 0);
+            *pRect = mi.rcMonitor;
         }
         else
         {
-            SetWindowStyle(m_hWnd, WS_THICKFRAME | WS_BORDER, WS_THICKFRAME | WS_BORDER);
-        }
+            pRect->left = 0;
+            pRect->top = 0;
+            pRect->right = GetSystemMetrics(SM_CXSCREEN);
+            pRect->bottom = GetSystemMetrics(SM_CYSCREEN);
 
-        return TRUE;
-    }
+            hMon = NULL;
+        }
 
-    LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
-    {
-        return OnThemeChanged();
+        return hMon;
     }
 
-    LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    HMONITOR GetMonitorFromRect(
+        IN const RECT *pRect)
     {
-        WCHAR szStartCaption[32];
-
-        ((ITrayWindow*)this)->AddRef();
+        HMONITOR hMon;
 
-        SetWindowTheme(m_hWnd, L"TaskBar", NULL);
-        OnThemeChanged();
+        /* 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;
 
-        InterlockedIncrement(&TrayWndCount);
+            pt.x = pRect->left + ((pRect->right - pRect->left) / 2);
+            pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2);
 
-        if (!LoadString(hExplorerInstance,
-            IDS_START,
-            szStartCaption,
-            sizeof(szStartCaption) / sizeof(szStartCaption[0])))
-        {
-            szStartCaption[0] = TEXT('\0');
+            /* be less error-prone, find the nearest monitor */
+            hMon = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
         }
 
-        if (hStartBtnFont == NULL || hCaptionFont == NULL)
-        {
-            NONCLIENTMETRICS ncm;
-
-            /* Get the system fonts, we use the caption font,
-               always bold, though. */
-            ncm.cbSize = sizeof(ncm);
-            if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
-                sizeof(ncm),
-                &ncm,
-                FALSE))
-            {
-                if (hCaptionFont == NULL)
-                {
-                    ncm.lfCaptionFont.lfWeight = FW_NORMAL;
-                    hCaptionFont = CreateFontIndirect(&ncm.lfCaptionFont);
-                }
+        return hMon;
+    }
 
-                if (hStartBtnFont == NULL)
-                {
-                    ncm.lfCaptionFont.lfWeight = FW_BOLD;
-                    hStartBtnFont = CreateFontIndirect(&ncm.lfCaptionFont);
-                }
-            }
-        }
+    HMONITOR GetScreenRect(
+        IN HMONITOR hMonitor,
+        IN OUT RECT *pRect)
+    {
+        HMONITOR hMon = NULL;
 
-        /* Create the Start button */
-        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 (StartButton.m_hWnd)
+        if (hMonitor != NULL)
         {
-            SetWindowTheme(StartButton.m_hWnd, L"Start", NULL);
-            StartButton.SendMessage(WM_SETFONT, (WPARAM) hStartBtnFont, FALSE);
+            MONITORINFO mi;
 
-            if (CreateStartBtnImageList())
+            mi.cbSize = sizeof(mi);
+            if (!GetMonitorInfo(hMonitor, &mi))
             {
-                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 = (HIMAGELIST) himlStartBtn;
-                bil.margin.left = bil.margin.right = 1;
-                bil.margin.top = bil.margin.bottom = 1;
-                bil.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT;
-
-                if (!StartButton.SendMessage(BCM_SETIMAGELIST, 0, (LPARAM) &bil))
+                /* 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))
                 {
-                    /* Fall back to the deprecated method on older systems that don't
-                       support Common Controls 6.0 */
-                    himlStartBtn->Release();
-                    himlStartBtn = NULL;
-
-                    goto SetStartBtnImage;
+                    hMon = NULL;
+                    goto GetPrimaryRect;
                 }
-
-                /* We're using the image list, remove the BS_BITMAP style and
-                   don't center it horizontally */
-                SetWindowStyle(StartButton.m_hWnd, BS_BITMAP | BS_RIGHT, 0);
-
-                UpdateStartButton(NULL);
             }
-            else
-            {
-                HBITMAP hbmStart, hbmOld;
-
-SetStartBtnImage:
-                hbmStart = CreateStartButtonBitmap();
-                if (hbmStart != NULL)
-                {
-                    UpdateStartButton(hbmStart);
-
-                    hbmOld = (HBITMAP) StartButton.SendMessage(BM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbmStart);
 
-                    if (hbmOld != NULL)
-                        DeleteObject(hbmOld);
-                }
-            }
+            *pRect = mi.rcMonitor;
         }
-
-        /* Load the saved tray window settings */
-        RegLoadSettings();
-
-        /* Create and initialize the start menu */
-        hbmStartMenu = LoadBitmap(hExplorerInstance,
-                                  MAKEINTRESOURCE(IDB_STARTMENU));
-        StartMenuPopup = CreateStartMenu(this, &StartMenuBand, hbmStartMenu, 0);
-
-        /* Load the tray band site */
-        if (TrayBandSite != NULL)
+        else
         {
-            TrayBandSite.Release();
+GetPrimaryRect:
+            pRect->left = 0;
+            pRect->top = 0;
+            pRect->right = GetSystemMetrics(SM_CXSCREEN);
+            pRect->bottom = GetSystemMetrics(SM_CYSCREEN);
         }
 
-        TrayBandSite = CreateTrayBandSite(this, &hwndRebar, &hwndTaskSwitch);
-        SetWindowTheme(hwndRebar, L"TaskBar", NULL);
-
-        /* Create the tray notification window */
-        hwndTrayNotify = CreateTrayNotifyWnd(this, HideClock);
-
-        if (UpdateNonClientMetrics())
-        {
-            SetWindowsFont();
-        }
+        return hMon;
+    }
 
-        /* Move the tray window to the right position and resize it if neccessary */
-        CheckTrayWndPosition();
+    VOID AdjustSizerRect(RECT *rc, DWORD pos)
+    {
+        int iSizerPart[4] = {TBP_SIZINGBARLEFT, TBP_SIZINGBARTOP, TBP_SIZINGBARRIGHT, TBP_SIZINGBARBOTTOM};
+        SIZE size;
 
-        /* Align all controls on the tray window */
-        AlignControls(
-            NULL);
+        if (pos > ABE_BOTTOM)
+            pos = ABE_BOTTOM;
 
-        InitShellServices(&(hdpaShellServices));
+        HRESULT hr = GetThemePartSize(m_Theme, NULL, iSizerPart[pos], 0, NULL, TS_TRUE, &size);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return;
 
-        if (AutoHide)
+        switch (pos)
         {
-            AutoHideState = AUTOHIDE_HIDING;
-            SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL);
+            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;
         }
-
-        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;
     }
 
-    HRESULT STDMETHODCALLTYPE Open()
+    VOID MakeTrayRectWithSize(IN DWORD Position,
+                              IN const SIZE *pTraySize,
+                              IN OUT RECT *pRect)
     {
-        RECT rcWnd;
-
-        /* 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())
+        switch (Position)
         {
-            if (!IsWindowVisible(m_hWnd))
-            {
-                CheckTrayWndPosition();
-
-                ShowWindow(SW_SHOW);
-            }
-
-            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;
+        case ABE_LEFT:
+            pRect->right = pRect->left + pTraySize->cx;
+            break;
 
-        ZeroMemory(&rcWnd, sizeof(rcWnd));
-        if (Position != (DWORD) -1)
-            rcWnd = rcTrayWnd[Position];
+        case ABE_TOP:
+            pRect->bottom = pRect->top + pTraySize->cy;
+            break;
 
-        if (!Create(NULL, rcWnd, NULL, dwStyle, dwExStyle))
-            return E_FAIL;
+        case ABE_RIGHT:
+            pRect->left = pRect->right - pTraySize->cx;
+            break;
 
-        return S_OK;
+        case ABE_BOTTOM:
+        default:
+            pRect->top = pRect->bottom - pTraySize->cy;
+            break;
+        }
     }
 
-    HRESULT STDMETHODCALLTYPE Close()
+    VOID GetTrayRectFromScreenRect(IN DWORD Position,
+                                   IN const RECT *pScreen,
+                                   IN const SIZE *pTraySize OPTIONAL,
+                                   OUT RECT *pRect)
     {
-        if (m_hWnd != NULL)
-        {
-            SendMessage(m_hWnd,
-                        WM_APP_TRAYDESTROY,
-                        0,
-                        0);
-        }
+        if (pTraySize == NULL)
+            pTraySize = &m_TraySize;
 
-        return S_OK;
-    }
+        *pRect = *pScreen;
 
-    HWND STDMETHODCALLTYPE GetHWND()
-    {
-        return m_hWnd;
-    }
+        if(!m_Theme)
+        {
+            /* Move the border outside of the screen */
+            InflateRect(pRect,
+                        GetSystemMetrics(SM_CXEDGE),
+                        GetSystemMetrics(SM_CYEDGE));
+        }
 
-    BOOL STDMETHODCALLTYPE IsSpecialHWND(IN HWND hWnd)
-    {
-        return (m_hWnd == hWnd ||
-                (hWndDesktop != NULL && m_hWnd == hWndDesktop));
+        MakeTrayRectWithSize(Position, pTraySize, pRect);
     }
 
-    BOOL STDMETHODCALLTYPE
-        IsHorizontal()
+    BOOL IsPosHorizontal()
     {
-        return IsPosHorizontal();
+        return m_Position == ABE_TOP || m_Position == ABE_BOTTOM;
     }
 
-    HFONT STDMETHODCALLTYPE GetCaptionFonts(OUT HFONT *phBoldCaption OPTIONAL)
+    HMONITOR CalculateValidSize(
+        IN DWORD Position,
+        IN OUT RECT *pRect)
     {
-        if (phBoldCaption != NULL)
-            *phBoldCaption = hStartBtnFont;
+        RECT rcScreen;
+        //BOOL Horizontal;
+        HMONITOR hMon;
+        SIZE szMax, szWnd;
 
-        return hCaptionFont;
-    }
+        //Horizontal = IsPosHorizontal();
 
-    DWORD WINAPI TrayPropertiesThread()
-    {
-        HWND hwnd;
-        RECT posRect;
+        szWnd.cx = pRect->right - pRect->left;
+        szWnd.cy = pRect->bottom - pRect->top;
 
-        GetWindowRect(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);
+        rcScreen = *pRect;
+        hMon = GetScreenRectFromRect(
+            &rcScreen,
+            MONITOR_DEFAULTTONEAREST);
 
-        hwndTrayPropertiesOwner = hwnd;
+        /* 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;
 
-        DisplayTrayProperties(hwnd);
+        /* FIXME - calculate */
 
-        hwndTrayPropertiesOwner = NULL;
-        DestroyWindow();
+        GetTrayRectFromScreenRect(Position,
+                                  &rcScreen,
+                                  &szWnd,
+                                  pRect);
 
-        return 0;
+        return hMon;
     }
 
-    static DWORD WINAPI s_TrayPropertiesThread(IN OUT PVOID pParam)
+#if 0
+    VOID
+        GetMinimumWindowSize(
+        OUT RECT *pRect)
     {
-        CTrayWindow *This = (CTrayWindow*) pParam;
+        RECT rcMin = {0};
 
-        return This->TrayPropertiesThread();
+        AdjustWindowRectEx(&rcMin,
+                           GetWindowLong(m_hWnd,
+                           GWL_STYLE),
+                           FALSE,
+                           GetWindowLong(m_hWnd,
+                           GWL_EXSTYLE));
+
+        *pRect = rcMin;
     }
+#endif
 
-    HWND STDMETHODCALLTYPE DisplayProperties()
+
+    DWORD GetDraggingRectFromPt(
+        IN POINT pt,
+        OUT RECT *pRect,
+        OUT HMONITOR *phMonitor)
     {
-        HWND hTrayProp;
+        HMONITOR hMon, hMonNew;
+        DWORD PosH, PosV, Pos;
+        SIZE DeltaPt, ScreenOffset;
+        RECT rcScreen;
 
-        if (hwndTrayPropertiesOwner)
+        rcScreen.left = 0;
+        rcScreen.top = 0;
+
+        /* Determine the screen rectangle */
+        hMon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);
+        if (hMon != NULL)
         {
-            hTrayProp = GetLastActivePopup(hwndTrayPropertiesOwner);
-            if (hTrayProp != NULL &&
-                hTrayProp != hwndTrayPropertiesOwner)
+            MONITORINFO mi;
+
+            mi.cbSize = sizeof(mi);
+            if (!GetMonitorInfo(hMon, &mi))
             {
-                SetForegroundWindow(hTrayProp);
-                return NULL;
+                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);
         }
 
-        CloseHandle(CreateThread(NULL, 0, s_TrayPropertiesThread, this, 0, NULL));
-        return NULL;
-    }
+        /* 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;
+        }
 
-    VOID OpenCommonStartMenuDirectory(IN HWND hWndOwner, IN LPCTSTR lpOperation)
-    {
-        WCHAR szDir[MAX_PATH];
+        if (pt.y < rcScreen.bottom / 2)
+        {
+            DeltaPt.cy = pt.y;
+            PosV = ABE_TOP;
+        }
+        else
+        {
+            DeltaPt.cy = rcScreen.bottom - pt.y;
+            PosV = ABE_BOTTOM;
+        }
 
-        if (SHGetSpecialFolderPath(hWndOwner,
-            szDir,
-            CSIDL_COMMON_STARTMENU,
-            FALSE))
+        Pos = (DeltaPt.cx * rcScreen.bottom < DeltaPt.cy * rcScreen.right) ? PosH : PosV;
+
+        /* 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)
         {
-            ShellExecute(hWndOwner,
-                         lpOperation,
-                         NULL,
-                         NULL,
-                         szDir,
-                         SW_SHOWNORMAL);
+            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);
+            hMon = hMonNew;
+        }
+        else
+        {
+            /* The user is dragging the tray window on the same monitor. We don't need
+               to recalculate the rectangle */
+            *pRect = rcPos;
         }
+
+        *phMonitor = hMon;
+
+        return Pos;
     }
 
-    VOID OpenTaskManager(IN HWND hWndOwner)
+    DWORD GetDraggingRectFromRect(
+        IN OUT RECT *pRect,
+        OUT HMONITOR *phMonitor)
     {
-        ShellExecute(hWndOwner,
-                     TEXT("open"),
-                     TEXT("taskmgr.exe"),
-                     NULL,
-                     NULL,
-                     SW_SHOWNORMAL);
+        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);
     }
 
-    BOOL STDMETHODCALLTYPE ExecContextMenuCmd(IN UINT uiCmd)
+    VOID ChangingWinPos(IN OUT LPWINDOWPOS pwp)
     {
-        BOOL bHandled = TRUE;
+        RECT rcTray;
 
-        switch (uiCmd)
+        if (IsDragging)
         {
-        case ID_SHELL_CMD_PROPERTIES:
-            DisplayProperties();
-            break;
+            rcTray.left = pwp->x;
+            rcTray.top = pwp->y;
+            rcTray.right = rcTray.left + pwp->cx;
+            rcTray.bottom = rcTray.top + pwp->cy;
 
-        case ID_SHELL_CMD_OPEN_ALL_USERS:
-            OpenCommonStartMenuDirectory(m_hWnd,
-                                         TEXT("open"));
-            break;
+            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;
+            }
 
-        case ID_SHELL_CMD_EXPLORE_ALL_USERS:
-            OpenCommonStartMenuDirectory(m_hWnd,
-                                         TEXT("explore"));
-            break;
+            //Monitor = CalculateValidSize(DraggingPosition,
+            //                             &rcTray);
 
-        case ID_LOCKTASKBAR:
-            if (SHRestricted(REST_CLASSICSHELL) == 0)
+            m_Monitor = m_DraggingMonitor;
+            m_Position = m_DraggingPosition;
+            IsDragging = FALSE;
+
+            m_TrayRects[m_Position] = rcTray;
+            goto ChangePos;
+        }
+        else if (GetWindowRect(&rcTray))
+        {
+            if (InSizeMove)
             {
-                Lock(!Locked);
-            }
-            break;
+                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;
+                }
 
-        case ID_SHELL_CMD_OPEN_TASKMGR:
-            OpenTaskManager(m_hWnd);
-            break;
+                m_Position = GetDraggingRectFromRect(&rcTray, &m_Monitor);
 
-        case ID_SHELL_CMD_UNDO_ACTION:
-            break;
+                if (!(pwp->flags & (SWP_NOMOVE | SWP_NOSIZE)))
+                {
+                    SIZE szWnd;
 
-        case ID_SHELL_CMD_SHOW_DESKTOP:
-            break;
+                    szWnd.cx = pwp->cx;
+                    szWnd.cy = pwp->cy;
 
-        case ID_SHELL_CMD_TILE_WND_H:
-            TileWindows(NULL, MDITILE_HORIZONTAL, NULL, 0, NULL);
-            break;
+                    MakeTrayRectWithSize(m_Position, &szWnd, &rcTray);
+                }
 
-        case ID_SHELL_CMD_TILE_WND_V:
-            TileWindows(NULL, MDITILE_VERTICAL, NULL, 0, NULL);
-            break;
+                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];
 
-        case ID_SHELL_CMD_CASCADE_WND:
-            CascadeWindows(NULL, MDITILE_SKIPDISABLED, NULL, 0, NULL);
-            break;
+                if (g_TaskbarSettings.sr.AutoHide)
+                {
+                    rcTray.left += m_AutoHideOffset.cx;
+                    rcTray.right += m_AutoHideOffset.cx;
+                    rcTray.top += m_AutoHideOffset.cy;
+                    rcTray.bottom += m_AutoHideOffset.cy;
+                }
 
-        case ID_SHELL_CMD_CUST_NOTIF:
-            break;
+            }
 
-        case ID_SHELL_CMD_ADJUST_DAT:
-            //FIXME: Use SHRunControlPanel
-            ShellExecuteW(m_hWnd, NULL, L"timedate.cpl", NULL, NULL, SW_NORMAL);
-            break;
+ChangePos:
+            m_TraySize.cx = rcTray.right - rcTray.left;
+            m_TraySize.cy = rcTray.bottom - rcTray.top;
 
-        default:
-            TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd);
-            bHandled = FALSE;
-            break;
+            pwp->flags &= ~(SWP_NOMOVE | SWP_NOSIZE);
+            pwp->x = rcTray.left;
+            pwp->y = rcTray.top;
+            pwp->cx = m_TraySize.cx;
+            pwp->cy = m_TraySize.cy;
         }
-
-        return bHandled;
     }
 
-    BOOL STDMETHODCALLTYPE Lock(IN BOOL bLock)
+    VOID ApplyClipping(IN BOOL Clip)
     {
-        BOOL bPrevLock;
+        RECT rcClip, rcWindow;
+        HRGN hClipRgn;
 
-        bPrevLock = Locked;
-        if (Locked != bLock)
+        if (GetWindowRect(&rcWindow))
         {
-            Locked = bLock;
+            /* Disable clipping on systems with only one monitor */
+            if (GetSystemMetrics(SM_CMONITORS) <= 1)
+                Clip = FALSE;
 
-            if (TrayBandSite != NULL)
+            if (Clip)
             {
-                if (!SUCCEEDED(TrayBandSite->Lock(
-                    bLock)))
+                rcClip = rcWindow;
+
+                GetScreenRect(m_Monitor, &rcClip);
+
+                if (!IntersectRect(&rcClip, &rcClip, &rcWindow))
                 {
-                    /* Reset?? */
-                    Locked = bPrevLock;
+                    rcClip = rcWindow;
                 }
+
+                OffsetRect(&rcClip,
+                           -rcWindow.left,
+                           -rcWindow.top);
+
+                hClipRgn = CreateRectRgnIndirect(&rcClip);
             }
-        }
+            else
+                hClipRgn = NULL;
 
-        return bPrevLock;
+            /* Set the clipping region or make sure the window isn't clipped
+               by disabling it explicitly. */
+            SetWindowRgn(hClipRgn, TRUE);
+        }
     }
 
-
-    LRESULT DrawBackground(HDC hdc)
+    VOID ResizeWorkArea()
     {
-        RECT rect;
-        int partId;
+#if !WIN7_DEBUG_MODE
+        RECT rcTray, rcWorkArea;
+
+        /* 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);
+        }
 
-        GetClientRect(&rect);
+        rcTray = m_TrayRects[m_Position];
 
-        if (TaskbarTheme)
+        GetScreenRect(m_Monitor, &rcWorkArea);
+        m_PreviousMonitor = m_Monitor;
+
+        /* If AutoHide is false then change the workarea to exclude
+           the area that the taskbar covers. */
+        if (!g_TaskbarSettings.sr.AutoHide)
         {
-            GetClientRect(&rect);
-            switch (Position)
+            switch (m_Position)
             {
-            case ABE_LEFT:
-                partId = TBP_BACKGROUNDLEFT;
-                break;
             case ABE_TOP:
-                partId = TBP_BACKGROUNDTOP;
+                rcWorkArea.top = rcTray.bottom;
+                break;
+            case ABE_LEFT:
+                rcWorkArea.left = rcTray.right;
                 break;
             case ABE_RIGHT:
-                partId = TBP_BACKGROUNDRIGHT;
+                rcWorkArea.right = rcTray.left;
                 break;
             case ABE_BOTTOM:
-            default:
-                partId = TBP_BACKGROUNDBOTTOM;
+                rcWorkArea.bottom = rcTray.top;
                 break;
             }
-
-            DrawThemeBackground(TaskbarTheme, hdc, partId, 0, &rect, 0);
         }
 
-        return TRUE;
+        /*
+         * 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 OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    VOID CheckTrayWndPosition()
     {
-        HDC hdc = (HDC) wParam;
+        /* Force the rebar bands to resize */
+        IUnknown_Exec(m_TrayBandSite,
+                      IID_IDeskBand,
+                      DBID_BANDINFOCHANGED,
+                      0,
+                      NULL,
+                      NULL);
 
-        if (!TaskbarTheme)
-        {
-            bHandled = FALSE;
-            return 0;
-        }
+        /* Calculate the size of the taskbar based on the rebar */
+        FitToRebar(&m_TrayRects[m_Position]);
 
-        return DrawBackground(hdc);
+        /* Move the tray window */
+        /* The handler of WM_WINDOWPOSCHANGING will override whatever size
+         * and position we use here with m_TrayRects */
+        SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE);
+        ResizeWorkArea();
+        ApplyClipping(TRUE);
     }
 
-    int DrawSizer(IN HRGN hRgn)
+    VOID RegLoadSettings()
     {
-        HDC hdc;
-        RECT rect;
-        int backoundPart;
+        DWORD Pos;
+        RECT rcScreen;
+        SIZE WndSize, EdgeSize, DlgFrameSize;
+        SIZE StartBtnSize = m_StartButton.GetSize();
 
-        GetWindowRect(m_hWnd, &rect);
-        OffsetRect(&rect, -rect.left, -rect.top);
+        EdgeSize.cx = GetSystemMetrics(SM_CXEDGE);
+        EdgeSize.cy = GetSystemMetrics(SM_CYEDGE);
+        DlgFrameSize.cx = GetSystemMetrics(SM_CXDLGFRAME);
+        DlgFrameSize.cy = GetSystemMetrics(SM_CYDLGFRAME);
 
-        hdc = GetDCEx(m_hWnd, hRgn, DCX_WINDOW | DCX_INTERSECTRGN | DCX_PARENTCLIP);
+        m_Position = g_TaskbarSettings.sr.Position;
+        rcScreen = g_TaskbarSettings.sr.Rect;
+        GetScreenRectFromRect(&rcScreen, MONITOR_DEFAULTTONEAREST);
 
-        switch (Position)
+        if (!g_TaskbarSettings.sr.Size.cx || !g_TaskbarSettings.sr.Size.cy)
         {
-        case ABE_LEFT:
-            backoundPart = TBP_SIZINGBARLEFT;
-            rect.left = rect.right - GetSystemMetrics(SM_CXSIZEFRAME);
-            break;
-        case ABE_TOP:
-            backoundPart = TBP_SIZINGBARTOP;
-            rect.top = rect.bottom - GetSystemMetrics(SM_CYSIZEFRAME);
-            break;
-        case ABE_RIGHT:
-            backoundPart = TBP_SIZINGBARRIGHT;
-            rect.right = rect.left + GetSystemMetrics(SM_CXSIZEFRAME);
-            break;
-        case ABE_BOTTOM:
-        default:
-            backoundPart = TBP_SIZINGBARBOTTOM;
-            rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZEFRAME);
-            break;
+            /* 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)
+            {
+                g_TaskbarSettings.sr.Size.cx = StartBtnSize.cx + (2 * (EdgeSize.cx + DlgFrameSize.cx));
+                g_TaskbarSettings.sr.Size.cy = StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy));
+            }
+            else
+            {
+                g_TaskbarSettings.sr.Size.cx = StartBtnSize.cx - EdgeSize.cx;
+                g_TaskbarSettings.sr.Size.cy = StartBtnSize.cy - EdgeSize.cy;
+                if(!g_TaskbarSettings.bLock)
+                    g_TaskbarSettings.sr.Size.cy += GetSystemMetrics(SM_CYSIZEFRAME);
+            }
+        }
+        /* 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)
+        {
+            WndSize.cx = 2 * (EdgeSize.cx + DlgFrameSize.cx);
+            WndSize.cy = StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy));
+        }
+        else
+        {
+            WndSize.cx = StartBtnSize.cx;
+            WndSize.cy = StartBtnSize.cy - EdgeSize.cx;
         }
 
-        DrawThemeBackground(TaskbarTheme, hdc, backoundPart, 0, &rect, 0);
+        if (WndSize.cx < g_TaskbarSettings.sr.Size.cx)
+            WndSize.cx = g_TaskbarSettings.sr.Size.cx;
+        if (WndSize.cy < g_TaskbarSettings.sr.Size.cy)
+            WndSize.cy = g_TaskbarSettings.sr.Size.cy;
 
-        ReleaseDC(m_hWnd, hdc);
-        return 0;
+        /* Save the calculated size */
+        m_TraySize = WndSize;
+
+        /* 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++)
+        {
+            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);
+        }
+
+        /* Determine which monitor we are on. It shouldn't matter which docked
+           position rectangle we use */
+        m_Monitor = GetMonitorFromRect(&m_TrayRects[ABE_LEFT]);
     }
 
-    DWORD WINAPI RunFileDlgThread()
+    VOID AlignControls(IN PRECT prcClient OPTIONAL)
     {
-        HINSTANCE hShell32;
-        RUNFILEDLG RunFileDlg;
-        HWND hwnd;
-        RECT posRect;
+        RECT rcClient;
+        SIZE TraySize, StartSize;
+        POINT ptTrayNotify = { 0, 0 };
+        BOOL Horizontal;
+        HDWP dwp;
+
+        m_StartButton.UpdateSize();
+        if (prcClient != NULL)
+        {
+            rcClient = *prcClient;
+        }
+        else
+        {
+            if (!GetClientRect(&rcClient))
+            {
+                ERR("Could not get client rect lastErr=%d\n", GetLastError());
+                return;
+            }
+        }
 
-        GetWindowRect(StartButton.m_hWnd, &posRect);
+        Horizontal = IsPosHorizontal();
 
-        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);
+        /* We're about to resize/move the start button, the rebar control and
+           the tray notification control */
+        dwp = BeginDeferWindowPos(3);
+        if (dwp == NULL)
+        {
+            ERR("BeginDeferWindowPos failed. lastErr=%d\n", GetLastError());
+            return;
+        }
+
+        /* 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_Theme)
+        {
+            HWND hwndTaskToolbar = ::GetWindow(m_TaskSwitch, GW_CHILD);
+            if (hwndTaskToolbar)
+            {
+                DWORD size = SendMessageW(hwndTaskToolbar, TB_GETBUTTONSIZE, 0, 0);
+                StartSize.cy = HIWORD(size);
+            }
+        }
+
+        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;
+            }
+        }
+
+        /* 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;
+        }
+
+        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;
+
+            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;
+            }
+        }
+
+        /* Resize/Move the rebar control */
+        if (m_Rebar != NULL)
+        {
+            POINT ptRebar = { 0, 0 };
+            SIZE szRebar;
 
-        hwndRunFileDlgOwner = hwnd;
+            SetWindowStyle(m_Rebar, CCS_VERT, Horizontal ? 0 : CCS_VERT);
 
-        hShell32 = GetModuleHandle(TEXT("SHELL32.DLL"));
-        RunFileDlg = (RUNFILEDLG) GetProcAddress(hShell32, (LPCSTR) 61);
+            if (Horizontal)
+            {
+                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;
+            }
 
-        RunFileDlg(hwnd, NULL, NULL, NULL, NULL, RFF_CALCDIRECTORY);
+            dwp = ::DeferWindowPos(dwp,
+                                   m_Rebar,
+                                   NULL,
+                                   ptRebar.x,
+                                   ptRebar.y,
+                                   szRebar.cx,
+                                   szRebar.cy,
+                                   SWP_NOZORDER | SWP_NOACTIVATE);
+        }
 
-        hwndRunFileDlgOwner = NULL;
-        ::DestroyWindow(hwnd);
+        if (dwp != NULL)
+            EndDeferWindowPos(dwp);
 
-        return 0;
+        if (m_TaskSwitch != NULL)
+        {
+            /* Update the task switch window configuration */
+            SendMessage(m_TaskSwitch, TSWM_UPDATETASKBARPOS, 0, 0);
+        }
     }
 
-    static DWORD WINAPI s_RunFileDlgThread(IN OUT PVOID pParam)
+    void FitToRebar(PRECT pRect)
     {
-        CTrayWindow * This = (CTrayWindow*) pParam;
-        return This->RunFileDlgThread();
-    }
+        /* 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);
 
-    void DisplayRunFileDlg()
-    {
-        HWND hRunDlg;
-        if (hwndRunFileDlgOwner)
+        /* 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;
+
+        /* Calculate the new size of the rebar and make it resize, then change the new taskbar size */
+        switch (m_Position)
         {
-            hRunDlg = GetLastActivePopup(hwndRunFileDlgOwner);
-            if (hRunDlg != NULL &&
-                hRunDlg != hwndRunFileDlgOwner)
-            {
-                SetForegroundWindow(hRunDlg);
-                return;
-            }
+        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 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 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;
+        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;
         }
 
-        CloseHandle(CreateThread(NULL, 0, s_RunFileDlgThread, this, 0, NULL));
+        CalculateValidSize(m_Position, pRect);
     }
 
     void PopupStartMenu()
     {
-        if (StartMenuPopup != NULL)
+        if (m_StartMenuPopup != NULL)
         {
             POINTL pt;
             RECTL rcExclude;
             DWORD dwFlags = 0;
 
-            if (GetWindowRect(StartButton.m_hWnd, (RECT*) &rcExclude))
+            if (m_StartButton.GetWindowRect((RECT*) &rcExclude))
             {
-                switch (Position)
+                switch (m_Position)
                 {
                 case ABE_BOTTOM:
                     pt.x = rcExclude.left;
                     pt.y = rcExclude.top;
-                    dwFlags |= MPPF_BOTTOM;
+                    dwFlags |= MPPF_TOP;
                     break;
                 case ABE_TOP:
-                case ABE_LEFT:
                     pt.x = rcExclude.left;
                     pt.y = rcExclude.bottom;
-                    dwFlags |= MPPF_TOP | MPPF_ALIGN_RIGHT;
+                    dwFlags |= MPPF_BOTTOM;
                     break;
-                case ABE_RIGHT:
+                case ABE_LEFT:
                     pt.x = rcExclude.right;
-                    pt.y = rcExclude.bottom;
-                    dwFlags |= MPPF_TOP | MPPF_ALIGN_LEFT;
+                    pt.y = rcExclude.top;
+                    dwFlags |= MPPF_RIGHT;
+                    break;
+                case ABE_RIGHT:
+                    pt.x = rcExclude.left;
+                    pt.y = rcExclude.top;
+                    dwFlags |= MPPF_LEFT;
                     break;
                 }
 
-                StartMenuPopup->Popup(
-                    &pt,
-                    &rcExclude,
-                    dwFlags);
+                m_StartMenuPopup->Popup(&pt, &rcExclude, dwFlags);
 
-                StartButton.SendMessageW(BM_SETSTATE, TRUE, 0);
+                m_StartButton.SendMessageW(BM_SETSTATE, TRUE, 0);
             }
         }
     }
@@ -2027,13 +1811,13 @@ SetStartBtnImage:
         RECT rcCurrent;
         POINT pt;
         BOOL over;
-        UINT state = AutoHideState;
+        UINT state = m_AutoHideState;
 
         GetCursorPos(&pt);
-        GetWindowRect(m_hWnd, &rcCurrent);
+        GetWindowRect(&rcCurrent);
         over = PtInRect(&rcCurrent, pt);
 
-        if (StartButton.SendMessage( BM_GETSTATE, 0, 0) != BST_UNCHECKED)
+        if (m_StartButton.SendMessage( BM_GETSTATE, 0, 0) != BST_UNCHECKED)
         {
             over = TRUE;
         }
@@ -2043,13 +1827,13 @@ SetStartBtnImage:
             if (state == AUTOHIDE_HIDING)
             {
                 TRACE("AutoHide cancelling hide.\n");
-                AutoHideState = AUTOHIDE_SHOWING;
+                m_AutoHideState = AUTOHIDE_SHOWING;
                 SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
             }
             else if (state == AUTOHIDE_HIDDEN)
             {
                 TRACE("AutoHide starting show.\n");
-                AutoHideState = AUTOHIDE_SHOWING;
+                m_AutoHideState = AUTOHIDE_SHOWING;
                 SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_SHOW, NULL);
             }
         }
@@ -2058,13 +1842,13 @@ SetStartBtnImage:
             if (state == AUTOHIDE_SHOWING)
             {
                 TRACE("AutoHide cancelling show.\n");
-                AutoHideState = AUTOHIDE_HIDING;
+                m_AutoHideState = AUTOHIDE_HIDING;
                 SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
             }
             else if (state == AUTOHIDE_SHOWN)
             {
                 TRACE("AutoHide starting hide.\n");
-                AutoHideState = AUTOHIDE_HIDING;
+                m_AutoHideState = AUTOHIDE_HIDING;
                 SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL);
             }
 
@@ -2074,44 +1858,41 @@ SetStartBtnImage:
 
     void ProcessAutoHide()
     {
-        RECT rc = rcTrayWnd[Position];
-        INT w = TraySize.cx - GetSystemMetrics(SM_CXBORDER) * 2 - 1;
-        INT h = TraySize.cy - GetSystemMetrics(SM_CYBORDER) * 2 - 1;
+        INT w = m_TraySize.cx - GetSystemMetrics(SM_CXBORDER) * 2 - 1;
+        INT h = m_TraySize.cy - GetSystemMetrics(SM_CYBORDER) * 2 - 1;
 
-        TRACE("AutoHide Timer received for %u, rc=(%d, %d, %d, %d), w=%d, h=%d.\n", AutoHideState, rc.left, rc.top, rc.right, rc.bottom, w, h);
-
-        switch (AutoHideState)
+        switch (m_AutoHideState)
         {
         case AUTOHIDE_HIDING:
-            switch (Position)
+            switch (m_Position)
             {
             case ABE_LEFT:
-                AutoHideOffset.cy = 0;
-                AutoHideOffset.cx -= AUTOHIDE_SPEED_HIDE;
-                if (AutoHideOffset.cx < -w)
-                    AutoHideOffset.cx = -w;
+                m_AutoHideOffset.cy = 0;
+                m_AutoHideOffset.cx -= AUTOHIDE_SPEED_HIDE;
+                if (m_AutoHideOffset.cx < -w)
+                    m_AutoHideOffset.cx = -w;
                 break;
             case ABE_TOP:
-                AutoHideOffset.cx = 0;
-                AutoHideOffset.cy -= AUTOHIDE_SPEED_HIDE;
-                if (AutoHideOffset.cy < -h)
-                    AutoHideOffset.cy = -h;
+                m_AutoHideOffset.cx = 0;
+                m_AutoHideOffset.cy -= AUTOHIDE_SPEED_HIDE;
+                if (m_AutoHideOffset.cy < -h)
+                    m_AutoHideOffset.cy = -h;
                 break;
             case ABE_RIGHT:
-                AutoHideOffset.cy = 0;
-                AutoHideOffset.cx += AUTOHIDE_SPEED_HIDE;
-                if (AutoHideOffset.cx > w)
-                    AutoHideOffset.cx = w;
+                m_AutoHideOffset.cy = 0;
+                m_AutoHideOffset.cx += AUTOHIDE_SPEED_HIDE;
+                if (m_AutoHideOffset.cx > w)
+                    m_AutoHideOffset.cx = w;
                 break;
             case ABE_BOTTOM:
-                AutoHideOffset.cx = 0;
-                AutoHideOffset.cy += AUTOHIDE_SPEED_HIDE;
-                if (AutoHideOffset.cy > h)
-                    AutoHideOffset.cy = h;
+                m_AutoHideOffset.cx = 0;
+                m_AutoHideOffset.cy += AUTOHIDE_SPEED_HIDE;
+                if (m_AutoHideOffset.cy > h)
+                    m_AutoHideOffset.cy = h;
                 break;
             }
 
-            if (AutoHideOffset.cx != w && AutoHideOffset.cy != h)
+            if (m_AutoHideOffset.cx != w && m_AutoHideOffset.cy != h)
             {
                 SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
                 break;
@@ -2120,78 +1901,431 @@ SetStartBtnImage:
             /* fallthrough */
         case AUTOHIDE_HIDDEN:
 
-            switch (Position)
+            switch (m_Position)
             {
             case ABE_LEFT:
-                AutoHideOffset.cx = -w;
-                AutoHideOffset.cy = 0;
+                m_AutoHideOffset.cx = -w;
+                m_AutoHideOffset.cy = 0;
                 break;
             case ABE_TOP:
-                AutoHideOffset.cx = 0;
-                AutoHideOffset.cy = -h;
+                m_AutoHideOffset.cx = 0;
+                m_AutoHideOffset.cy = -h;
                 break;
             case ABE_RIGHT:
-                AutoHideOffset.cx = w;
-                AutoHideOffset.cy = 0;
+                m_AutoHideOffset.cx = w;
+                m_AutoHideOffset.cy = 0;
                 break;
             case ABE_BOTTOM:
-                AutoHideOffset.cx = 0;
-                AutoHideOffset.cy = h;
+                m_AutoHideOffset.cx = 0;
+                m_AutoHideOffset.cy = h;
                 break;
             }
 
             KillTimer(TIMER_ID_AUTOHIDE);
-            AutoHideState = AUTOHIDE_HIDDEN;
+            m_AutoHideState = AUTOHIDE_HIDDEN;
             break;
 
         case AUTOHIDE_SHOWING:
-            if (AutoHideOffset.cx >= AUTOHIDE_SPEED_SHOW)
+            if (m_AutoHideOffset.cx >= AUTOHIDE_SPEED_SHOW)
             {
-                AutoHideOffset.cx -= AUTOHIDE_SPEED_SHOW;
+                m_AutoHideOffset.cx -= AUTOHIDE_SPEED_SHOW;
             }
-            else if (AutoHideOffset.cx <= -AUTOHIDE_SPEED_SHOW)
+            else if (m_AutoHideOffset.cx <= -AUTOHIDE_SPEED_SHOW)
             {
-                AutoHideOffset.cx += AUTOHIDE_SPEED_SHOW;
+                m_AutoHideOffset.cx += AUTOHIDE_SPEED_SHOW;
             }
             else
             {
-                AutoHideOffset.cx = 0;
+                m_AutoHideOffset.cx = 0;
             }
 
-            if (AutoHideOffset.cy >= AUTOHIDE_SPEED_SHOW)
+            if (m_AutoHideOffset.cy >= AUTOHIDE_SPEED_SHOW)
             {
-                AutoHideOffset.cy -= AUTOHIDE_SPEED_SHOW;
+                m_AutoHideOffset.cy -= AUTOHIDE_SPEED_SHOW;
             }
-            else if (AutoHideOffset.cy <= -AUTOHIDE_SPEED_SHOW)
+            else if (m_AutoHideOffset.cy <= -AUTOHIDE_SPEED_SHOW)
             {
-                AutoHideOffset.cy += AUTOHIDE_SPEED_SHOW;
+                m_AutoHideOffset.cy += AUTOHIDE_SPEED_SHOW;
             }
             else
             {
-                AutoHideOffset.cy = 0;
+                m_AutoHideOffset.cy = 0;
+            }
+
+            if (m_AutoHideOffset.cx != 0 || m_AutoHideOffset.cy != 0)
+            {
+                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
+                break;
+            }
+
+            /* fallthrough */
+        case AUTOHIDE_SHOWN:
+
+            KillTimer(TIMER_ID_AUTOHIDE);
+            m_AutoHideState = AUTOHIDE_SHOWN;
+            break;
+        }
+
+        SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER);
+    }
+
+
+
+
+
+    /**********************************************************
+     *    ##### taskbar drawing #####
+     */
+
+    LRESULT EraseBackgroundWithTheme(HDC hdc)
+    {
+        RECT rect;
+        int iSBkgndPart[4] = {TBP_BACKGROUNDLEFT, TBP_BACKGROUNDTOP, TBP_BACKGROUNDRIGHT, TBP_BACKGROUNDBOTTOM};
+
+        ASSERT(m_Position <= ABE_BOTTOM);
+
+        if (m_Theme)
+        {
+            GetClientRect(&rect);
+            DrawThemeBackground(m_Theme, hdc, iSBkgndPart[m_Position], 0, &rect, 0);
+        }
+
+        return 0;
+    }
+
+    int DrawSizerWithTheme(IN HRGN hRgn)
+    {
+        HDC hdc;
+        RECT rect;
+        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(&rect);
+        OffsetRect(&rect, -rect.left, -rect.top);
+
+        hdc = GetWindowDC();
+
+        switch (m_Position)
+        {
+        case ABE_LEFT:
+            rect.left = rect.right - size.cx;
+            break;
+        case ABE_TOP:
+            rect.top = rect.bottom - size.cy;
+            break;
+        case ABE_RIGHT:
+            rect.right = rect.left + size.cx;
+            break;
+        case ABE_BOTTOM:
+        default:
+            rect.bottom = rect.top + size.cy;
+            break;
+        }
+
+        DrawThemeBackground(m_Theme, hdc, iSizerPart[m_Position], 0, &rect, 0);
+
+        ReleaseDC(hdc);
+        return 0;
+    }
+
+
+
+
+
+    /*
+     * ITrayWindow
+     */
+    HRESULT STDMETHODCALLTYPE Open()
+    {
+        RECT rcWnd;
+
+        /* 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;
+        }
+
+        DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE;
+        if (g_TaskbarSettings.sr.AlwaysOnTop)
+            dwExStyle |= WS_EX_TOPMOST;
+
+        DWORD dwStyle = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
+        if(!m_Theme)
+        {
+            dwStyle |= WS_THICKFRAME | WS_BORDER;
+        }
+
+        ZeroMemory(&rcWnd, sizeof(rcWnd));
+        if (m_Position != (DWORD) -1)
+            rcWnd = m_TrayRects[m_Position];
+
+        if (!Create(NULL, rcWnd, NULL, dwStyle, dwExStyle))
+            return E_FAIL;
+
+        /* Align all controls on the tray window */
+        AlignControls(NULL);
+
+        /* Move the tray window to the right position and resize it if necessary */
+        CheckTrayWndPosition();
+
+        return S_OK;
+    }
+
+    HRESULT STDMETHODCALLTYPE Close()
+    {
+        if (m_hWnd != NULL)
+        {
+            SendMessage(m_hWnd,
+                        WM_APP_TRAYDESTROY,
+                        0,
+                        0);
+        }
+
+        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();
+    }
+
+    BOOL STDMETHODCALLTYPE Lock(IN BOOL bLock)
+    {
+        BOOL bPrevLock = g_TaskbarSettings.bLock;
+
+        if (g_TaskbarSettings.bLock != bLock)
+        {
+            g_TaskbarSettings.bLock = bLock;
+
+            if (m_TrayBandSite != NULL)
+            {
+                if (!SUCCEEDED(m_TrayBandSite->Lock(bLock)))
+                {
+                    /* Reset?? */
+                    g_TaskbarSettings.bLock = bPrevLock;
+                    return bPrevLock;
+                }
+            }
+
+            if (m_Theme)
+            {
+                /* Update cached tray sizes */
+                for(DWORD Pos = ABE_LEFT; Pos <= ABE_BOTTOM; Pos++)
+                {
+                    RECT rcGripper = {0};
+                    AdjustSizerRect(&rcGripper, Pos);
+
+                    if(g_TaskbarSettings.bLock)
+                    {
+                        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);
+        }
+
+        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);
+    }
+
+    HRESULT STDMETHODCALLTYPE InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
+    {
+        if (!m_ContextMenu)
+            return E_INVALIDARG;
+
+        return m_ContextMenu->InvokeCommand(lpici);
+    }
+
+    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;
+
+        /* Create the tray notification window */
+        hRet = CTrayNotifyWnd_CreateInstance(m_hWnd, IID_PPV_ARG(IUnknown, &m_TrayNotifyInstance));
+        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;
+
+        /* Get the hwnd of the tray notification window */
+        hRet = IUnknown_GetWindow(m_TrayNotifyInstance, &m_TrayNotify);
+        if (FAILED_UNEXPECTEDLY(hRet))
+            return FALSE;
+
+        SetWindowTheme(m_Rebar, L"TaskBar", NULL);
+
+        UpdateFonts();
+
+        InitShellServices(&m_ShellServices);
+
+        if (g_TaskbarSettings.sr.AutoHide)
+        {
+            m_AutoHideState = AUTOHIDE_HIDING;
+            SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL);
+        }
+
+        /* Set the initial lock state in the band site */
+        m_TrayBandSite->Lock(g_TaskbarSettings.bLock);
+
+        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;
+    }
 
-            if (AutoHideOffset.cx != 0 || AutoHideOffset.cy != 0)
-            {
-                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
-                break;
-            }
+    LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        if (m_Theme)
+            CloseThemeData(m_Theme);
 
-            /* fallthrough */
-        case AUTOHIDE_SHOWN:
+        m_Theme = OpenThemeData(m_hWnd, L"TaskBar");
 
-            KillTimer(TIMER_ID_AUTOHIDE);
-            AutoHideState = AUTOHIDE_SHOWN;
-            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);
 
-        rc.left += AutoHideOffset.cx;
-        rc.right += AutoHideOffset.cx;
-        rc.top += AutoHideOffset.cy;
-        rc.bottom += AutoHideOffset.cy;
+        return TRUE;
+    }
+
+    LRESULT OnSettingChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        if (wParam == SPI_SETNONCLIENTMETRICS)
+        {
+            SendMessage(m_TrayNotify, uMsg, wParam, lParam);
+            SendMessage(m_TaskSwitch, uMsg, wParam, lParam);
+            UpdateFonts();
+            AlignControls(NULL);
+            CheckTrayWndPosition();
+        }
+
+        return 0;
+    }
+
+    LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        HDC hdc = (HDC) wParam;
+
+        if (!m_Theme)
+        {
+            bHandled = FALSE;
+            return 0;
+        }
 
-        TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc.left, rc.top, rc.right, rc.bottom, 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)
@@ -2199,33 +2333,32 @@ SetStartBtnImage:
         /* 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;
     }
 
     LRESULT OnCopyData(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
-        if (hwndTrayNotify)
-        {
-            TrayNotify_NotifyMsg(wParam, lParam);
-        }
+        if (m_TrayNotify)
+            ::SendMessageW(m_TrayNotify, uMsg, wParam, lParam);
         return TRUE;
     }
 
     LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
-        if (!TaskbarTheme)
+        if (!m_Theme)
         {
             bHandled = FALSE;
             return 0;
         }
+        else if (g_TaskbarSettings.bLock)
+        {
+            return 0;
+        }
 
-        return DrawSizer((HRGN) wParam);
+        return DrawSizerWithTheme((HRGN) wParam);
     }
 
     LRESULT OnCtlColorBtn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
@@ -2239,7 +2372,7 @@ SetStartBtnImage:
         RECT rcClient;
         POINT pt;
 
-        if (Locked)
+        if (g_TaskbarSettings.bLock)
         {
             /* The user may not be able to resize the tray window.
             Pretend like the window is not sizeable when the user
@@ -2249,13 +2382,12 @@ SetStartBtnImage:
 
         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);
 
-            if (PtInRect(&rcClient,
-                pt))
+            if (PtInRect(&rcClient, pt))
             {
                 /* The user is trying to drag the tray window */
                 return HTCAPTION;
@@ -2263,7 +2395,7 @@ SetStartBtnImage:
 
             /* Depending on the position of the tray window, allow only
             changing the border next to the monitor working area */
-            switch (Position)
+            switch (m_Position)
             {
             case ABE_TOP:
                 if (pt.y > rcClient.bottom)
@@ -2285,7 +2417,6 @@ SetStartBtnImage:
             }
         }
         return HTBORDER;
-        return TRUE;
     }
 
     LRESULT OnMoving(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
@@ -2298,25 +2429,14 @@ SetStartBtnImage:
         need to be able to move the window in case the user wants to
         drag the tray window to another position or in case the user
         wants to resize the tray window. */
-        if (!Locked && GetCursorPos(&ptCursor))
+        if (!g_TaskbarSettings.bLock && GetCursorPos(&ptCursor))
         {
             IsDragging = TRUE;
-            DraggingPosition = GetDraggingRectFromPt(
-                ptCursor,
-                pRect,
-                &DraggingMonitor);
+            m_DraggingPosition = GetDraggingRectFromPt(ptCursor, pRect, &m_DraggingMonitor);
         }
         else
         {
-            *pRect = rcTrayWnd[Position];
-
-            if (AutoHide)
-            {
-                pRect->left += AutoHideOffset.cx;
-                pRect->right += AutoHideOffset.cx;
-                pRect->top += AutoHideOffset.cy;
-                pRect->bottom += AutoHideOffset.cy;
-            }
+            *pRect = m_TrayRects[m_Position];
         }
         return TRUE;
     }
@@ -2325,26 +2445,18 @@ SetStartBtnImage:
     {
         PRECT pRect = (PRECT) lParam;
 
-        if (!Locked)
+        if (!g_TaskbarSettings.bLock)
         {
-            CalculateValidSize(Position, pRect);
+            FitToRebar(pRect);
         }
         else
         {
-            *pRect = rcTrayWnd[Position];
-
-            if (AutoHide)
-            {
-                pRect->left += AutoHideOffset.cx;
-                pRect->right += AutoHideOffset.cx;
-                pRect->top += AutoHideOffset.cy;
-                pRect->bottom += AutoHideOffset.cy;
-            }
+            *pRect = m_TrayRects[m_Position];
         }
         return TRUE;
     }
 
-    LRESULT OnWindowPosChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    LRESULT OnWindowPosChanging(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
         ChangingWinPos((LPWINDOWPOS) lParam);
         return TRUE;
@@ -2353,7 +2465,6 @@ SetStartBtnImage:
     LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
         RECT rcClient;
-        InvalidateRect(NULL, TRUE);
         if (wParam == SIZE_RESTORED && lParam == 0)
         {
             ResizeWorkArea();
@@ -2381,7 +2492,7 @@ SetStartBtnImage:
     {
         InSizeMove = TRUE;
         IsDragging = FALSE;
-        if (!Locked)
+        if (!g_TaskbarSettings.bLock)
         {
             /* Remove the clipping on multi monitor systems while dragging around */
             ApplyClipping(FALSE);
@@ -2392,10 +2503,12 @@ SetStartBtnImage:
     LRESULT OnExitSizeMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
         InSizeMove = FALSE;
-        if (!Locked)
+        if (!g_TaskbarSettings.bLock)
         {
+            FitToRebar(&m_TrayRects[m_Position]);
+
             /* Apply clipping */
-            PostMessage(m_hWnd, WM_SIZE, SIZE_RESTORED, 0);
+            PostMessage(WM_SIZE, SIZE_RESTORED, 0);
         }
         return TRUE;
     }
@@ -2418,17 +2531,16 @@ SetStartBtnImage:
                 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],
@@ -2444,15 +2556,12 @@ SetStartBtnImage:
                 uId = TrackMenu(
                     hSysMenu,
                     NULL,
-                    StartButton.m_hWnd,
-                    Position != ABE_TOP,
+                    m_StartButton.m_hWnd,
+                    m_Position != ABE_TOP,
                     FALSE);
                 if (uId != 0)
                 {
-                    SendMessage(m_hWnd,
-                                WM_SYSCOMMAND,
-                                (WPARAM) uId,
-                                0);
+                    SendMessage(m_hWnd, WM_SYSCOMMAND, (WPARAM) uId, 0);
                 }
             }
 
@@ -2467,6 +2576,63 @@ SetStartBtnImage:
         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
@@ -2493,45 +2659,44 @@ SetStartBtnImage:
         if (pt.x != -1 || pt.y != -1)
             ppt = &pt;
         else
-            hWndExclude = StartButton.m_hWnd;
+            hWndExclude = m_StartButton.m_hWnd;
 
-        if ((HWND) wParam == StartButton.m_hWnd)
+        if ((HWND) wParam == m_StartButton.m_hWnd)
         {
             /* Make sure we can't track the context menu if the start
             menu is currently being shown */
-            if (!(StartButton.SendMessage(BM_GETSTATE, 0, 0) & BST_PUSHED))
+            if (!(m_StartButton.SendMessage(BM_GETSTATE, 0, 0) & BST_PUSHED))
             {
                 CComPtr<IContextMenu> ctxMenu;
                 StartMenuBtnCtxMenuCreator(this, m_hWnd, &ctxMenu);
-                TrackCtxMenu(ctxMenu, ppt, hWndExclude, Position == ABE_BOTTOM, this);
+                TrackCtxMenu(ctxMenu, ppt, hWndExclude, m_Position == ABE_BOTTOM, this);
             }
         }
         else
         {
             /* See if the context menu should be handled by the task band site */
-            if (ppt != NULL && TrayBandSite != NULL)
+            if (ppt != NULL && m_TrayBandSite != NULL)
             {
                 HWND hWndAtPt;
                 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 == hwndRebar || IsChild(hwndRebar,
-                    hWndAtPt)))
+                    (hWndAtPt == m_Rebar || ::IsChild(m_Rebar, hWndAtPt)))
                 {
                     /* Check if the user clicked on the task switch window */
                     ptClient = *ppt;
-                    MapWindowPoints(NULL, hwndRebar, &ptClient, 1);
+                    ::MapWindowPoints(NULL, m_Rebar, &ptClient, 1);
 
-                    hWndAtPt = ChildWindowFromPointEx(hwndRebar, ptClient, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED);
-                    if (hWndAtPt == hwndTaskSwitch)
+                    hWndAtPt = ::ChildWindowFromPointEx(m_Rebar, ptClient, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED);
+                    if (hWndAtPt == m_TaskSwitch)
                         goto HandleTrayContextMenu;
 
                     /* Forward the message to the task band site */
-                    TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret);
+                    m_TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret);
                 }
                 else
                     goto HandleTrayContextMenu;
@@ -2540,9 +2705,7 @@ SetStartBtnImage:
             {
 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;
@@ -2557,24 +2720,24 @@ HandleTrayContextMenu:
 
         HRESULT hr = E_FAIL;
 
-        if (TrayBandSite)
+        if (m_TrayBandSite)
         {
-            hr = TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret);
+            hr = m_TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret);
             if (SUCCEEDED(hr))
                 return Ret;
         }
 
-        if (TrayBandSite == NULL || FAILED(hr))
+        if (m_TrayBandSite == NULL || FAILED(hr))
         {
             const NMHDR *nmh = (const NMHDR *) lParam;
 
-            if (nmh->hwndFrom == hwndTrayNotify)
+            if (nmh->hwndFrom == m_TrayNotify)
             {
                 switch (nmh->code)
                 {
                 case NTNWM_REALIGN:
                     /* Cause all controls to be aligned */
-                    PostMessage(m_hWnd, WM_SIZE, SIZE_RESTORED, 0);
+                    PostMessage(WM_SIZE, SIZE_RESTORED, 0);
                     break;
                 }
             }
@@ -2584,23 +2747,11 @@ HandleTrayContextMenu:
 
     LRESULT OnNcLButtonDblClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
+        /* Let the clock handle the double click */
+        ::SendMessageW(m_TrayNotify, uMsg, wParam, lParam);
+
         /* We "handle" this message so users can't cause a weird maximize/restore
         window animation when double-clicking the tray window! */
-
-        /* We should forward mouse messages to child windows here.
-        Right now, this is only clock double-click */
-        RECT rcClock;
-        if (TrayNotify_GetClockRect(&rcClock))
-        {
-            POINT ptClick;
-            ptClick.x = MAKEPOINTS(lParam).x;
-            ptClick.y = MAKEPOINTS(lParam).y;
-            if (PtInRect(&rcClock, ptClick))
-            {
-                //FIXME: use SHRunControlPanel
-                ShellExecuteW(m_hWnd, NULL, L"timedate.cpl", NULL, NULL, SW_NORMAL);
-            }
-        }
         return TRUE;
     }
 
@@ -2613,13 +2764,13 @@ HandleTrayContextMenu:
     LRESULT OnOpenStartMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
         HWND hwndStartMenu;
-        HRESULT hr = IUnknown_GetWindow((IUnknown*) StartMenuPopup, &hwndStartMenu);
+        HRESULT hr = IUnknown_GetWindow(m_StartMenuPopup, &hwndStartMenu);
         if (FAILED_UNEXPECTEDLY(hr))
             return FALSE;
 
-        if (IsWindowVisible(hwndStartMenu))
+        if (::IsWindowVisible(hwndStartMenu))
         {
-            StartMenuPopup->OnSelect(MPOS_CANCELLEVEL);
+            m_StartMenuPopup->OnSelect(MPOS_CANCELLEVEL);
         }
         else
         {
@@ -2629,17 +2780,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();
     }
@@ -2655,119 +2801,112 @@ HandleTrayContextMenu:
         return TRUE;
     }
 
-    HRESULT ExecResourceCmd(int id)
+    LRESULT OnHotkey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
-        WCHAR szCommand[256];
-        WCHAR *pszParameters;
+        return HandleHotKey(wParam);
+    }
+
+    struct MINIMIZE_INFO
+    {
+        HWND hwndDesktop;
+        HWND hTrayWnd;
+        HWND hwndProgman;
+        BOOL bRet;
+        CSimpleArray<HWND> *pMinimizedAll;
+        BOOL bShowDesktop;
+    };
+
+    static BOOL IsDialog(HWND hwnd)
+    {
+        WCHAR szClass[32];
+        GetClassNameW(hwnd, szClass, _countof(szClass));
+        return wcscmp(szClass, L"#32770") == 0;
+    }
 
-        if (!LoadString(hExplorerInstance,
-                        id,
-                        szCommand,
-                        sizeof(szCommand) / sizeof(szCommand[0])))
+    static BOOL CALLBACK MinimizeWindowsProc(HWND hwnd, LPARAM lParam)
+    {
+        MINIMIZE_INFO *info = (MINIMIZE_INFO *)lParam;
+        if (hwnd == info->hwndDesktop || hwnd == info->hTrayWnd ||
+            hwnd == info->hwndProgman)
         {
-            return E_FAIL;
+            return TRUE;
         }
+        if (!info->bShowDesktop)
+        {
+            if (!::IsWindowEnabled(hwnd) || IsDialog(hwnd))
+                return TRUE;
+            HWND hwndOwner = ::GetWindow(hwnd, GW_OWNER);
+            if (hwndOwner && !::IsWindowEnabled(hwndOwner))
+                return TRUE;
+        }
+        if (::IsWindowVisible(hwnd) && !::IsIconic(hwnd))
+        {
+            ::ShowWindowAsync(hwnd, SW_MINIMIZE);
+            info->bRet = TRUE;
+            info->pMinimizedAll->Add(hwnd);
+        }
+        return TRUE;
+    }
 
-        pszParameters = wcschr(szCommand, L'>');
-        if (!pszParameters)
-            return E_FAIL;
+    VOID MinimizeAll(BOOL bShowDesktop = FALSE)
+    {
+        MINIMIZE_INFO info;
+        info.hwndDesktop = GetDesktopWindow();;
+        info.hTrayWnd = FindWindowW(L"Shell_TrayWnd", NULL);
+        info.hwndProgman = FindWindowW(L"Progman", NULL);
+        info.bRet = FALSE;
+        info.pMinimizedAll = &g_MinimizedAll;
+        info.bShowDesktop = bShowDesktop;
+        EnumWindows(MinimizeWindowsProc, (LPARAM)&info);
 
-        *pszParameters = 0;
-        pszParameters++;
+        // invalid handles should be cleared to avoid mismatch of handles
+        for (INT i = 0; i < g_MinimizedAll.GetSize(); ++i)
+        {
+            if (!::IsWindow(g_MinimizedAll[i]))
+                g_MinimizedAll[i] = NULL;
+        }
 
-        ShellExecuteW(m_hWnd, NULL, szCommand, pszParameters, NULL, 0);
-        return S_OK;
+        ::SetForegroundWindow(m_DesktopWnd);
+        ::SetFocus(m_DesktopWnd);
     }
 
-    LRESULT OnHotkey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    VOID ShowDesktop()
     {
-        switch (wParam)
+        MinimizeAll(TRUE);
+    }
+
+    VOID RestoreAll()
+    {
+        for (INT i = g_MinimizedAll.GetSize() - 1; i >= 0; --i)
         {
-        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;
+            HWND hwnd = g_MinimizedAll[i];
+            if (::IsWindowVisible(hwnd) && ::IsIconic(hwnd))
+            {
+                ::ShowWindow(hwnd, SW_RESTORE);
+            }
         }
-
-        return 0;
+        g_MinimizedAll.RemoveAll();
     }
 
     LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
         LRESULT Ret = FALSE;
 
-        if ((HWND) lParam == StartButton.m_hWnd)
+        if ((HWND) lParam == m_StartButton.m_hWnd)
         {
-            PopupStartMenu();
             return FALSE;
         }
 
-        if (TrayBandSite == NULL || FAILED_UNEXPECTEDLY(TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret)))
+        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;
     }
 
     LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
-        if (AutoHide)
+        if (g_TaskbarSettings.sr.AutoHide)
         {
             SetTimer(TIMER_ID_MOUSETRACK, MOUSETRACK_INTERVAL, NULL);
         }
@@ -2790,6 +2929,53 @@ 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 || g_TaskbarSettings.bLock)
+        {
+            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 OnInitMenuPopup(INT code, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        HMENU hMenu = (HMENU)wParam;
+        if (::IsThereAnyEffectiveWindow(FALSE))
+        {
+            ::EnableMenuItem(hMenu, ID_SHELL_CMD_CASCADE_WND, MF_BYCOMMAND | MF_ENABLED);
+            ::EnableMenuItem(hMenu, ID_SHELL_CMD_TILE_WND_H, MF_BYCOMMAND | MF_ENABLED);
+            ::EnableMenuItem(hMenu, ID_SHELL_CMD_TILE_WND_V, MF_BYCOMMAND | MF_ENABLED);
+        }
+        else
+        {
+            ::EnableMenuItem(hMenu, ID_SHELL_CMD_CASCADE_WND, MF_BYCOMMAND | MF_GRAYED);
+            ::EnableMenuItem(hMenu, ID_SHELL_CMD_TILE_WND_H, MF_BYCOMMAND | MF_GRAYED);
+            ::EnableMenuItem(hMenu, ID_SHELL_CMD_TILE_WND_V, MF_BYCOMMAND | MF_GRAYED);
+        }
+        return 0;
+    }
+
     LRESULT OnRebarAutoSize(INT code, LPNMHDR nmhdr, BOOL& bHandled)
     {
 #if 0
@@ -2801,14 +2987,14 @@ HandleTrayContextMenu:
         RECT rc;
         ::GetWindowRect(m_hWnd, &rc);
 
-        SIZE szWindow = { 
-            rc.right - rc.left, 
+        SIZE szWindow = {
+            rc.right - rc.left,
             rc.bottom - rc.top };
-        SIZE szTarget = { 
-            as->rcTarget.right - as->rcTarget.left, 
+        SIZE szTarget = {
+            as->rcTarget.right - as->rcTarget.left,
             as->rcTarget.bottom - as->rcTarget.top };
-        SIZE szActual = { 
-            as->rcActual.right - as->rcActual.left, 
+        SIZE szActual = {
+            as->rcActual.right - as->rcActual.left,
             as->rcActual.bottom - as->rcActual.top };
 
         SIZE borders = {
@@ -2816,7 +3002,7 @@ HandleTrayContextMenu:
             szWindow.cy - szTarget.cx,
         };
 
-        switch (Position)
+        switch (m_Position)
         {
         case ABE_LEFT:
             szWindow.cx = szActual.cx + borders.cx;
@@ -2841,10 +3027,45 @@ HandleTrayContextMenu:
         return 0;
     }
 
+    LRESULT OnTaskbarSettingsChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        TaskbarSettings* newSettings = (TaskbarSettings*)lParam;
+
+        /* Propagate the new settings to the children */
+        ::SendMessageW(m_TaskSwitch, uMsg, wParam, lParam);
+        ::SendMessageW(m_TrayNotify, uMsg, wParam, lParam);
+
+        /* Toggle autohide */
+        if (newSettings->sr.AutoHide != g_TaskbarSettings.sr.AutoHide)
+        {
+            g_TaskbarSettings.sr.AutoHide = newSettings->sr.AutoHide;
+            memset(&m_AutoHideOffset, 0, sizeof(m_AutoHideOffset));
+            m_AutoHideState = AUTOHIDE_SHOWN;
+            if (!newSettings->sr.AutoHide)
+                SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER);
+            else
+                SetTimer(TIMER_ID_MOUSETRACK, MOUSETRACK_INTERVAL, NULL);
+        }
+
+        /* Toggle lock state */
+        Lock(newSettings->bLock);
+
+        /* Toggle OnTop state */
+        if (newSettings->sr.AlwaysOnTop != g_TaskbarSettings.sr.AlwaysOnTop)
+        {
+            g_TaskbarSettings.sr.AlwaysOnTop = newSettings->sr.AlwaysOnTop;
+            HWND hWndInsertAfter = newSettings->sr.AlwaysOnTop ? HWND_TOPMOST : HWND_BOTTOM;
+            SetWindowPos(hWndInsertAfter, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
+        }
+
+        g_TaskbarSettings.Save();
+        return 0;
+    }
+
     DECLARE_WND_CLASS_EX(szTrayWndClass, CS_DBLCLKS, COLOR_3DFACE)
 
     BEGIN_MSG_MAP(CTrayWindow)
-        if (StartMenuBand != NULL)
+        if (m_StartMenuBand != NULL)
         {
             MSG Msg;
             LRESULT lRet;
@@ -2854,7 +3075,7 @@ HandleTrayContextMenu:
             Msg.wParam = wParam;
             Msg.lParam = lParam;
 
-            if (StartMenuBand->TranslateMenuMessage(&Msg, &lRet) == S_OK)
+            if (m_StartMenuBand->TranslateMenuMessage(&Msg, &lRet) == S_OK)
             {
                 return lRet;
             }
@@ -2863,6 +3084,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)
@@ -2880,18 +3102,23 @@ HandleTrayContextMenu:
         MESSAGE_HANDLER(WM_CTLCOLORBTN, OnCtlColorBtn)
         MESSAGE_HANDLER(WM_MOVING, OnMoving)
         MESSAGE_HANDLER(WM_SIZING, OnSizing)
-        MESSAGE_HANDLER(WM_WINDOWPOSCHANGING, OnWindowPosChange)
+        MESSAGE_HANDLER(WM_WINDOWPOSCHANGING, OnWindowPosChanging)
         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)
         MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
         MESSAGE_HANDLER(WM_NCMOUSEMOVE, OnMouseMove)
         MESSAGE_HANDLER(WM_APP_TRAYDESTROY, OnAppTrayDestroy)
+        MESSAGE_HANDLER(WM_CLOSE, OnDoExitWindows)
+        MESSAGE_HANDLER(WM_HOTKEY, OnHotkey)
+        MESSAGE_HANDLER(WM_NCCALCSIZE, OnNcCalcSize)
+        MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup)
+        MESSAGE_HANDLER(TWM_SETTINGSCHANGED, OnTaskbarSettingsChanged)
         MESSAGE_HANDLER(TWM_OPENSTARTMENU, OnOpenStartMenu)
         MESSAGE_HANDLER(TWM_DOEXITWINDOWS, OnDoExitWindows)
-        MESSAGE_HANDLER(WM_HOTKEY, OnHotkey)
     ALT_MSG_MAP(1)
     END_MSG_MAP()
 
@@ -2903,18 +3130,13 @@ HandleTrayContextMenu:
 
         /* FIXME: We should keep a reference here... */
 
-        while (PeekMessage(&Msg,
-            NULL,
-            0,
-            0,
-            PM_REMOVE))
+        while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
         {
             if (Msg.message == WM_QUIT)
                 break;
 
-            if (StartMenuBand == NULL ||
-                StartMenuBand->IsMenuMessage(
-                &Msg) != S_OK)
+            if (m_StartMenuBand == NULL ||
+                m_StartMenuBand->IsMenuMessage(&Msg) != S_OK)
             {
                 TranslateMessage(&Msg);
                 DispatchMessage(&Msg);
@@ -2929,15 +3151,15 @@ HandleTrayContextMenu:
 
         /* FIXME: We should keep a reference here... */
 
-        while (1)
+        while (true)
         {
             Ret = GetMessage(&Msg, NULL, 0, 0);
 
             if (!Ret || Ret == -1)
                 break;
 
-            if (StartMenuBand == NULL ||
-                StartMenuBand->IsMenuMessage(&Msg) != S_OK)
+            if (m_StartMenuBand == NULL ||
+                m_StartMenuBand->IsMenuMessage(&Msg) != S_OK)
             {
                 TranslateMessage(&Msg);
                 DispatchMessage(&Msg);
@@ -2973,7 +3195,7 @@ HandleTrayContextMenu:
     {
         TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop);
 
-        this->hWndDesktop = hWndDesktop;
+        m_DesktopWnd = hWndDesktop;
         return S_OK;
     }
 
@@ -2985,13 +3207,26 @@ HandleTrayContextMenu:
 
     virtual HRESULT RaiseStartButton()
     {
-        StartButton.SendMessageW(BM_SETSTATE, FALSE, 0);
+        m_StartButton.SendMessageW(BM_SETSTATE, FALSE, 0);
+        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()
     {
-        Position = (DWORD) -1;
+        m_Position = (DWORD) -1;
     }
 
     DECLARE_NOT_AGGREGATABLE(CTrayWindow)
@@ -3000,6 +3235,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()
 };
 
@@ -3011,49 +3248,41 @@ 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;
     }
 
-    virtual HRESULT STDMETHODCALLTYPE 
+    virtual HRESULT STDMETHODCALLTYPE
         QueryContextMenu(HMENU hPopup,
                          UINT indexMenu,
                          UINT idCmdFirst,
                          UINT idCmdLast,
                          UINT uFlags)
     {
-        HMENU menubase = LoadPopupMenu(hExplorerInstance, MAKEINTRESOURCE(IDM_TRAYWND));
-
-        if (!menubase)
-            return HRESULT_FROM_WIN32(GetLastError());
+        HMENU hMenuBase;
 
-        int count = ::GetMenuItemCount(menubase);
+        hMenuBase = LoadPopupMenu(hExplorerInstance, MAKEINTRESOURCEW(IDM_TRAYWND));
 
-        for (int i = 0; i < count; i++)
+        if (g_MinimizedAll.GetSize() != 0 && !::IsThereAnyEffectiveWindow(TRUE))
         {
-            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);
+            CStringW strRestoreAll(MAKEINTRESOURCEW(IDS_RESTORE_ALL));
+            MENUITEMINFOW mii = { sizeof(mii) };
+            mii.fMask = MIIM_ID | MIIM_TYPE;
+            mii.wID = ID_SHELL_CMD_RESTORE_ALL;
+            mii.fType = MFT_STRING;
+            mii.dwTypeData = const_cast<LPWSTR>(&strRestoreAll[0]);
+            SetMenuItemInfoW(hMenuBase, ID_SHELL_CMD_SHOW_DESKTOP, FALSE, &mii);
         }
 
-        ::DestroyMenu(menubase);
+        if (!hMenuBase)
+            return HRESULT_FROM_WIN32(GetLastError());
 
         if (SHRestricted(REST_CLASSICSHELL) != 0)
         {
@@ -3062,17 +3291,23 @@ public:
                        MF_BYCOMMAND);
         }
 
-        CheckMenuItem(hPopup,
+        CheckMenuItem(hMenuBase,
                       ID_LOCKTASKBAR,
-                      MF_BYCOMMAND | (TrayWnd->Locked ? MF_CHECKED : MF_UNCHECKED));
+                      MF_BYCOMMAND | (g_TaskbarSettings.bLock ? MF_CHECKED : MF_UNCHECKED));
 
-        if (TrayWnd->TrayBandSite != NULL)
+        UINT idCmdNext;
+        idCmdNext = Shell_MergeMenus(hPopup, hMenuBase, indexMenu, idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS | MM_ADDSEPARATOR);
+        m_idCmdCmFirst = idCmdNext - idCmdFirst;
+
+        ::DestroyMenu(hMenuBase);
+
+        if (TrayWnd->m_TrayBandSite != NULL)
         {
-            if (FAILED(TrayWnd->TrayBandSite->AddContextMenus(
+            if (FAILED(TrayWnd->m_TrayBandSite->AddContextMenus(
                 hPopup,
-                0,
-                ID_SHELL_CMD_FIRST,
-                ID_SHELL_CMD_LAST,
+                indexMenu,
+                idCmdNext,
+                idCmdLast,
                 CMF_NORMAL,
                 &pcm)))
             {
@@ -3090,7 +3325,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 };
 
@@ -3099,7 +3334,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);
@@ -3145,15 +3380,6 @@ HRESULT TrayWindowCtxMenuCreator(ITrayWindow * TrayWnd, IN HWND hWndOwner, ICont
     return S_OK;
 }
 
-CTrayWindow * g_TrayWindow;
-
-HRESULT
-Tray_OnStartMenuDismissed()
-{
-    return g_TrayWindow->RaiseStartButton();
-}
-
-
 HRESULT CreateTrayWindow(ITrayWindow ** ppTray)
 {
     CComPtr<CTrayWindow> Tray = new CComObject<CTrayWindow>();
@@ -3162,19 +3388,27 @@ HRESULT CreateTrayWindow(ITrayWindow ** ppTray)
 
     Tray->_Init();
     Tray->Open();
-    g_TrayWindow = Tray;
 
     *ppTray = (ITrayWindow *) Tray;
 
     return S_OK;
 }
 
-VOID TrayProcessMessages(ITrayWindow *)
+HRESULT
+Tray_OnStartMenuDismissed(ITrayWindow* Tray)
+{
+    CTrayWindow * TrayWindow = static_cast<CTrayWindow *>(Tray);
+    return TrayWindow->RaiseStartButton();
+}
+
+VOID TrayProcessMessages(ITrayWindow *Tray)
 {
-    g_TrayWindow->TrayProcessMessages();
+    CTrayWindow * TrayWindow = static_cast<CTrayWindow *>(Tray);
+    TrayWindow->TrayProcessMessages();
 }
 
-VOID TrayMessageLoop(ITrayWindow *)
+VOID TrayMessageLoop(ITrayWindow *Tray)
 {
-    g_TrayWindow->TrayMessageLoop();
+    CTrayWindow * TrayWindow = static_cast<CTrayWindow *>(Tray);
+    TrayWindow->TrayMessageLoop();
 }