[EXPLORER_NEW]
authorThomas Faber <thomas.faber@reactos.org>
Sun, 23 Dec 2012 14:37:22 +0000 (14:37 +0000)
committerThomas Faber <thomas.faber@reactos.org>
Sun, 23 Dec 2012 14:37:22 +0000 (14:37 +0000)
- Add support for task bar theming
- Add notification area support
- Add support for window flashing
- Hide minimized windows
- Based on Andrew Green's GSoC branch (3/3)

svn path=/trunk/; revision=57978

reactos/base/shell/explorer-new/CMakeLists.txt
reactos/base/shell/explorer-new/precomp.h
reactos/base/shell/explorer-new/taskswnd.c
reactos/base/shell/explorer-new/trayntfy.c
reactos/base/shell/explorer-new/traywnd.c

index 2e1122e..b2494a8 100644 (file)
@@ -17,6 +17,19 @@ list(APPEND SOURCE
 add_executable(explorer_new ${SOURCE})
 target_link_libraries(explorer_new uuid)
 set_module_type(explorer_new win32gui UNICODE)
-add_importlibs(explorer_new advapi32 gdi32 user32 comctl32 ole32 oleaut32 shell32 shlwapi version msvcrt kernel32 ntdll)
+add_importlibs(explorer_new
+    advapi32
+    gdi32
+    user32
+    comctl32
+    ole32
+    oleaut32
+    shell32
+    shlwapi
+    version
+    uxtheme
+    msvcrt
+    kernel32
+    ntdll)
 add_pch(explorer_new precomp.h)
 add_cd_file(TARGET explorer_new DESTINATION reactos FOR all)
index 64f3ce7..66db62d 100644 (file)
@@ -17,7 +17,9 @@
 #include <tchar.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <uxtheme.h>
 
+#include "tmschema.h"
 #include "resource.h"
 #include "comcsup.h"
 #include "todo.h"
@@ -384,6 +386,11 @@ HWND
 CreateTrayNotifyWnd(IN OUT ITrayWindow *TrayWindow,
                     IN BOOL bHideClock);
 
+VOID
+TrayNotify_NotifyMsg(IN HWND hwnd,
+                     IN WPARAM wParam,
+                     IN LPARAM lParam);
+
 /*
  * taskswnd.c
  */
index 332b65b..847ed99 100644 (file)
 
 #include <precomp.h>
 
-/* By default we don't use DrawCaptionTemp() because it causes some minimal
-   drawing glitches with the toolbar custom painting code */
-#define TASK_USE_DRAWCAPTIONTEMP    1
-
 /* Set DUMP_TASKS to 1 to enable a dump of the tasks and task groups every
    5 seconds */
 #define DUMP_TASKS  0
@@ -47,14 +43,6 @@ typedef struct _TASK_GROUP
         struct
         {
 
-#if TASK_USE_DRAWCAPTIONTEMP != 0
-
-            /* DisplayTooltip is TRUE when the group button text didn't fit into
-               the button. */
-            DWORD DisplayTooltip : 1;
-
-#endif
-
             DWORD IsCollapsed : 1;
         };
     };
@@ -65,12 +53,9 @@ typedef struct _TASK_ITEM
     HWND hWnd;
     PTASK_GROUP Group;
     INT Index;
-
-#if !(TASK_USE_DRAWCAPTIONTEMP != 0)
-
     INT IconIndex;
 
-#endif
+
 
     union
     {
@@ -78,14 +63,6 @@ typedef struct _TASK_ITEM
         struct
         {
 
-#if TASK_USE_DRAWCAPTIONTEMP != 0
-
-            /* DisplayTooltip is TRUE when the window text didn't fit into the
-               button. */
-            DWORD DisplayTooltip : 1;
-
-#endif
-
             /* IsFlashing is TRUE when the task bar item should be flashing. */
             DWORD IsFlashing : 1;
 
@@ -113,9 +90,11 @@ typedef struct _TASK_SWITCH_WND
     PTASK_ITEM TaskItems;
     PTASK_ITEM ActiveTaskItem;
 
+    HTHEME TaskBandTheme;
     HWND hWndToolbar;
     UINT TbButtonsPerLine;
     WORD ToolbarBtnCount;
+    HIMAGELIST TaskIcons;
 
     union
     {
@@ -139,12 +118,6 @@ typedef struct _TASK_SWITCH_WND
 static VOID TaskSwitchWnd_UpdateButtonsSize(IN OUT PTASK_SWITCH_WND This,
                                             IN BOOL bRedrawDisabled);
 
-#if TASK_USE_DRAWCAPTIONTEMP != 0
-
-#define TaskSwitchWnd_GetWndTextFromTaskItem(a,b) NULL
-
-#else /* !TASK_USE_DRAWCAPTIONTEMP */
-
 static LPTSTR
 TaskSwitchWnd_GetWndTextFromTaskItem(IN OUT PTASK_SWITCH_WND This,
                                      IN PTASK_ITEM TaskItem)
@@ -161,7 +134,6 @@ TaskSwitchWnd_GetWndTextFromTaskItem(IN OUT PTASK_SWITCH_WND This,
     return NULL;
 }
 
-#endif
 
 #if DUMP_TASKS != 0
 static VOID
@@ -408,20 +380,45 @@ TaskSwitchWnd_ExpandTaskGroup(IN OUT PTASK_SWITCH_WND This,
     /* FIXME: Implement */
 }
 
+static HICON
+TaskSwitchWnd_GetWndIcon(HWND hwnd)
+{
+    HICON hIcon = 0;
+
+    SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL2, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
+
+    if (!hIcon)
+       SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
+
+    if (!hIcon)
+       SendMessageTimeout(hwnd, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
+
+    if (!hIcon)
+       hIcon = (HICON)GetClassLongPtr(hwnd, GCL_HICONSM);
+
+    if (!hIcon)
+       hIcon = (HICON)GetClassLongPtr(hwnd, GCL_HICON);
+
+    return hIcon;
+}
 static INT
 TaskSwitchWnd_UpdateTaskItemButton(IN OUT PTASK_SWITCH_WND This,
                                    IN PTASK_ITEM TaskItem)
 {
     TBBUTTONINFO tbbi;
+    HICON icon;
 
     ASSERT(TaskItem->Index >= 0);
 
     tbbi.cbSize = sizeof(tbbi);
-    tbbi.dwMask = TBIF_BYINDEX | TBIF_STATE | TBIF_TEXT;
+    tbbi.dwMask = TBIF_BYINDEX | TBIF_STATE | TBIF_TEXT | TBIF_IMAGE;
     tbbi.fsState = TBSTATE_ENABLED;
     if (This->ActiveTaskItem == TaskItem)
         tbbi.fsState |= TBSTATE_CHECKED;
 
+    if (TaskItem->RenderFlashed)
+        tbbi.fsState |= TBSTATE_MARKED;
+
     /* Check if we're updating a button that is the last one in the
        line. If so, we need to set the TBSTATE_WRAP flag! */
     if (This->TbButtonsPerLine != 0 &&
@@ -433,6 +430,10 @@ TaskSwitchWnd_UpdateTaskItemButton(IN OUT PTASK_SWITCH_WND This,
     tbbi.pszText = TaskSwitchWnd_GetWndTextFromTaskItem(This,
                                                         TaskItem);
 
+    icon = TaskSwitchWnd_GetWndIcon(TaskItem->hWnd);
+    TaskItem->IconIndex = ImageList_ReplaceIcon(This->TaskIcons,TaskItem->IconIndex,icon);
+    tbbi.iImage = TaskItem->IconIndex;
+
     if (!SendMessage(This->hWndToolbar,
                      TB_SETBUTTONINFO,
                      (WPARAM)TaskItem->Index,
@@ -446,6 +447,39 @@ TaskSwitchWnd_UpdateTaskItemButton(IN OUT PTASK_SWITCH_WND This,
     return TaskItem->Index;
 }
 
+static VOID
+TaskSwitchWnd_RemoveIcon(IN OUT PTASK_SWITCH_WND This,
+                         IN PTASK_ITEM TaskItem)
+{
+    TBBUTTONINFO tbbi;
+    PTASK_ITEM currentTaskItem,LastItem;
+
+    if (TaskItem->IconIndex==-1)
+        return;
+
+    tbbi.cbSize = sizeof(tbbi);
+    tbbi.dwMask = TBIF_IMAGE;
+
+    currentTaskItem = This->TaskItems;
+    LastItem = currentTaskItem + This->TaskItemCount;
+    while (currentTaskItem != LastItem)
+    {
+        if (currentTaskItem->IconIndex > TaskItem->IconIndex)
+        {
+            currentTaskItem->IconIndex--;
+            tbbi.iImage = currentTaskItem->IconIndex;
+
+            SendMessage(This->hWndToolbar,
+                        TB_SETBUTTONINFO,
+                        currentTaskItem->Index,
+                        (LPARAM)&tbbi);
+        }
+        currentTaskItem++;
+    }
+
+    ImageList_Remove(This->TaskIcons, TaskItem->IconIndex);
+}
+
 static PTASK_ITEM
 TaskSwitchWnd_FindLastTaskItemOfGroup(IN OUT PTASK_SWITCH_WND This,
                                       IN PTASK_GROUP TaskGroup  OPTIONAL,
@@ -541,6 +575,7 @@ TaskSwitchWnd_AddTaskItemButton(IN OUT PTASK_SWITCH_WND This,
 {
     TBBUTTON tbBtn;
     INT iIndex;
+    HICON icon;
 
     if (TaskItem->Index >= 0)
     {
@@ -556,7 +591,10 @@ TaskSwitchWnd_AddTaskItemButton(IN OUT PTASK_SWITCH_WND This,
                                                    TaskItem->Group);
     }
 
-    tbBtn.iBitmap = 0;
+    icon = TaskSwitchWnd_GetWndIcon(TaskItem->hWnd);
+    TaskItem->IconIndex = ImageList_AddIcon(This->TaskIcons, icon);
+
+    tbBtn.iBitmap = TaskItem->IconIndex;
     tbBtn.fsState = TBSTATE_ENABLED | TBSTATE_ELLIPSES;
     tbBtn.fsStyle = BTNS_CHECK | BTNS_NOPREFIX | BTNS_SHOWTEXT;
     tbBtn.dwData = TaskItem->Index;
@@ -612,6 +650,7 @@ TaskSwitchWnd_DeleteTaskItemButton(IN OUT PTASK_SWITCH_WND This,
         {
             TaskSwitchWnd_BeginUpdate(This);
 
+            TaskSwitchWnd_RemoveIcon(This, TaskItem);
             iIndex = TaskItem->Index;
             if (SendMessage(This->hWndToolbar,
                             TB_DELETEBUTTON,
@@ -1107,7 +1146,9 @@ static VOID
 TaskSwitchWnd_FlashTaskItem(IN OUT PTASK_SWITCH_WND This,
                             IN OUT PTASK_ITEM TaskItem)
 {
-    /* FIXME: Implement */
+    TaskItem->RenderFlashed = 1;
+    TaskSwitchWnd_UpdateTaskItemButton(This,
+                                       TaskItem);
 }
 
 static BOOL
@@ -1151,6 +1192,7 @@ TaskSwitchWnd_RedrawTaskItem(IN OUT PTASK_SWITCH_WND This,
     else if (TaskItem->Index >= 0)
     {
 UpdateTaskItem:
+        TaskItem->RenderFlashed = 0;
         TaskSwitchWnd_UpdateTaskItemButton(This,
                                            TaskItem);
     }
@@ -1386,6 +1428,18 @@ TaskSwichWnd_ToolbarSubclassedProc(IN HWND hWnd,
     return Ret;
 }
 
+static VOID
+TaskSwitchWnd_UpdateTheme(IN OUT PTASK_SWITCH_WND This)
+{
+    if (This->TaskBandTheme)
+        CloseThemeData(This->TaskBandTheme);
+
+    if (IsThemeActive())
+        This->TaskBandTheme = OpenThemeData(This->hWnd, L"TaskBand");
+    else
+        This->TaskBandTheme = NULL;
+}
+
 static VOID
 TaskSwitchWnd_Create(IN OUT PTASK_SWITCH_WND This)
 {
@@ -1410,12 +1464,17 @@ TaskSwitchWnd_Create(IN OUT PTASK_SWITCH_WND This)
         HMODULE hShell32;
         SIZE BtnSize;
 
+        SetWindowTheme(This->hWndToolbar, L"TaskBand", NULL);
+        TaskSwitchWnd_UpdateTheme(This);
         /* Identify the version we're using */
         SendMessage(This->hWndToolbar,
                     TB_BUTTONSTRUCTSIZE,
                     sizeof(TBBUTTON),
                     0);
 
+        This->TaskIcons = ImageList_Create(16, 16, ILC_COLOR32, 0, 1000);
+        SendMessage(This->hWndToolbar, TB_SETIMAGELIST, 0, (LPARAM)This->TaskIcons);
+
         /* Calculate the default button size. Don't save this in This->ButtonSize.cx so that
            the actual button width gets updated correctly on the first recalculation */
         BtnSize.cx = GetSystemMetrics(SM_CXMINIMIZED);
@@ -1497,6 +1556,7 @@ TaskSwitchWnd_NCDestroy(IN OUT PTASK_SWITCH_WND This)
         }
     }
 
+    CloseThemeData(This->TaskBandTheme);
     TaskSwitchWnd_DeleteAllTasks(This);
 }
 
@@ -1778,16 +1838,10 @@ static LRESULT
 TaskSwichWnd_HandleItemPaint(IN OUT PTASK_SWITCH_WND This,
                              IN OUT NMTBCUSTOMDRAW *nmtbcd)
 {
-    HFONT hCaptionFont, hBoldCaptionFont;
     LRESULT Ret = CDRF_DODEFAULT;
     PTASK_GROUP TaskGroup;
     PTASK_ITEM TaskItem;
 
-#if TASK_USE_DRAWCAPTIONTEMP != 0
-
-    UINT uidctFlags = DC_TEXT | DC_ICON | DC_NOSENDMSG;
-
-#endif
     TaskItem = FindTaskItemByIndex(This,
                                    (INT)nmtbcd->nmcd.dwItemSpec);
     TaskGroup = FindTaskGroupByIndex(This,
@@ -1798,97 +1852,32 @@ TaskSwichWnd_HandleItemPaint(IN OUT PTASK_SWITCH_WND This,
 
         if (TaskItem != NULL && IsWindow(TaskItem->hWnd))
         {
-            hCaptionFont = ITrayWindow_GetCaptionFonts(This->Tray,
-                                                       &hBoldCaptionFont);
-            if (nmtbcd->nmcd.uItemState & CDIS_CHECKED)
-                hCaptionFont = hBoldCaptionFont;
-
-#if TASK_USE_DRAWCAPTIONTEMP != 0
-
-            /* Make sure we don't draw on the button edges */
-            InflateRect(&nmtbcd->nmcd.rc,
-                        -GetSystemMetrics(SM_CXEDGE),
-                        -GetSystemMetrics(SM_CYEDGE));
-
-            if ((nmtbcd->nmcd.uItemState & CDIS_MARKED) && TaskItem->RenderFlashed)
-            {
-                /* This is a slight glitch. We have to move the rectangle so that
-                   the button content appears to be pressed. However, when flashing
-                   is enabled, we can see a light line at the top and left inner
-                   border. We need to fill that area with the flashing color. Note
-                   that since we're using DrawCaptionTemp() the flashing color is
-                   COLOR_ACTIVECAPTION, not COLOR_HIGHLIGHT! */
-                FillRect(nmtbcd->nmcd.hdc,
-                         &nmtbcd->nmcd.rc,
-                         (HBRUSH)(COLOR_ACTIVECAPTION + 1));
-
-                /* Make the button content appear pressed. This however draws a bit
-                   into the right and bottom border of the button edge, making it
-                   look a bit odd. However, selecting a clipping region to prevent
-                   that from happening causes problems with DrawCaptionTemp()! */
-                OffsetRect(&nmtbcd->nmcd.rc,
-                           1,
-                           1);
-
-                /* Render flashed */
-                uidctFlags |= DC_ACTIVE;
-            }
-            else
-            {
-                uidctFlags |= DC_INBUTTON;
-                if (nmtbcd->nmcd.uItemState & CDIS_CHECKED)
-                    uidctFlags |= DC_ACTIVE;
-            }
-
-            if (DrawCapTemp != NULL)
-            {
-                /* Draw the button content */
-                TaskItem->DisplayTooltip = !DrawCapTemp(TaskItem->hWnd,
-                                                        nmtbcd->nmcd.hdc,
-                                                        &nmtbcd->nmcd.rc,
-                                                        hCaptionFont,
-                                                        NULL,
-                                                        NULL,
-                                                        uidctFlags);
-            }
-
-            return CDRF_SKIPDEFAULT;
-
-#else /* !TASK_USE_DRAWCAPTIONTEMP */
-
             /* Make the entire button flashing if neccessary */
             if (nmtbcd->nmcd.uItemState & CDIS_MARKED)
             {
-                if (TaskItem->RenderFlashed)
+                Ret = TBCDRF_NOBACKGROUND;
+                if (!This->TaskBandTheme)
                 {
-                    nmtbcd->hbrMonoDither = GetSysColorBrush(COLOR_HIGHLIGHT);
-                    nmtbcd->clrTextHighlight = GetSysColor(COLOR_HIGHLIGHTTEXT);
-                    nmtbcd->nHLStringBkMode = TRANSPARENT;
-
-                    /* We don't really need to set clrMark because we set the
-                       background mode to TRANSPARENT! */
-                    nmtbcd->clrMark = GetSysColor(COLOR_HIGHLIGHT);
-
-                    Ret |= TBCDRF_USECDCOLORS;
+                    SelectObject(nmtbcd->nmcd.hdc, GetSysColorBrush(COLOR_HIGHLIGHT));
+                    Rectangle(nmtbcd->nmcd.hdc,
+                              nmtbcd->nmcd.rc.left,
+                              nmtbcd->nmcd.rc.top,
+                              nmtbcd->nmcd.rc.right,
+                              nmtbcd->nmcd.rc.bottom);
                 }
                 else
-                    Ret |= TBCDRF_NOMARK;
+                {
+                    DrawThemeBackground(This->TaskBandTheme, nmtbcd->nmcd.hdc, TDP_FLASHBUTTON, 0, &nmtbcd->nmcd.rc, 0);
+                }
+                nmtbcd->clrText = GetSysColor(COLOR_HIGHLIGHTTEXT);
+                return Ret;
             }
-
-            /* Select the font we want to use */
-            SelectObject(nmtbcd->nmcd.hdc,
-                         hCaptionFont);
-            return Ret | CDRF_NEWFONT;
-
-#endif
-
         }
     }
     else if (TaskGroup != NULL)
     {
         /* FIXME: Implement painting for task groups */
     }
-
     return Ret;
 }
 
@@ -1907,22 +1896,7 @@ TaskSwitchWnd_HandleToolbarNotification(IN OUT PTASK_SWITCH_WND This,
             switch (nmtbcd->nmcd.dwDrawStage)
             {
 
-#if TASK_USE_DRAWCAPTIONTEMP != 0
-
                 case CDDS_ITEMPREPAINT:
-                    /* We handle drawing in the post-paint stage so that we
-                       don't have to draw the button edges, etc */
-                    Ret = CDRF_NOTIFYPOSTPAINT;
-                    break;
-
-                case CDDS_ITEMPOSTPAINT:
-
-#else /* !TASK_USE_DRAWCAPTIONTEMP */
-
-                case CDDS_ITEMPREPAINT:
-
-#endif
-
                     Ret = TaskSwichWnd_HandleItemPaint(This,
                                                        nmtbcd);
                     break;
@@ -1942,6 +1916,16 @@ TaskSwitchWnd_HandleToolbarNotification(IN OUT PTASK_SWITCH_WND This,
     return Ret;
 }
 
+static VOID
+TaskSwitchWnd_DrawBackground(HWND hwnd,
+                             HDC hdc)
+{
+    RECT rect;
+
+    GetClientRect(hwnd, &rect);
+    DrawThemeParentBackground(hwnd, hdc, &rect);
+}
+
 static LRESULT CALLBACK
 TaskSwitchWndProc(IN HWND hwnd,
                   IN UINT uMsg,
@@ -1961,6 +1945,12 @@ TaskSwitchWndProc(IN HWND hwnd,
     {
         switch (uMsg)
         {
+            case WM_THEMECHANGED:
+                TaskSwitchWnd_UpdateTheme(This);
+                break;
+            case WM_ERASEBKGND:
+                TaskSwitchWnd_DrawBackground(hwnd, (HDC)wParam);
+                break;
             case WM_SIZE:
             {
                 SIZE szClient;
index 679fa6e..9e0bbb9 100644 (file)
  */
 
 #include <precomp.h>
+#include <docobj.h>
+
+/*
+ * SysPagerWnd
+ */
+static const TCHAR szSysPagerWndClass[] = TEXT("SysPager");
+
+typedef struct _NOTIFY_ITEM
+{
+    struct _NOTIFY_ITEM *next;
+    INT Index;
+    INT IconIndex;
+    NOTIFYICONDATA iconData;
+} NOTIFY_ITEM, *PNOTIFY_ITEM, **PPNOTIFY_ITEM;
+
+typedef struct _SYS_PAGER_DATA
+{
+    HWND hWnd;
+    HWND hWndToolbar;
+    HIMAGELIST SysIcons;
+    PNOTIFY_ITEM NotifyItems;
+    INT ButtonCount;
+    INT VisibleButtonCount;
+} SYS_PAGER_WND_DATA, *PSYS_PAGER_WND_DATA;
+
+
+static PNOTIFY_ITEM
+SysPagerWnd_CreateNotifyItemData(IN OUT PSYS_PAGER_WND_DATA This)
+{
+    PNOTIFY_ITEM *findNotifyPointer = &This->NotifyItems;
+    PNOTIFY_ITEM notifyItem;
+
+    notifyItem = malloc(sizeof(*notifyItem));
+    if (notifyItem == NULL)
+        return NULL;
+
+    ZeroMemory(notifyItem, sizeof(*notifyItem));
+    notifyItem->next = NULL;
+
+    while (*findNotifyPointer != NULL)
+    {
+        findNotifyPointer = &(*findNotifyPointer)->next;
+    }
+
+    *findNotifyPointer = notifyItem;
+
+    return notifyItem;
+}
+
+static PPNOTIFY_ITEM
+SysPagerWnd_FindPPNotifyItemByIconData(IN OUT PSYS_PAGER_WND_DATA This,
+                                       IN CONST NOTIFYICONDATA *iconData)
+{
+    PPNOTIFY_ITEM findNotifyPointer = &This->NotifyItems;
+
+    while (*findNotifyPointer != NULL)
+    {
+        if ((*findNotifyPointer)->iconData.hWnd == iconData->hWnd &&
+            (*findNotifyPointer)->iconData.uID == iconData->uID)
+        {
+            return findNotifyPointer;
+        }
+        findNotifyPointer = &(*findNotifyPointer)->next;
+    }
+
+    return NULL;
+}
+
+static PPNOTIFY_ITEM
+SysPagerWnd_FindPPNotifyItemByIndex(IN OUT PSYS_PAGER_WND_DATA This,
+                                    IN WORD wIndex)
+{
+    PPNOTIFY_ITEM findNotifyPointer = &This->NotifyItems;
+
+    while (*findNotifyPointer != NULL)
+    {
+        if ((*findNotifyPointer)->Index == wIndex)
+        {
+            return findNotifyPointer;
+        }
+        findNotifyPointer = &(*findNotifyPointer)->next;
+    }
+
+    return NULL;
+}
+
+static VOID
+SysPagerWnd_UpdateButton(IN OUT PSYS_PAGER_WND_DATA This,
+                         IN CONST NOTIFYICONDATA *iconData)
+{
+    TBBUTTONINFO tbbi;
+    PNOTIFY_ITEM notifyItem;
+    PPNOTIFY_ITEM NotifyPointer;
+
+    NotifyPointer = SysPagerWnd_FindPPNotifyItemByIconData(This, iconData);
+    notifyItem = *NotifyPointer;
+
+    tbbi.cbSize = sizeof(tbbi);
+    tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND;
+    tbbi.idCommand = notifyItem->Index;
+
+    if (iconData->uFlags & NIF_MESSAGE)
+    {
+        notifyItem->iconData.uCallbackMessage = iconData->uCallbackMessage;
+    }
+
+    if (iconData->uFlags & NIF_ICON)
+    {
+        tbbi.dwMask |= TBIF_IMAGE;
+        notifyItem->IconIndex = tbbi.iImage = ImageList_AddIcon(This->SysIcons, iconData->hIcon);
+    }
+
+    /* TODO: support NIF_TIP */
+
+    if (iconData->uFlags & NIF_STATE)
+    {
+        if (iconData->dwStateMask & NIS_HIDDEN &&
+            (notifyItem->iconData.dwState & NIS_HIDDEN) != (iconData->dwState & NIS_HIDDEN))
+        {
+            tbbi.dwMask |= TBIF_STATE;
+            if (iconData->dwState & NIS_HIDDEN)
+            {
+                tbbi.fsState |= TBSTATE_HIDDEN;
+                This->VisibleButtonCount--;
+            }
+            else
+            {
+                tbbi.fsState &= ~TBSTATE_HIDDEN;
+                This->VisibleButtonCount++;
+            }
+        }
+
+        notifyItem->iconData.dwState &= ~iconData->dwStateMask;
+        notifyItem->iconData.dwState |= (iconData->dwState & iconData->dwStateMask);
+    }
+
+    /* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */
+
+    SendMessage(This->hWndToolbar,
+                TB_SETBUTTONINFO,
+                (WPARAM)notifyItem->Index,
+                (LPARAM)&tbbi);
+}
+
+
+static VOID
+SysPagerWnd_AddButton(IN OUT PSYS_PAGER_WND_DATA This,
+                      IN CONST NOTIFYICONDATA *iconData)
+{
+    TBBUTTON tbBtn;
+    PNOTIFY_ITEM notifyItem;
+    TCHAR text[] = TEXT("");
+
+    notifyItem = SysPagerWnd_CreateNotifyItemData(This);
+
+    notifyItem->next = NULL;
+    notifyItem->Index = This->ButtonCount;
+    This->ButtonCount++;
+    This->VisibleButtonCount++;
+
+    notifyItem->iconData.hWnd = iconData->hWnd;
+    notifyItem->iconData.uID = iconData->uID;
+
+    tbBtn.fsState = TBSTATE_ENABLED;
+    tbBtn.fsStyle = BTNS_NOPREFIX;
+    tbBtn.dwData = notifyItem->Index;
+
+    tbBtn.iString = (INT_PTR)text;
+    tbBtn.idCommand=notifyItem->Index;
+
+    if (iconData->uFlags & NIF_MESSAGE)
+    {
+        notifyItem->iconData.uCallbackMessage = iconData->uCallbackMessage;
+    }
+
+    if (iconData->uFlags & NIF_ICON)
+    {
+        notifyItem->IconIndex = tbBtn.iBitmap = ImageList_AddIcon(This->SysIcons, iconData->hIcon);
+    }
+
+    /* TODO: support NIF_TIP */
+
+    if (iconData->uFlags & NIF_STATE)
+    {
+        notifyItem->iconData.dwState &= ~iconData->dwStateMask;
+        notifyItem->iconData.dwState |= (iconData->dwState & iconData->dwStateMask);
+        if (notifyItem->iconData.dwState & NIS_HIDDEN)
+        {
+            tbBtn.fsState |= TBSTATE_HIDDEN;
+            This->VisibleButtonCount--;
+        }
+
+    }
+
+    /* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */
+
+    SendMessage(This->hWndToolbar,
+                TB_INSERTBUTTON,
+                notifyItem->Index,
+                (LPARAM)&tbBtn);
+
+    SendMessage(This->hWndToolbar,
+                TB_SETBUTTONSIZE,
+                0,
+                MAKELONG(16, 16));
+}
+
+static VOID
+SysPagerWnd_RemoveButton(IN OUT PSYS_PAGER_WND_DATA This,
+                         IN CONST NOTIFYICONDATA *iconData)
+{
+    PPNOTIFY_ITEM NotifyPointer;
+
+    NotifyPointer = SysPagerWnd_FindPPNotifyItemByIconData(This, iconData);
+    if (NotifyPointer)
+    {
+        PNOTIFY_ITEM deleteItem;
+        PNOTIFY_ITEM updateItem;
+        deleteItem=*NotifyPointer;
+
+
+        SendMessage(This->hWndToolbar,
+                    TB_DELETEBUTTON,
+                    deleteItem->Index,
+                    0);
+
+        *NotifyPointer=updateItem=deleteItem->next;
+
+        if (!(deleteItem->iconData.dwState & NIS_HIDDEN))
+            This->VisibleButtonCount--;
+        free(deleteItem);
+        This->ButtonCount--;
+
+        while (updateItem != NULL)
+        {
+            TBBUTTONINFO tbbi;
+            updateItem->Index--;
+            tbbi.cbSize = sizeof(tbbi);
+            tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND;
+            tbbi.idCommand = updateItem->Index;
+
+            SendMessage(This->hWndToolbar,
+                        TB_SETBUTTONINFO,
+                        updateItem->Index,
+                        (LPARAM)&tbbi);
+
+            updateItem = updateItem->next;
+        }
+    }
+}
+
+static VOID
+SysPagerWnd_HandleButtonClick(IN OUT PSYS_PAGER_WND_DATA This,
+                              IN WORD wIndex,
+                              IN UINT uMsg,
+                              IN WPARAM wParam)
+{
+    PPNOTIFY_ITEM NotifyPointer;
+
+    NotifyPointer = SysPagerWnd_FindPPNotifyItemByIndex(This, wIndex);
+    if (NotifyPointer)
+    {
+        PNOTIFY_ITEM notifyItem;
+        notifyItem = *NotifyPointer;
+
+        if (IsWindow(notifyItem->iconData.hWnd))
+        {
+            if (uMsg == WM_MOUSEMOVE ||
+                uMsg == WM_LBUTTONDOWN ||
+                uMsg == WM_MBUTTONDOWN ||
+                uMsg == WM_RBUTTONDOWN)
+            {
+                PostMessage(notifyItem->iconData.hWnd,
+                            notifyItem->iconData.uCallbackMessage,
+                            notifyItem->iconData.uID,
+                            uMsg);
+            }
+            else
+            {
+                DWORD pid;
+                GetWindowThreadProcessId(notifyItem->iconData.hWnd, &pid);
+                if (pid == GetCurrentProcessId())
+                {
+                    PostMessage(notifyItem->iconData.hWnd,
+                                notifyItem->iconData.uCallbackMessage,
+                                notifyItem->iconData.uID,
+                                uMsg);
+                }
+                else
+                {
+                    SendMessage(notifyItem->iconData.hWnd,
+                                notifyItem->iconData.uCallbackMessage,
+                                notifyItem->iconData.uID,
+                                uMsg);
+                }
+            }
+        }
+    }
+}
+
+static VOID
+SysPagerWnd_DrawBackground(IN HWND hwnd,
+                           IN HDC hdc)
+{
+    RECT rect;
+
+    GetClientRect(hwnd, &rect);
+    DrawThemeParentBackground(hwnd, hdc, &rect);
+}
+
+static LRESULT CALLBACK
+SysPagerWnd_ToolbarSubclassedProc(IN HWND hWnd,
+                                  IN UINT msg,
+                                  IN WPARAM wParam,
+                                  IN LPARAM lParam,
+                                  IN UINT_PTR uIdSubclass,
+                                  IN DWORD_PTR dwRefData)
+{
+    if (msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST)
+    {
+        HWND parent = GetParent(hWnd);
+
+        if (!parent)
+            return 0;
+
+        return SendMessage(parent, msg, wParam, lParam);
+    }
+
+    return DefSubclassProc(hWnd, msg, wParam, lParam);
+}
+
+static VOID
+SysPagerWnd_Create(IN OUT PSYS_PAGER_WND_DATA This)
+{
+    This->hWndToolbar = CreateWindowEx(0,
+                                       TOOLBARCLASSNAME,
+                                       NULL,
+                                       WS_CHILD | WS_VISIBLE  | WS_CLIPCHILDREN |
+                                           TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE |
+                                           TBSTYLE_TRANSPARENT |
+                                           CCS_TOP | CCS_NORESIZE | CCS_NODIVIDER,
+                                       0,
+                                       0,
+                                       0,
+                                       0,
+                                       This->hWnd,
+                                       NULL,
+                                       hExplorerInstance,
+                                       NULL);
+    if (This->hWndToolbar != NULL)
+    {
+        SIZE BtnSize;
+        SetWindowTheme(This->hWndToolbar, L"TrayNotify", NULL);
+        /* Identify the version we're using */
+        SendMessage(This->hWndToolbar,
+                    TB_BUTTONSTRUCTSIZE,
+                    sizeof(TBBUTTON),
+                    0);
+
+        This->SysIcons = ImageList_Create(16, 16, ILC_COLOR32, 0, 1000);
+        SendMessage(This->hWndToolbar, TB_SETIMAGELIST, 0, (LPARAM)This->SysIcons);
+
+        BtnSize.cx = BtnSize.cy = 18;
+        //BtnSize.cx = GetSystemMetrics(SM_CXMINIMIZED);
+        //This->ButtonSize.cy = BtnSize.cy = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE));
+        SendMessage(This->hWndToolbar,
+                    TB_SETBUTTONSIZE,
+                    0,
+                    MAKELONG(BtnSize.cx, BtnSize.cy));
+        /*SysPagerWnd_AddButton(This);*/
+
+        SetWindowSubclass(This->hWndToolbar,
+                          SysPagerWnd_ToolbarSubclassedProc,
+                          2,
+                          (DWORD_PTR)This);
+    }
+}
+
+static VOID
+SysPagerWnd_NCDestroy(IN OUT PSYS_PAGER_WND_DATA This)
+{
+    /* Free allocated resources */
+    SetWindowLongPtr(This->hWnd,
+                     0,
+                     0);
+    HeapFree(hProcessHeap,
+             0,
+             This);
+}
+
+static VOID
+SysPagerWnd_NotifyMsg(IN HWND hwnd,
+                      IN WPARAM wParam,
+                      IN LPARAM lParam)
+{
+    PSYS_PAGER_WND_DATA This = (PSYS_PAGER_WND_DATA)GetWindowLongPtr(hwnd, 0);
+
+    PCOPYDATASTRUCT cpData = (PCOPYDATASTRUCT)lParam;
+    if (cpData->dwData == 1)
+    {
+        DWORD trayCommand;
+        NOTIFYICONDATA *iconData;
+        HWND parentHWND;
+        RECT windowRect;
+        parentHWND = GetParent(This->hWnd);
+        parentHWND = GetParent(parentHWND);
+        GetClientRect(parentHWND, &windowRect);
+
+        trayCommand = *(DWORD *) (((BYTE *)cpData->lpData) + 4);
+        iconData = (NOTIFYICONDATA *) (((BYTE *)cpData->lpData) + 8);
+
+        switch (trayCommand)
+        {
+            case NIM_ADD:
+            {
+                PPNOTIFY_ITEM NotifyPointer;
+                NotifyPointer = SysPagerWnd_FindPPNotifyItemByIconData(This,
+                                                                       iconData);
+                if (!NotifyPointer)
+                {
+                    SysPagerWnd_AddButton(This, iconData);
+                }
+                break;
+            }
+            case NIM_MODIFY:
+            {
+                PPNOTIFY_ITEM NotifyPointer;
+                NotifyPointer = SysPagerWnd_FindPPNotifyItemByIconData(This,
+                                                                       iconData);
+                if(!NotifyPointer)
+                {
+                    SysPagerWnd_AddButton(This, iconData);
+                }
+                else
+                {
+                    SysPagerWnd_UpdateButton(This, iconData);
+                }
+                break;
+            }
+            case NIM_DELETE:
+            {
+                SysPagerWnd_RemoveButton(This, iconData);
+                break;
+            }
+        }
+        SendMessage(parentHWND,
+                    WM_SIZE,
+                    0,
+                    MAKELONG(windowRect.right - windowRect.left,
+                             windowRect.bottom - windowRect.top));
+    }
+}
+
+static void
+SysPagerWnd_GetSize(IN HWND hwnd,
+                    IN WPARAM wParam,
+                    IN PSIZE size)
+{
+    PSYS_PAGER_WND_DATA This = (PSYS_PAGER_WND_DATA)GetWindowLongPtr(hwnd, 0);
+    INT rows = 0;
+    TBMETRICS tbm;
+
+    if (wParam) /* horizontal */
+    {
+        rows = size->cy / 24;
+        if (rows == 0)
+            rows++;
+        size->cx = (This->VisibleButtonCount+rows - 1) / rows * 24;
+    }
+    else
+    {
+        rows = size->cx / 24;
+        if (rows == 0)
+            rows++;
+        size->cy = (This->VisibleButtonCount+rows - 1) / rows * 24;
+    }
+
+    tbm.cbSize = sizeof(tbm);
+    tbm.dwMask = TBMF_BARPAD | TBMF_BUTTONSPACING;
+    tbm.cxBarPad = tbm.cyBarPad = 0;
+    tbm.cxButtonSpacing = 0;
+    tbm.cyButtonSpacing = 0;
+
+    SendMessage(This->hWndToolbar,
+                TB_SETMETRICS,
+                0,
+                (LPARAM)&tbm);
+}
+
+static LRESULT CALLBACK
+SysPagerWndProc(IN HWND hwnd,
+                IN UINT uMsg,
+                IN WPARAM wParam,
+                IN LPARAM lParam)
+{
+    PSYS_PAGER_WND_DATA This = NULL;
+    LRESULT Ret = FALSE;
+
+    if (uMsg != WM_NCCREATE)
+    {
+        This = (PSYS_PAGER_WND_DATA)GetWindowLongPtr(hwnd, 0);
+    }
+
+    if (This != NULL || uMsg == WM_NCCREATE)
+    {
+        switch (uMsg)
+        {
+            case WM_ERASEBKGND:
+                SysPagerWnd_DrawBackground(hwnd,(HDC)wParam);
+                return 0;
+
+            case WM_NCCREATE:
+            {
+                LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam;
+                This = CreateStruct->lpCreateParams;
+                This->hWnd = hwnd;
+                This->NotifyItems = NULL;
+                This->ButtonCount = 0;
+                This->VisibleButtonCount = 0;
+
+                SetWindowLongPtr(hwnd,
+                                 0,
+                                 (LONG_PTR)This);
+
+                return TRUE;
+            }
+            case WM_CREATE:
+                SysPagerWnd_Create(This);
+                break;
+            case WM_NCDESTROY:
+                SysPagerWnd_NCDestroy(This);
+                break;
+
+            case WM_SIZE:
+            {
+                SIZE szClient;
+                szClient.cx = LOWORD(lParam);
+                szClient.cy = HIWORD(lParam);
+
+                Ret = DefWindowProc(hwnd,
+                                    uMsg,
+                                    wParam,
+                                    lParam);
+
+
+                if (This->hWndToolbar != NULL && This->hWndToolbar != hwnd)
+                {
+                    SetWindowPos(This->hWndToolbar,
+                                 NULL,
+                                 0,
+                                 0,
+                                 szClient.cx,
+                                 szClient.cy,
+                                 SWP_NOZORDER);
+                }
+            }
+
+            default:
+                if (uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST)
+                {
+                    POINT pt;
+                    INT iBtn;
+
+                    pt.x = LOWORD(lParam);
+                    pt.y = HIWORD(lParam);
+
+                    iBtn = (INT)SendMessage(This->hWndToolbar,
+                                            TB_HITTEST,
+                                            0,
+                                            (LPARAM)&pt);
+
+                    if (iBtn >= 0)
+                    {
+                        SysPagerWnd_HandleButtonClick(This,iBtn,uMsg,wParam);
+                    }
+
+                    return 0;
+                }
+
+                Ret = DefWindowProc(hwnd,
+                                    uMsg,
+                                    wParam,
+                                    lParam);
+                break;
+        }
+    }
+
+    return Ret;
+}
+
+static HWND
+CreateSysPagerWnd(IN HWND hWndParent,
+                  IN BOOL bVisible)
+{
+    PSYS_PAGER_WND_DATA TcData;
+    DWORD dwStyle;
+    HWND hWnd = NULL;
+
+    TcData = HeapAlloc(hProcessHeap,
+                       0,
+                       sizeof(*TcData));
+    if (TcData != NULL)
+    {
+        ZeroMemory(TcData, sizeof(*TcData));
+
+        /* Create the window. The tray window is going to move it to the correct
+           position and resize it as needed. */
+        dwStyle = WS_CHILD | WS_CLIPSIBLINGS;
+        if (bVisible)
+            dwStyle |= WS_VISIBLE;
+
+        hWnd = CreateWindowEx(0,
+                              szSysPagerWndClass,
+                              NULL,
+                              dwStyle,
+                              0,
+                              0,
+                              0,
+                              0,
+                              hWndParent,
+                              NULL,
+                              hExplorerInstance,
+                              TcData);
+
+        if (hWnd == NULL)
+        {
+            HeapFree(hProcessHeap,
+                     0,
+                     TcData);
+        }
+    }
+
+    SetWindowTheme(hWnd, L"TrayNotify", NULL);
+
+    return hWnd;
+
+}
+
+static BOOL
+RegisterSysPagerWndClass(VOID)
+{
+    WNDCLASS wcTrayClock;
+
+    wcTrayClock.style = CS_DBLCLKS;
+    wcTrayClock.lpfnWndProc = SysPagerWndProc;
+    wcTrayClock.cbClsExtra = 0;
+    wcTrayClock.cbWndExtra = sizeof(PSYS_PAGER_WND_DATA);
+    wcTrayClock.hInstance = hExplorerInstance;
+    wcTrayClock.hIcon = NULL;
+    wcTrayClock.hCursor = LoadCursor(NULL, IDC_ARROW);
+    wcTrayClock.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
+    wcTrayClock.lpszMenuName = NULL;
+    wcTrayClock.lpszClassName = szSysPagerWndClass;
+
+    return RegisterClass(&wcTrayClock) != 0;
+}
+
+static VOID
+UnregisterSysPagerWndClass(VOID)
+{
+    UnregisterClass(szSysPagerWndClass,
+                    hExplorerInstance);
+}
 
 /*
  * TrayClockWnd
@@ -92,6 +755,7 @@ typedef struct _TRAY_CLOCK_WND_DATA
     HWND hWnd;
     HWND hWndNotify;
     HFONT hFont;
+    COLORREF textColor;
     RECT rcText;
     SYSTEMTIME LocalTime;
 
@@ -113,6 +777,49 @@ typedef struct _TRAY_CLOCK_WND_DATA
     TCHAR szLines[CLOCKWND_FORMAT_COUNT][48];
 } TRAY_CLOCK_WND_DATA, *PTRAY_CLOCK_WND_DATA;
 
+static VOID
+TrayClockWnd_SetFont(IN OUT PTRAY_CLOCK_WND_DATA This,
+                     IN HFONT hNewFont,
+                     IN BOOL bRedraw);
+
+static VOID
+TrayClockWnd_UpdateTheme(IN OUT PTRAY_CLOCK_WND_DATA This)
+{
+    LOGFONTW clockFont;
+    HTHEME clockTheme;
+    HFONT hFont;
+
+    clockTheme = OpenThemeData(This->hWnd, L"Clock");
+
+    if (clockTheme)
+    {
+        GetThemeFont(clockTheme,
+                     NULL,
+                     CLP_TIME,
+                     0,
+                     TMT_FONT,
+                     &clockFont);
+
+        hFont = CreateFontIndirect(&clockFont);
+
+        TrayClockWnd_SetFont(This,
+                             hFont,
+                             FALSE);
+
+        GetThemeColor(clockTheme,
+                      CLP_TIME,
+                      0,
+                      TMT_TEXTCOLOR,
+                      &This->textColor);
+    }
+    else
+    {
+        This->textColor = RGB(0,0,0);
+    }
+
+    CloseThemeData(clockTheme);
+}
+
 static BOOL
 TrayClockWnd_MeasureLines(IN OUT PTRAY_CLOCK_WND_DATA This)
 {
@@ -483,6 +1190,8 @@ TrayClockWnd_Paint(IN OUT PTRAY_CLOCK_WND_DATA This,
         iPrevBkMode = SetBkMode(hDC,
                                 TRANSPARENT);
 
+        SetTextColor(hDC, This->textColor);
+
         hPrevFont = SelectObject(hDC,
                                  This->hFont);
 
@@ -532,6 +1241,16 @@ TrayClockWnd_SetFont(IN OUT PTRAY_CLOCK_WND_DATA This,
     }
 }
 
+static VOID
+TrayClockWnd_DrawBackground(IN HWND hwnd,
+                            IN HDC hdc)
+{
+    RECT rect;
+
+    GetClientRect(hwnd, &rect);
+    DrawThemeParentBackground(hwnd, hdc, &rect);
+}
+
 static LRESULT CALLBACK
 TrayClockWndProc(IN HWND hwnd,
                  IN UINT uMsg,
@@ -551,6 +1270,12 @@ TrayClockWndProc(IN HWND hwnd,
     {
         switch (uMsg)
         {
+            case WM_THEMECHANGED:
+                TrayClockWnd_UpdateTheme(This);
+                break;
+            case WM_ERASEBKGND:
+                TrayClockWnd_DrawBackground(hwnd, (HDC)wParam);
+                break;
             case WM_PAINT:
             case WM_PRINTCLIENT:
             {
@@ -621,6 +1346,7 @@ TrayClockWndProc(IN HWND hwnd,
                 SetWindowLongPtr(hwnd,
                                  0,
                                  (LONG_PTR)This);
+                TrayClockWnd_UpdateTheme(This);
 
                 return TRUE;
             }
@@ -714,6 +1440,7 @@ CreateTrayClockWnd(IN HWND hWndParent,
                      TcData);
         }
     }
+    SetWindowTheme(hWnd, L"TrayNotify", NULL);
 
     return hWnd;
 
@@ -760,9 +1487,13 @@ typedef struct _TRAY_NOTIFY_WND_DATA
     HWND hWnd;
     HWND hWndTrayClock;
     HWND hWndNotify;
+    HWND hWndSysPager;
+    HTHEME TrayTheme;
     SIZE szTrayClockMin;
-    SIZE szNonClient;
+    SIZE szTrayNotify;
+    MARGINS ContentMargin;
     ITrayWindow *TrayWindow;
+    HFONT hFontClock;
     union
     {
         DWORD dwFlags;
@@ -775,22 +1506,43 @@ typedef struct _TRAY_NOTIFY_WND_DATA
 } TRAY_NOTIFY_WND_DATA, *PTRAY_NOTIFY_WND_DATA;
 
 static VOID
-TrayNotifyWnd_UpdateStyle(IN OUT PTRAY_NOTIFY_WND_DATA This)
+TrayNotifyWnd_UpdateTheme(IN OUT PTRAY_NOTIFY_WND_DATA This)
 {
-    RECT rcClient = { 0, 0, 0, 0 };
-
-    if (AdjustWindowRectEx(&rcClient,
-                           GetWindowLongPtr(This->hWnd,
-                                            GWL_STYLE),
-                           FALSE,
-                           GetWindowLongPtr(This->hWnd,
-                                            GWL_EXSTYLE)))
+    LONG_PTR style;
+
+    if (This->TrayTheme)
+        CloseThemeData(This->TrayTheme);
+
+    if (IsThemeActive())
+        This->TrayTheme = OpenThemeData(This->hWnd, L"TrayNotify");
+    else
+        This->TrayTheme = 0;
+
+    if (This->TrayTheme)
     {
-        This->szNonClient.cx = rcClient.right - rcClient.left;
-        This->szNonClient.cy = rcClient.bottom - rcClient.top;
+        style = GetWindowLongPtr(This->hWnd, GWL_EXSTYLE);
+        style = style & ~WS_EX_STATICEDGE;
+        SetWindowLongPtr(This->hWnd, GWL_EXSTYLE, style);
+
+        GetThemeMargins(This->TrayTheme,
+                        NULL,
+                        TNP_BACKGROUND,
+                        0,
+                        TMT_CONTENTMARGINS,
+                        NULL,
+                        &This->ContentMargin);
     }
     else
-        This->szNonClient.cx = This->szNonClient.cy = 0;
+    {
+        style = GetWindowLongPtr(This->hWnd, GWL_EXSTYLE);
+        style = style | WS_EX_STATICEDGE;
+        SetWindowLongPtr(This->hWnd, GWL_EXSTYLE, style);
+
+        This->ContentMargin.cxLeftWidth = 0;
+        This->ContentMargin.cxRightWidth = 0;
+        This->ContentMargin.cyTopHeight = 0;
+        This->ContentMargin.cyBottomHeight = 0;
+    }
 }
 
 static VOID
@@ -799,7 +1551,10 @@ TrayNotifyWnd_Create(IN OUT PTRAY_NOTIFY_WND_DATA This)
     This->hWndTrayClock = CreateTrayClockWnd(This->hWnd,
                                              !This->HideClock);
 
-    TrayNotifyWnd_UpdateStyle(This);
+    This->hWndSysPager = CreateSysPagerWnd(This->hWnd,
+                                           !This->HideClock);
+
+    TrayNotifyWnd_UpdateTheme(This);
 }
 
 static VOID
@@ -818,21 +1573,26 @@ TrayNotifyWnd_GetMinimumSize(IN OUT PTRAY_NOTIFY_WND_DATA This,
                              IN BOOL Horizontal,
                              IN OUT PSIZE pSize)
 {
+    SIZE szClock = { 0, 0 };
+    SIZE szTray = { 0, 0 };
+
     This->IsHorizontal = Horizontal;
+    if (This->IsHorizontal)
+        SetWindowTheme(This->hWnd, L"TrayNotifyHoriz", NULL);
+    else
+        SetWindowTheme(This->hWnd, L"TrayNotifyVert", NULL);
 
     if (!This->HideClock)
     {
-        SIZE szClock = { 0, 0 };
-
         if (Horizontal)
         {
-            szClock.cy = pSize->cy - This->szNonClient.cy - (2 * TRAY_NOTIFY_WND_SPACING_Y);
+            szClock.cy = pSize->cy - 2 * TRAY_NOTIFY_WND_SPACING_Y;
             if (szClock.cy <= 0)
                 goto NoClock;
         }
         else
         {
-            szClock.cx = pSize->cx - This->szNonClient.cx - (2 * TRAY_NOTIFY_WND_SPACING_X);
+            szClock.cx = pSize->cx - 2 * TRAY_NOTIFY_WND_SPACING_X;
             if (szClock.cx <= 0)
                 goto NoClock;
         }
@@ -846,23 +1606,45 @@ TrayNotifyWnd_GetMinimumSize(IN OUT PTRAY_NOTIFY_WND_DATA This,
     }
     else
 NoClock:
-        This->szTrayClockMin = This->szNonClient;
+        This->szTrayClockMin = szClock;
 
     if (Horizontal)
     {
-        pSize->cx = This->szNonClient.cx + (2 * TRAY_NOTIFY_WND_SPACING_X);
+        szTray.cy = pSize->cy - 2 * TRAY_NOTIFY_WND_SPACING_Y;
+    }
+    else
+    {
+        szTray.cx = pSize->cx - 2 * TRAY_NOTIFY_WND_SPACING_X;
+    }
+
+    SysPagerWnd_GetSize(This->hWndSysPager,
+                        Horizontal,
+                        &szTray);
+
+    This->szTrayNotify = szTray;
+
+    if (Horizontal)
+    {
+        pSize->cx = 2 * TRAY_NOTIFY_WND_SPACING_X;
 
         if (!This->HideClock)
             pSize->cx += TRAY_NOTIFY_WND_SPACING_X + This->szTrayClockMin.cx;
+
+        pSize->cx += szTray.cx;
     }
     else
     {
-        pSize->cy = This->szNonClient.cy + (2 * TRAY_NOTIFY_WND_SPACING_Y);
+        pSize->cy = 2 * TRAY_NOTIFY_WND_SPACING_Y;
 
         if (!This->HideClock)
             pSize->cy += TRAY_NOTIFY_WND_SPACING_Y + This->szTrayClockMin.cy;
+
+        pSize->cy += szTray.cy;
     }
 
+    pSize->cy += This->ContentMargin.cyTopHeight + This->ContentMargin.cyBottomHeight;
+    pSize->cx += This->ContentMargin.cxLeftWidth + This->ContentMargin.cxRightWidth;
+
     return TRUE;
 }
 
@@ -897,6 +1679,55 @@ TrayNotifyWnd_Size(IN OUT PTRAY_NOTIFY_WND_DATA This,
                      szClock.cx,
                      szClock.cy,
                      SWP_NOZORDER);
+
+        if (This->IsHorizontal)
+        {
+            ptClock.x -= This->szTrayNotify.cx;
+        }
+        else
+        {
+            ptClock.y -= This->szTrayNotify.cy;
+        }
+
+        SetWindowPos(This->hWndSysPager,
+                     NULL,
+                     ptClock.x,
+                     ptClock.y,
+                     This->szTrayNotify.cx,
+                     This->szTrayNotify.cy,
+                     SWP_NOZORDER);
+    }
+}
+
+static LRESULT
+TrayNotifyWnd_DrawBackground(IN HWND hwnd,
+                             IN UINT uMsg,
+                             IN WPARAM wParam,
+                             IN LPARAM lParam)
+{
+    PTRAY_NOTIFY_WND_DATA This = (PTRAY_NOTIFY_WND_DATA)GetWindowLongPtr(hwnd, 0);
+    RECT rect;
+    HDC hdc = (HDC)wParam;
+
+    GetClientRect(hwnd, &rect);
+
+    DrawThemeParentBackground(hwnd, hdc, &rect);
+    DrawThemeBackground(This->TrayTheme, hdc, TNP_BACKGROUND, 0, &rect, 0);
+
+    return 0;
+}
+
+VOID
+TrayNotify_NotifyMsg(IN HWND hwnd,
+                     IN WPARAM wParam,
+                     IN LPARAM lParam)
+{
+    PTRAY_NOTIFY_WND_DATA This = (PTRAY_NOTIFY_WND_DATA)GetWindowLongPtr(hwnd, 0);
+    if (This->hWndSysPager)
+    {
+        SysPagerWnd_NotifyMsg(This->hWndSysPager,
+                              wParam,
+                              lParam);
     }
 }
 
@@ -919,6 +1750,14 @@ TrayNotifyWndProc(IN HWND hwnd,
     {
         switch (uMsg)
         {
+            case WM_THEMECHANGED:
+                TrayNotifyWnd_UpdateTheme(This);
+                return 0;
+            case WM_ERASEBKGND:
+                return TrayNotifyWnd_DrawBackground(hwnd,
+                                                    uMsg,
+                                                    wParam,
+                                                    lParam);
             case TNWM_GETMINIMUMSIZE:
             {
                 Ret = (LRESULT)TrayNotifyWnd_GetMinimumSize(This,
@@ -1112,6 +1951,7 @@ RegisterTrayNotifyWndClass(VOID)
             UnregisterClass(szTrayNotifyWndClass,
                             hExplorerInstance);
         }
+        RegisterSysPagerWndClass();
     }
 
     return Ret;
@@ -1122,6 +1962,8 @@ UnregisterTrayNotifyWndClass(VOID)
 {
     UnregisterTrayClockWndClass();
 
+    UnregisterSysPagerWndClass();
+
     UnregisterClass(szTrayNotifyWndClass,
                     hExplorerInstance);
 }
index 0cdec7e..23889ab 100644 (file)
@@ -43,6 +43,7 @@ typedef struct
     const IShellDesktopTrayVtbl *lpVtblShellDesktopTray;
     LONG Ref;
 
+    HTHEME TaskbarTheme;
     HWND hWnd;
     HWND hWndDesktop;
 
@@ -1027,6 +1028,12 @@ ITrayWindowImpl_Destroy(ITrayWindowImpl *This)
         This->TrayBandSite = NULL;
     }
 
+    if (This->TaskbarTheme)
+    {
+        CloseThemeData(This->TaskbarTheme);
+        This->TaskbarTheme = NULL;
+    }
+
     ITrayWindowImpl_Release(ITrayWindow_from_impl(This));
 
     if (InterlockedDecrement(&TrayWndCount) == 0)
@@ -1113,6 +1120,7 @@ ITrayWindowImpl_AlignControls(IN OUT ITrayWindowImpl *This,
     BOOL Horizontal;
     HDWP dwp;
 
+    ITrayWindowImpl_UpdateStartButton(This, NULL);
     if (prcClient != NULL)
     {
         rcClient = *prcClient;
@@ -1401,11 +1409,26 @@ Cleanup:
     return hBitmap;
 }
 
+static VOID
+ITrayWindowImpl_UpdateTheme(IN OUT ITrayWindowImpl *This)
+{
+    if (This->TaskbarTheme)
+        CloseThemeData(This->TaskbarTheme);
+
+    if (IsThemeActive())
+        This->TaskbarTheme = OpenThemeData(This->hWnd, L"Taskbar");
+    else
+        This->TaskbarTheme = 0;
+}
+
 static VOID
 ITrayWindowImpl_Create(IN OUT ITrayWindowImpl *This)
 {
     TCHAR szStartCaption[32];
 
+    SetWindowTheme(This->hWnd, L"TaskBar", NULL);
+    ITrayWindowImpl_UpdateTheme(This);
+
     InterlockedIncrement(&TrayWndCount);
 
     if (!LoadString(hExplorerInstance,
@@ -1458,6 +1481,7 @@ ITrayWindowImpl_Create(IN OUT ITrayWindowImpl *This)
                                      NULL);
     if (This->hwndStart)
     {
+        SetWindowTheme(This->hwndStart, L"Start", NULL);
         SendMessage(This->hwndStart,
                     WM_SETFONT,
                     (WPARAM)This->hStartBtnFont,
@@ -1538,6 +1562,7 @@ SetStartBtnImage:
     This->TrayBandSite = CreateTrayBandSite(ITrayWindow_from_impl(This),
                                             &This->hwndRebar,
                                             &This->hwndTaskSwitch);
+    SetWindowTheme(This->hwndRebar, L"TaskBar", NULL);
 
     /* Create the tray notification window */
     This->hwndTrayNotify = CreateTrayNotifyWnd(ITrayWindow_from_impl(This),
@@ -1883,6 +1908,74 @@ static const ITrayWindowVtbl ITrayWindowImpl_Vtbl =
     ITrayWindowImpl_Lock
 };
 
+static int
+ITrayWindowImpl_DrawBackground(IN ITrayWindowImpl *This,
+                               IN HDC dc)
+{
+    int backoundPart;
+    RECT rect;
+
+    GetClientRect(This->hWnd, &rect);
+    switch (This->Position)
+    {
+        case ABE_LEFT:
+            backoundPart = TBP_BACKGROUNDLEFT;
+            break;
+        case ABE_TOP:
+            backoundPart = TBP_BACKGROUNDTOP;
+            break;
+        case ABE_RIGHT:
+            backoundPart = TBP_BACKGROUNDRIGHT;
+            break;
+        case ABE_BOTTOM:
+        default:
+            backoundPart = TBP_BACKGROUNDBOTTOM;
+            break;
+    }
+    DrawThemeBackground(This->TaskbarTheme, dc, backoundPart, 0, &rect, 0);
+    return 0;
+}
+
+static int
+ITrayWindowImpl_DrawSizer(IN ITrayWindowImpl *This,
+                          IN HRGN hRgn)
+{
+    HDC hdc;
+    RECT rect;
+    int backoundPart;
+
+    GetWindowRect(This->hWnd, &rect);
+    OffsetRect(&rect, -rect.left, -rect.top);
+
+    hdc = GetDCEx(This->hWnd, hRgn, DCX_WINDOW | DCX_INTERSECTRGN | DCX_PARENTCLIP);
+
+    switch (This->Position)
+    {
+        case ABE_LEFT:
+            backoundPart = TBP_SIZINGBARLEFT;
+            rect.left = rect.right - GetSystemMetrics(SM_CXSIZEFRAME);
+            break;
+        case ABE_TOP:
+            backoundPart = TBP_SIZINGBARTOP;
+            rect.top = rect.bottom - GetSystemMetrics(SM_CYSIZEFRAME);
+            break;
+        case ABE_RIGHT:
+            backoundPart = TBP_SIZINGBARRIGHT;
+            rect.right = rect.left + GetSystemMetrics(SM_CXSIZEFRAME);
+            break;
+        case ABE_BOTTOM:
+        default:
+            backoundPart = TBP_SIZINGBARBOTTOM;
+            rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZEFRAME);
+            break;
+    }
+
+    DrawThemeBackground(This->TaskbarTheme, hdc, backoundPart, 0, &rect, 0);
+
+    ReleaseDC(This->hWnd, hdc);
+    return 0;
+}
+
 static DWORD WINAPI
 RunFileDlgThread(IN OUT PVOID pParam)
 { 
@@ -1957,6 +2050,32 @@ TrayWndProc(IN HWND hwnd,
 
         switch (uMsg)
         {
+            case WM_COPYDATA:
+            {
+                if (This->hwndTrayNotify)
+                {
+                    TrayNotify_NotifyMsg(This->hwndTrayNotify,
+                                         wParam,
+                                         lParam);
+                }
+                return TRUE;
+            }
+            case WM_THEMECHANGED:
+                ITrayWindowImpl_UpdateTheme(This);
+                return 0;
+            case WM_NCPAINT:
+                if (!This->TaskbarTheme)
+                    goto DefHandler;
+                return ITrayWindowImpl_DrawSizer(This,
+                                                 (HRGN)wParam);
+            case WM_ERASEBKGND:
+                if (!This->TaskbarTheme)
+                    goto DefHandler;
+                return ITrayWindowImpl_DrawBackground(This,
+                                                      (HDC)wParam);
+            case WM_CTLCOLORBTN:
+                SetBkMode((HDC)wParam, TRANSPARENT);
+                return (LRESULT)GetStockObject(HOLLOW_BRUSH);
             case WM_NCHITTEST:
             {
                 RECT rcClient;
@@ -1996,30 +2115,23 @@ TrayWndProc(IN HWND hwnd,
                             if (pt.y > rcClient.bottom)
                                 return HTBOTTOM;
                             break;
-
-                        case ABE_BOTTOM:
-                            if (pt.y < rcClient.top)
-                                return HTTOP;
-                            break;
-
                         case ABE_LEFT:
                             if (pt.x > rcClient.right)
                                 return HTRIGHT;
                             break;
-
                         case ABE_RIGHT:
                             if (pt.x < rcClient.left)
                                 return HTLEFT;
                             break;
-
+                        case ABE_BOTTOM:
                         default:
+                            if (pt.y < rcClient.top)
+                                return HTTOP;
                             break;
                     }
                 }
-
                 return HTBORDER;
             }
-
             case WM_MOVING:
             {
                 POINT ptCursor;
@@ -2072,7 +2184,7 @@ TrayWndProc(IN HWND hwnd,
             case WM_SIZE:
             {
                 RECT rcClient;
-
+                InvalidateRect(This->hWnd, NULL, TRUE);
                 if (wParam == SIZE_RESTORED && lParam == 0)
                 {
                     ITrayWindowImpl_ResizeWorkArea(This);