* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <precomp.h>
+#include "precomp.h"
+//#include <docobj.h>
/*
- * TrayClockWnd
- */
+ * SysPagerWnd
+ */
+static const TCHAR szSysPagerWndClass[] = TEXT("SysPager");
-static const TCHAR szTrayClockWndClass[] = TEXT("TrayClockWClass");
-static LPCTSTR s_szRegistryKey = _T("Software\\ReactOS\\Features\\Explorer");
-BOOL blShowSeconds;
+typedef struct _NOTIFY_ITEM
+{
+ struct _NOTIFY_ITEM *next;
+ INT Index;
+ INT IconIndex;
+ NOTIFYICONDATA iconData;
+} NOTIFY_ITEM, *PNOTIFY_ITEM, **PPNOTIFY_ITEM;
-#define ID_TRAYCLOCK_TIMER 0
-#define ID_TRAYCLOCK_TIMER_INIT 1
+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;
+
+// Data comes from shell32/systray.cpp -> TrayNotifyCDS_Dummy
+typedef struct _SYS_PAGER_COPY_DATA
+{
+ DWORD cookie;
+ DWORD notify_code;
+ NOTIFYICONDATA nicon_data;
+} SYS_PAGER_COPY_DATA, *PSYS_PAGER_COPY_DATA;
-static const struct
+static PNOTIFY_ITEM
+SysPagerWnd_CreateNotifyItemData(IN OUT PSYS_PAGER_WND_DATA This)
{
- BOOL IsTime;
- DWORD dwFormatFlags;
- LPCTSTR lpFormat;
-}ClockWndFormats[]= {
-{TRUE, 0, NULL},
-{FALSE, 0, TEXT("dddd")},
-{FALSE, DATE_SHORTDATE, NULL}
-};
+ PNOTIFY_ITEM *findNotifyPointer = &This->NotifyItems;
+ PNOTIFY_ITEM notifyItem;
+
+ notifyItem = HeapAlloc(hProcessHeap,
+ HEAP_ZERO_MEMORY,
+ sizeof(*notifyItem));
+ if (notifyItem == NULL)
+ return NULL;
+
+ 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 = {0};
+ 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);
+ }
+
+ if (iconData->uFlags & NIF_TIP)
+ {
+ StringCchCopy(notifyItem->iconData.szTip, _countof(notifyItem->iconData.szTip), iconData->szTip);
+ }
+
+ 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--;
+ HeapFree(hProcessHeap,
+ 0,
+ 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);
+ }
+ }
+ }
+ }
+}
-HRESULT RegGetDWord(HKEY hKey, LPCTSTR szValueName, DWORD * lpdwResult)
+static VOID
+SysPagerWnd_DrawBackground(IN HWND hwnd,
+ IN HDC hdc)
{
- LONG lResult;
- DWORD dwDataSize = sizeof(DWORD);
- DWORD dwType = 0;
+ RECT rect;
- // Check input parameters...
- if (hKey == NULL || lpdwResult == NULL) return E_INVALIDARG;
+ GetClientRect(hwnd, &rect);
+ DrawThemeParentBackground(hwnd, hdc, &rect);
+}
- // Get dword value from the registry...
- lResult = RegQueryValueEx(hKey, szValueName, 0, &dwType, (LPBYTE) lpdwResult, &dwDataSize );
+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);
- // Check result and make sure the registry value is a DWORD(REG_DWORD)...
- if (lResult != ERROR_SUCCESS) return HRESULT_FROM_WIN32(lResult);
- else if (dwType != REG_DWORD) return DISP_E_TYPEMISMATCH;
+ if (parent)
+ {
+ SendMessage(parent, msg, wParam, lParam);
+ }
+ }
- return NOERROR;
+ return DefSubclassProc(hWnd, msg, wParam, lParam);
}
-void LoadSettings(void)
+static VOID
+SysPagerWnd_Create(IN OUT PSYS_PAGER_WND_DATA This)
{
- HKEY hKey = NULL;
- DWORD dwValue;
-
- if (RegOpenKey(HKEY_CURRENT_USER, s_szRegistryKey, &hKey) == ERROR_SUCCESS)
- {
- RegGetDWord(hKey, TEXT("blShowSeconds"), &dwValue);
- if (dwValue == 1)
- {
- blShowSeconds = TRUE;
- }
- else
- {
- blShowSeconds = FALSE;
- }
-
- RegCloseKey(hKey);
- }
+ DWORD styles =
+ WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN |
+ TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE | TBSTYLE_TRANSPARENT |
+ CCS_TOP | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NODIVIDER;
+ DWORD exStyles = WS_EX_TOOLWINDOW;
+
+ This->hWndToolbar = CreateWindowEx(exStyles,
+ TOOLBARCLASSNAME,
+ NULL,
+ styles,
+ 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 | ILC_MASK, 0, 1000);
+ SendMessage(This->hWndToolbar, TB_SETIMAGELIST, 0, (LPARAM)This->SysIcons);
+
+ BtnSize.cx = BtnSize.cy = 18;
+ SendMessage(This->hWndToolbar,
+ TB_SETBUTTONSIZE,
+ 0,
+ MAKELONG(BtnSize.cx, BtnSize.cy));
+
+ 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)
+ {
+ SYS_PAGER_COPY_DATA * data;
+ NOTIFYICONDATA *iconData;
+ HWND parentHWND;
+ RECT windowRect;
+ parentHWND = GetParent(This->hWnd);
+ parentHWND = GetParent(parentHWND);
+ GetClientRect(parentHWND, &windowRect);
+
+ data = (PSYS_PAGER_COPY_DATA) cpData->lpData;
+ iconData = &data->nicon_data;
+
+ switch (data->notify_code)
+ {
+ 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;
+ }
+ default:
+ TRACE("NotifyMessage received with unknown code %d.\n", data->notify_code);
+ 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:
+ if (!IsAppThemed())
+ break;
+
+ SysPagerWnd_DrawBackground(hwnd, (HDC) wParam);
+ return TRUE;
+
+ 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_NOTIFY:
+ {
+ const NMHDR * nmh = (const NMHDR *) lParam;
+ if (nmh->code == TBN_GETINFOTIPW)
+ {
+ NMTBGETINFOTIP * nmtip = (NMTBGETINFOTIP *) lParam;
+ PPNOTIFY_ITEM ptr = SysPagerWnd_FindPPNotifyItemByIndex(This, nmtip->iItem);
+ if (ptr)
+ {
+ PNOTIFY_ITEM item = *ptr;
+ StringCchCopy(nmtip->pszText, nmtip->cchTextMax, item->iconData.szTip);
+ }
+ }
+ else if (nmh->code == NM_CUSTOMDRAW)
+ {
+ NMCUSTOMDRAW * cdraw = (NMCUSTOMDRAW *) lParam;
+ switch (cdraw->dwDrawStage)
+ {
+ case CDDS_PREPAINT:
+ return CDRF_NOTIFYITEMDRAW;
+
+ case CDDS_ITEMPREPAINT:
+ return TBCDRF_NOBACKGROUND | TBCDRF_NOEDGES | TBCDRF_NOOFFSET | TBCDRF_NOMARK | TBCDRF_NOETCHEDEFFECT;
+ }
+ }
+
+ 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);
+ }
+
+ return Ret;
+ }
+
+ 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;
+ }
+
+ break;
+ }
+ }
+
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+}
+
+static HWND
+CreateSysPagerWnd(IN HWND hWndParent,
+ IN BOOL bVisible)
+{
+ PSYS_PAGER_WND_DATA SpData;
+ DWORD dwStyle;
+ HWND hWnd = NULL;
+
+ SpData = HeapAlloc(hProcessHeap,
+ HEAP_ZERO_MEMORY,
+ sizeof(*SpData));
+ if (SpData != NULL)
+ {
+ /* 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,
+ SpData);
+
+ if (hWnd != NULL)
+ {
+ SetWindowTheme(hWnd, L"TrayNotify", NULL);
+ }
+ else
+ {
+ HeapFree(hProcessHeap,
+ 0,
+ SpData);
+ }
+ }
+
+ 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
+ */
+
+static const TCHAR szTrayClockWndClass[] = TEXT("TrayClockWClass");
+
+#define ID_TRAYCLOCK_TIMER 0
+#define ID_TRAYCLOCK_TIMER_INIT 1
+
+static const struct
+{
+ BOOL IsTime;
+ DWORD dwFormatFlags;
+ LPCTSTR lpFormat;
+} ClockWndFormats[] = {
+ { TRUE, 0, NULL },
+ { FALSE, 0, TEXT("dddd") },
+ { FALSE, DATE_SHORTDATE, NULL }
+};
+
#define CLOCKWND_FORMAT_COUNT (sizeof(ClockWndFormats) / sizeof(ClockWndFormats[0]))
#define TRAY_CLOCK_WND_SPACING_X 0
HWND hWnd;
HWND hWndNotify;
HFONT hFont;
+ COLORREF textColor;
RECT rcText;
SYSTEMTIME LocalTime;
-
+
union
{
DWORD dwFlags;
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 = CreateFontIndirectW(&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)
{
if (ClockWndFormats[i].IsTime)
{
iRet = GetTimeFormat(LOCALE_USER_DEFAULT,
- ClockWndFormats[i].dwFormatFlags,
+ AdvancedSettings.bShowSeconds ? ClockWndFormats[i].dwFormatFlags : TIME_NOSECONDS,
&This->LocalTime,
ClockWndFormats[i].lpFormat,
This->szLines[i],
if (iRet != 0 && i == 0)
{
- if (blShowSeconds == FALSE)
- {
- (This->szLines[0][5] = '\0');
- };
-
/* Set the window text to the time only */
SetWindowText(This->hWnd,
This->szLines[i]);
nmh.hwndFrom = This->hWnd;
nmh.idFrom = GetWindowLongPtr(This->hWnd,
- GWL_ID);
+ GWLP_ID);
nmh.code = NTNWM_REALIGN;
SendMessage(This->hWndNotify,
/* Calculate the due time */
GetLocalTime(&This->LocalTime);
uiDueTime = 1000 - (UINT)This->LocalTime.wMilliseconds;
- if (blShowSeconds == TRUE)
- uiDueTime += ( (UINT)This->LocalTime.wSecond) * 100;
- else
- uiDueTime += (59 - (UINT)This->LocalTime.wSecond) * 1000;
+ if (AdvancedSettings.bShowSeconds)
+ uiDueTime += (UINT)This->LocalTime.wSecond * 100;
+ else
+ uiDueTime += (59 - (UINT)This->LocalTime.wSecond) * 1000;
if (uiDueTime < USER_TIMER_MINIMUM || uiDueTime > USER_TIMER_MAXIMUM)
uiDueTime = 1000;
{
UINT uiDueTime;
BOOL Ret;
- int intWait1, intWait2;
+ UINT uiWait1, uiWait2;
/* Kill the initialization timer */
KillTimer(This->hWnd,
This->IsInitTimerEnabled = FALSE;
uiDueTime = TrayClockWnd_CalculateDueTime(This);
-
- if (blShowSeconds == TRUE)
- {
- intWait1 = 1000-200;
- intWait2 = 1000;
- }
- else
- {
- intWait1 = 60*1000-200;
- intWait2 = 60*1000;
- }
-
- if (uiDueTime > intWait1)
+
+ if (AdvancedSettings.bShowSeconds)
+ {
+ uiWait1 = 1000 - 200;
+ uiWait2 = 1000;
+ }
+ else
+ {
+ uiWait1 = 60 * 1000 - 200;
+ uiWait2 = 60 * 1000;
+ }
+
+ if (uiDueTime > uiWait1)
{
/* The update of the clock will be up to 200 ms late, but that's
acceptable. We're going to setup a timer that fires depending
- intWait2. */
+ uiWait2. */
Ret = SetTimer(This->hWnd,
ID_TRAYCLOCK_TIMER,
- intWait2,
+ uiWait2,
NULL) != 0;
This->IsTimerEnabled = Ret;
iPrevBkMode = SetBkMode(hDC,
TRANSPARENT);
+ SetTextColor(hDC, This->textColor);
+
hPrevFont = SelectObject(hDC,
This->hFont);
}
}
+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,
IN LPARAM lParam)
{
PTRAY_CLOCK_WND_DATA This = NULL;
- LRESULT Ret = FALSE;
if (uMsg != WM_NCCREATE)
{
{
switch (uMsg)
{
+ case WM_THEMECHANGED:
+ TrayClockWnd_UpdateTheme(This);
+ break;
+ case WM_ERASEBKGND:
+ if (!IsAppThemed())
+ break;
+
+ TrayClockWnd_DrawBackground(hwnd, (HDC) wParam);
+ return TRUE;
case WM_PAINT:
case WM_PRINTCLIENT:
{
if (wParam == 0)
{
- hDC = BeginPaint(This->hWnd,
- &ps);
+ hDC = BeginPaint(This->hWnd, &ps);
}
if (hDC != NULL)
{
- TrayClockWnd_Paint(This,
- hDC);
+ TrayClockWnd_Paint(This, hDC);
if (wParam == 0)
{
- EndPaint(This->hWnd,
- &ps);
+ EndPaint(This->hWnd, &ps);
}
}
break;
case WM_NCHITTEST:
/* We want the user to be able to drag the task bar when clicking the clock */
- Ret = HTTRANSPARENT;
- break;
+ return HTTRANSPARENT;
case TCWM_GETMINIMUMSIZE:
{
This->IsHorizontal = (BOOL)wParam;
- Ret = (LRESULT)TrayClockWnd_GetMinimumSize(This,
- (BOOL)wParam,
- (PSIZE)lParam) != 0;
- break;
+ return (LRESULT) TrayClockWnd_GetMinimumSize(This, (BOOL) wParam, (PSIZE) lParam) != 0;
}
case TCWM_UPDATETIME:
{
- Ret = (LRESULT)TrayClockWnd_ResetTime(This);
- break;
+ return (LRESULT)TrayClockWnd_ResetTime(This);
}
case WM_NCCREATE:
This->hWnd = hwnd;
This->hWndNotify = CreateStruct->hwndParent;
- SetWindowLongPtr(hwnd,
- 0,
- (LONG_PTR)This);
+ SetWindowLongPtr(hwnd, 0, (LONG_PTR) This);
+ TrayClockWnd_UpdateTheme(This);
return TRUE;
}
TRUE);
break;
}
-
- default:
- Ret = DefWindowProc(hwnd,
- uMsg,
- wParam,
- lParam);
- break;
}
}
- return Ret;
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
static HWND
PTRAY_CLOCK_WND_DATA TcData;
DWORD dwStyle;
HWND hWnd = NULL;
- LoadSettings();
TcData = HeapAlloc(hProcessHeap,
- 0,
+ HEAP_ZERO_MEMORY,
sizeof(*TcData));
if (TcData != NULL)
{
- ZeroMemory(TcData,
- sizeof(*TcData));
-
TcData->IsHorizontal = TRUE;
/* Create the window. The tray window is going to move it to the correct
position and resize it as needed. */
hWndParent,
NULL,
hExplorerInstance,
- (LPVOID)TcData);
+ TcData);
- if (hWnd == NULL)
+ if (hWnd != NULL)
+ {
+ SetWindowTheme(hWnd, L"TrayNotify", NULL);
+ }
+ else
{
HeapFree(hProcessHeap,
0,
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;
} 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 = GetWindowLong(This->hWnd, GWL_EXSTYLE);
+ style = style & ~WS_EX_STATICEDGE;
+ SetWindowLong(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 = GetWindowLong(This->hWnd, GWL_EXSTYLE);
+ style = style | WS_EX_STATICEDGE;
+ SetWindowLong(This->hWnd, GWL_EXSTYLE, style);
+
+ This->ContentMargin.cxLeftWidth = 0;
+ This->ContentMargin.cxRightWidth = 0;
+ This->ContentMargin.cyTopHeight = 0;
+ This->ContentMargin.cyBottomHeight = 0;
+ }
}
static VOID
This->hWndTrayClock = CreateTrayClockWnd(This->hWnd,
!This->HideClock);
- TrayNotifyWnd_UpdateStyle(This);
+ This->hWndSysPager = CreateSysPagerWnd(This->hWnd,
+ !This->HideClock);
+
+ TrayNotifyWnd_UpdateTheme(This);
}
static VOID
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;
}
}
else
NoClock:
- This->szTrayClockMin = This->szNonClient;
+ This->szTrayClockMin = szClock;
+
+ if (Horizontal)
+ {
+ 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 = This->szNonClient.cx + (2 * TRAY_NOTIFY_WND_SPACING_X);
+ 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;
}
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);
}
}
+BOOL
+TrayNotify_GetClockRect(IN HWND hwnd,
+ OUT PRECT rcClock)
+{
+ PTRAY_NOTIFY_WND_DATA This = (PTRAY_NOTIFY_WND_DATA)GetWindowLongPtr(hwnd, 0);
+ if (!IsWindowVisible(This->hWndTrayClock))
+ return FALSE;
+
+ return GetWindowRect(This->hWndTrayClock, rcClock);
+}
+
static LRESULT CALLBACK
TrayNotifyWndProc(IN HWND hwnd,
IN UINT uMsg,
IN LPARAM lParam)
{
PTRAY_NOTIFY_WND_DATA This = NULL;
- LRESULT Ret = FALSE;
if (uMsg != WM_NCCREATE)
{
{
switch (uMsg)
{
+ case WM_THEMECHANGED:
+ TrayNotifyWnd_UpdateTheme(This);
+ return 0;
+ case WM_ERASEBKGND:
+ if (!This->TrayTheme)
+ break;
+ return TrayNotifyWnd_DrawBackground(hwnd, uMsg, wParam, lParam);
case TNWM_GETMINIMUMSIZE:
{
- Ret = (LRESULT)TrayNotifyWnd_GetMinimumSize(This,
- (BOOL)wParam,
- (PSIZE)lParam);
- break;
+ return (LRESULT) TrayNotifyWnd_GetMinimumSize(This, (BOOL) wParam, (PSIZE) lParam);
}
case TNWM_UPDATETIME:
if (This->hWndTrayClock != NULL)
{
/* Forward the message to the tray clock window procedure */
- Ret = TrayClockWndProc(This->hWndTrayClock,
- TCWM_UPDATETIME,
- wParam,
- lParam);
+ return TrayClockWndProc(This->hWndTrayClock, TCWM_UPDATETIME, wParam, lParam);
}
- break;
+ return 0;
}
case WM_SIZE:
TrayNotifyWnd_Size(This,
&szClient);
- break;
+ return 0;
}
case WM_NCHITTEST:
/* We want the user to be able to drag the task bar when clicking the
tray notification window */
- Ret = HTTRANSPARENT;
- break;
-
+ return HTTRANSPARENT;
case TNWM_SHOWCLOCK:
{
BOOL PrevHidden = This->HideClock;
This->HideClock ? SW_HIDE : SW_SHOW);
}
- Ret = (LRESULT)(!PrevHidden);
- break;
+ return (LRESULT) (!PrevHidden);
}
case WM_NOTIFY:
if (nmh->hwndFrom == This->hWndTrayClock)
{
/* Pass down notifications */
- Ret = SendMessage(This->hWndNotify,
- WM_NOTIFY,
- wParam,
- lParam);
+ return SendMessage(This->hWndNotify, WM_NOTIFY, wParam, lParam);
}
- break;
+ return 0;
}
case WM_SETFONT:
wParam,
lParam);
}
- goto HandleDefaultMessage;
+ break;
}
case WM_NCCREATE:
This->hWnd = hwnd;
This->hWndNotify = CreateStruct->hwndParent;
- SetWindowLongPtr(hwnd,
- 0,
- (LONG_PTR)This);
+ SetWindowLongPtr(hwnd, 0, (LONG_PTR) This);
return TRUE;
}
case WM_CREATE:
TrayNotifyWnd_Create(This);
- break;
+ return 0;
case WM_NCDESTROY:
TrayNotifyWnd_NCDestroy(This);
- break;
-
- default:
-HandleDefaultMessage:
- Ret = DefWindowProc(hwnd,
- uMsg,
- wParam,
- lParam);
- break;
+ return 0;
}
}
- return Ret;
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
HWND
return NULL;
TnData = HeapAlloc(hProcessHeap,
- 0,
+ HEAP_ZERO_MEMORY,
sizeof(*TnData));
if (TnData != NULL)
{
- ZeroMemory(TnData,
- sizeof(*TnData));
-
TnData->TrayWindow = TrayWindow;
TnData->HideClock = bHideClock;
hWndTrayWindow,
NULL,
hExplorerInstance,
- (LPVOID)TnData);
+ TnData);
if (hWnd == NULL)
{
UnregisterClass(szTrayNotifyWndClass,
hExplorerInstance);
}
+ RegisterSysPagerWndClass();
}
return Ret;
{
UnregisterTrayClockWndClass();
+ UnregisterSysPagerWndClass();
+
UnregisterClass(szTrayNotifyWndClass,
hExplorerInstance);
}