Windows-Server-2003/shell/explorer/trayclok.cpp

871 lines
23 KiB
C++

#include "cabinet.h"
#include "trayclok.h"
#include "tray.h"
#include "util.h"
#include "strsafe.h"
class CClockCtl : public CImpWndProc
{
public:
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
CClockCtl() : _cRef(1) {}
protected:
// Create & Destroy
LRESULT _HandleCreate();
LRESULT _HandleDestroy();
// Paint helpers
LRESULT _DoPaint(BOOL fPaint);
void _EnsureFontsInitialized(BOOL fForce);
void _GetTextExtent(HDC hdc, TCHAR* pszText, int cchText, LPRECT prcText);
void _DrawText(HDC hdc, TCHAR* pszText, int cchText, LPRECT prcText);
// Time/Date calc helpers
void _Reset();
void _UpdateLastHour();
DWORD _RecalcCurTime();
void _EnableTimer(DWORD dtNextTick);
// Message handlers
void _HandleThemeChanged(WPARAM wParam);
LRESULT _HandleIniChange(WPARAM wParam, LPTSTR pszSection);
LRESULT _HandleTimeChange();
// Text extent helpers
void _GetMaxTimeSize(HDC hdc, LPSIZE pszTime);
void _GetMaxDateSize(HDC hdc, LPSIZE pszTime);
void _GetMaxDaySize(HDC hdc, LPSIZE pszTime);
LRESULT _CalcMinSize(int cxMax, int cyMax);
// Tooltip text handler
LRESULT _OnNeedText(LPTOOLTIPTEXT lpttt);
// Window procedure
LRESULT v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
private:
ULONG _cRef;
int _cchCurDate;
TCHAR _szDateFmt[40]; // The format string to pass to GetFormatTime
TCHAR _szCurDate[40]; // The current Date string.
int _cchCurTime;
TCHAR _szTimeFmt[40]; // The format string to pass to GetFormatTime
TCHAR _szCurTime[40]; // The current Time string.
int _cchCurDay;
TCHAR _szCurDay[40]; // The current Day string.
WORD _wLastHour; // wHour from local time of last clock tick
WORD _wLastMinute; // wMinute from local time of last clock tick
HTHEME _hTheme;
HFONT _hfontCapNormal;
BOOL _fClockRunning;
BOOL _fClockClipped;
BOOL _fHasFocus;
friend BOOL ClockCtl_Class(HINSTANCE hinst);
};
ULONG CClockCtl::AddRef()
{
return ++_cRef;
}
ULONG CClockCtl::Release()
{
if (--_cRef == 0)
{
delete this;
return 0;
}
return _cRef;
}
void CClockCtl::_UpdateLastHour()
{
SYSTEMTIME st;
// Grab the time
GetLocalTime(&st);
_wLastHour = st.wHour;
_wLastMinute = st.wMinute;
}
void CClockCtl::_EnableTimer(DWORD dtNextTick)
{
if (dtNextTick)
{
SetTimer(_hwnd, 0, dtNextTick, NULL);
_fClockRunning = TRUE;
}
else if (_fClockRunning)
{
_fClockRunning = FALSE;
KillTimer(_hwnd, 0);
}
}
LRESULT CClockCtl::_HandleCreate()
{
AddRef();
_EnsureFontsInitialized(FALSE);
_hTheme = OpenThemeData(_hwnd, L"Clock");
_UpdateLastHour();
return 1;
}
LRESULT CClockCtl::_HandleDestroy()
{
Release(); // safe because cwndproc is holding a ref across call to v_wndproc
if (_hTheme)
{
CloseThemeData(_hTheme);
_hTheme = NULL;
}
if (_hfontCapNormal)
{
DeleteFont(_hfontCapNormal);
_hfontCapNormal = NULL;
}
_EnableTimer(0);
return 1;
}
DWORD CClockCtl::_RecalcCurTime()
{
SYSTEMTIME st;
//
// Current time.
//
GetLocalTime(&st);
//
// Don't recalc the text if the time hasn't changed yet.
//
if ((st.wMinute != _wLastMinute) || (st.wHour != _wLastHour) || !*_szCurTime)
{
_wLastMinute = st.wMinute;
_wLastHour = st.wHour;
//
// Text for the current time.
//
_cchCurTime = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS,
&st, _szTimeFmt, _szCurTime, ARRAYSIZE(_szCurTime));
BOOL fRTL = IS_WINDOW_RTL_MIRRORED(_hwnd);
_cchCurDate = GetDateFormat(LOCALE_USER_DEFAULT, fRTL ? DATE_RTLREADING : 0,
&st, _szDateFmt, _szCurDate, ARRAYSIZE(_szCurDate));
_cchCurDay = GetDateFormat(LOCALE_USER_DEFAULT, fRTL ? DATE_RTLREADING : 0,
&st, TEXT("dddd"), _szCurDay, ARRAYSIZE(_szCurDay));
// Don't count the NULL terminator.
if (_cchCurTime > 0)
_cchCurTime--;
if (_cchCurDate > 0)
_cchCurDate--;
if (_cchCurDay > 0)
_cchCurDay--;
//
// Update our window text so accessibility apps can see. Since we
// don't have a caption USER won't try to paint us or anything, it
// will just set the text and fire an event if any accessibility
// clients are listening...
//
SetWindowText(_hwnd, _szCurTime);
}
//
// Return number of milliseconds till we need to be called again.
//
return 1000UL * (60 - st.wSecond);
}
void CClockCtl::_EnsureFontsInitialized(BOOL fForce)
{
if (fForce || !_hfontCapNormal)
{
HFONT hfont;
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(ncm);
if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
{
// Create the normal font
ncm.lfCaptionFont.lfWeight = FW_NORMAL;
hfont = CreateFontIndirect(&ncm.lfCaptionFont);
if (hfont)
{
if (_hfontCapNormal)
DeleteFont(_hfontCapNormal);
_hfontCapNormal = hfont;
}
}
}
}
void CClockCtl::_GetTextExtent(HDC hdc, TCHAR* pszText, int cchText, LPRECT prcText)
{
if (_hTheme)
{
GetThemeTextExtent(_hTheme, hdc, CLP_TIME, 0, pszText, cchText, 0, prcText, prcText);
}
else
{
SIZE size;
GetTextExtentPoint(hdc, pszText, cchText, &size);
SetRect(prcText, 0, 0, size.cx, size.cy);
}
}
void CClockCtl::_DrawText(HDC hdc, TCHAR* pszText, int cchText, LPRECT prcText)
{
if (_hTheme)
{
DrawThemeText(_hTheme, hdc, CLP_TIME, 0, pszText, cchText, 0, 0, prcText);
}
else
{
ExtTextOut(hdc, prcText->left, prcText->top, ETO_OPAQUE, NULL, pszText, cchText, NULL);
}
}
LRESULT CClockCtl::_DoPaint(BOOL fPaint)
{
PAINTSTRUCT ps;
RECT rcClient, rcClip = {0};
DWORD dtNextTick = 0;
BOOL fDoTimer;
HDC hdc;
HBITMAP hMemBm, hOldBm;
//
// If we are asked to paint and the clock is not running then start it.
// Otherwise wait until we get a clock tick to recompute the time etc.
//
fDoTimer = !fPaint || !_fClockRunning;
//
// Get a DC to paint with.
//
if (fPaint)
{
BeginPaint(_hwnd, &ps);
}
else
{
ps.hdc = GetDC(_hwnd);
GetClipBox(ps.hdc, &ps.rcPaint);
}
// Create memory surface and map rendering context if double buffering
// Only make large enough for clipping region
hdc = CreateCompatibleDC(ps.hdc);
if (hdc)
{
hMemBm = CreateCompatibleBitmap(ps.hdc, RECTWIDTH(ps.rcPaint), RECTHEIGHT(ps.rcPaint));
if (hMemBm)
{
hOldBm = (HBITMAP) SelectObject(hdc, hMemBm);
// Offset painting to paint in region
OffsetWindowOrgEx(hdc, ps.rcPaint.left, ps.rcPaint.top, NULL);
}
else
{
DeleteDC(hdc);
hdc = NULL;
}
}
if (hdc)
{
SHSendPrintRect(GetParent(_hwnd), _hwnd, hdc, &ps.rcPaint);
_EnsureFontsInitialized(FALSE);
//
// Update the time if we need to.
//
if (fDoTimer || !*_szCurTime)
{
dtNextTick = _RecalcCurTime();
ASSERT(dtNextTick);
}
//
// Paint the clock face if we are not clipped or if we got a real
// paint message for the window. We want to avoid turning off the
// timer on paint messages (regardless of clip region) because this
// implies the window is visible in some way. If we guessed wrong, we
// will turn off the timer next timer tick anyway so no big deal.
//
if (GetClipBox(hdc, &rcClip) != NULLREGION || fPaint)
{
//
// Draw the text centered in the window.
//
GetClientRect(_hwnd, &rcClient);
HFONT hfontOld;
if (_hfontCapNormal)
hfontOld = SelectFont(hdc, _hfontCapNormal);
SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
BOOL fShowDate = FALSE;
BOOL fShowDay = FALSE;
RECT rcTime = {0};
RECT rcDate = {0};
RECT rcDay = {0};
_GetTextExtent(hdc, _szCurTime, _cchCurTime, &rcTime);
_GetTextExtent(hdc, _szCurDate, _cchCurDate, &rcDate);
_GetTextExtent(hdc, _szCurDay, _cchCurDay, &rcDay);
int cySpace = RECTHEIGHT(rcTime) / 2;
int cy = RECTHEIGHT(rcTime) + cySpace;
if ((cy + RECTHEIGHT(rcDay) < rcClient.bottom) && (RECTWIDTH(rcDay) < rcClient.right))
{
fShowDay = TRUE;
cy += RECTHEIGHT(rcDay) + cySpace;
if ((cy + RECTHEIGHT(rcDate) < rcClient.bottom) && (RECTWIDTH(rcDate) < rcClient.right))
{
fShowDate = TRUE;
cy += RECTHEIGHT(rcDate) + cySpace;
}
}
cy -= cySpace;
int yOffset = max((rcClient.bottom - cy) / 2, 0);
RECT rcDraw = rcTime;
OffsetRect(&rcDraw, max((rcClient.right - RECTWIDTH(rcTime)) / 2, 0), yOffset);
_DrawText(hdc, _szCurTime, _cchCurTime, &rcDraw);
yOffset += RECTHEIGHT(rcTime) + cySpace;
if (fShowDay)
{
rcDraw = rcDay;
OffsetRect(&rcDraw, max((rcClient.right - RECTWIDTH(rcDay)) / 2, 0), yOffset);
_DrawText(hdc, _szCurDay, _cchCurDay, &rcDraw);
yOffset += RECTHEIGHT(rcDay) + cySpace;
if (fShowDate)
{
rcDraw = rcDate;
OffsetRect(&rcDraw, max((rcClient.right - RECTWIDTH(rcDate)) / 2, 0), yOffset);
_DrawText(hdc, _szCurDate, _cchCurDate, &rcDraw);
}
}
// figure out if the time is clipped
_fClockClipped = (RECTWIDTH(rcTime) > rcClient.right || RECTHEIGHT(rcTime) > rcClient.bottom);
if (_hfontCapNormal)
SelectObject(hdc, hfontOld);
if (_fHasFocus)
{
LRESULT lRes = SendMessage(_hwnd, WM_QUERYUISTATE, 0, 0);
if (!(LOWORD(lRes) & UISF_HIDEFOCUS))
{
RECT rcFocus = rcClient;
InflateRect(&rcFocus, -2, 0);
DrawFocusRect(hdc, &rcFocus);
}
}
}
else
{
//
// We are obscured so make sure we turn off the clock.
//
dtNextTick = 0;
fDoTimer = TRUE;
}
BitBlt(ps.hdc, ps.rcPaint.left, ps.rcPaint.top, RECTWIDTH(ps.rcPaint), RECTHEIGHT(ps.rcPaint), hdc, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
SelectObject(hdc, hOldBm);
DeleteObject(hMemBm);
DeleteDC(hdc);
//
// Release our paint DC.
//
if (fPaint)
EndPaint(_hwnd, &ps);
else
ReleaseDC(_hwnd, ps.hdc);
}
//
// Reset/Kill the timer.
//
if (fDoTimer)
{
_EnableTimer(dtNextTick);
//
// If we just killed the timer because we were clipped when it arrived,
// make sure that we are really clipped by invalidating ourselves once.
//
if (hdc)
{
if (!dtNextTick && !fPaint)
InvalidateRect(_hwnd, NULL, FALSE);
else
{
InvalidateRect(_hwnd, NULL, TRUE);
}
}
}
return 0;
}
void CClockCtl::_Reset()
{
//
// Reset the clock by killing the timer and invalidating.
// Everything will be updated when we try to paint.
//
_EnableTimer(0);
InvalidateRect(_hwnd, NULL, FALSE);
}
LRESULT CClockCtl::_HandleTimeChange()
{
*_szCurTime = 0; // Force a text recalc.
_UpdateLastHour();
_Reset();
return 1;
}
static const TCHAR c_szSlop[] = TEXT("00");
void CClockCtl::_GetMaxTimeSize(HDC hdc, LPSIZE pszTime)
{
SYSTEMTIME st={0}; // Initialize to 0...
RECT rcAM = {0};
RECT rcPM = {0};
TCHAR szTime[40];
// We need to get the AM and the PM sizes...
// We append Two 0s at end to add slop into size
// first AM
st.wHour=11;
int cch = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st,
_szTimeFmt, szTime, ARRAYSIZE(szTime) - ARRAYSIZE(c_szSlop));
if (cch)
cch--; // don't count the NULL
StringCchCat(szTime, ARRAYSIZE(szTime), c_szSlop);
_GetTextExtent(hdc, szTime, cch+2, &rcAM);
// then PM
st.wHour=23;
cch = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st,
_szTimeFmt, szTime, ARRAYSIZE(szTime) - ARRAYSIZE(c_szSlop));
if (cch)
cch--; // don't count the NULL
StringCchCat(szTime, ARRAYSIZE(szTime), c_szSlop);
_GetTextExtent(hdc, szTime, cch+2, &rcPM);
pszTime->cx = max(rcAM.right, rcPM.right);
pszTime->cy = max(rcAM.bottom, rcPM.bottom);
}
void CClockCtl::_GetMaxDateSize(HDC hdc, LPSIZE pszTime)
{
SYSTEMTIME st={0}; // Initialize to 0...
TCHAR szDate[43];
st.wYear = 2001;
st.wMonth = 5;
st.wDay = 5;
BOOL fRTL = IS_WINDOW_RTL_MIRRORED(_hwnd);
int cch = GetDateFormat(LOCALE_USER_DEFAULT, fRTL ? DATE_RTLREADING : 0,
&st, _szDateFmt, szDate, ARRAYSIZE(szDate) - ARRAYSIZE(c_szSlop));
if (cch > 0)
cch--; // don't count the NULL
StringCchCat(szDate, ARRAYSIZE(szDate), c_szSlop);
RECT rc = {0};
_GetTextExtent(hdc, szDate, cch+2, &rc);
pszTime->cx = rc.right;
pszTime->cy = rc.bottom;
}
void CClockCtl::_GetMaxDaySize(HDC hdc, LPSIZE pszTime)
{
SYSTEMTIME st={0}; // Initialize to 0...
TCHAR szDay[40];
pszTime->cx = 0;
pszTime->cy = 0;
// Use a fake date, otherwise GetDateFormat complains about invalid args
// BTW, the date is the day I fixed this bug for those of you reading this comment
// in the year 2025.
st.wYear = 2001;
st.wMonth = 3;
for (WORD wDay = 1; wDay <= 7; wDay++)
{
st.wDay = wDay;
int cch = GetDateFormat(LOCALE_USER_DEFAULT, 0,
&st, TEXT("dddd"), szDay, ARRAYSIZE(szDay) - ARRAYSIZE(c_szSlop));
if (cch)
cch--; // don't count the NULL
StringCchCat(szDay, ARRAYSIZE(szDay), c_szSlop);
RECT rc = {0};
_GetTextExtent(hdc, szDay, cch+2, &rc);
pszTime->cx = max(pszTime->cx, rc.right);
pszTime->cy = max(pszTime->cy, rc.bottom);
}
}
LRESULT CClockCtl::_CalcMinSize(int cxMax, int cyMax)
{
RECT rc;
HDC hdc;
HFONT hfontOld;
if (!(GetWindowLong(_hwnd, GWL_STYLE) & WS_VISIBLE))
return 0L;
if (_szTimeFmt[0] == TEXT('\0'))
{
if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, _szTimeFmt,
ARRAYSIZE(_szTimeFmt)) == 0)
{
TraceMsg(TF_ERROR, "c.ccms: GetLocalInfo Failed %d.", GetLastError());
}
*_szCurTime = 0; // Force the text to be recomputed.
}
if (_szDateFmt[0] == TEXT('\0'))
{
if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE, _szDateFmt,
ARRAYSIZE(_szDateFmt)) == 0)
{
TraceMsg(TF_ERROR, "c.ccms: GetLocalInfo Failed %d.", GetLastError());
}
*_szCurDate = 0; // Force the text to be recomputed.
}
hdc = GetDC(_hwnd);
if (!hdc)
return(0L);
_EnsureFontsInitialized(FALSE);
if (_hfontCapNormal)
hfontOld = SelectFont(hdc, _hfontCapNormal);
SIZE size = {0};
SIZE sizeTemp = {0};
_GetMaxTimeSize(hdc, &sizeTemp);
int cySpace = sizeTemp.cy / 2;
size.cy += sizeTemp.cy;
size.cx = max(sizeTemp.cx, size.cx);
_GetMaxDaySize(hdc, &sizeTemp);
if ((size.cy + sizeTemp.cy + cySpace < cyMax) && (sizeTemp.cx < cxMax))
{
size.cy += sizeTemp.cy + cySpace;
size.cx = max(sizeTemp.cx, size.cx);
_GetMaxDateSize(hdc, &sizeTemp);
if ((size.cy + sizeTemp.cy + cySpace < cyMax) && (sizeTemp.cx < cxMax))
{
size.cy += sizeTemp.cy + cySpace;
size.cx = max(sizeTemp.cx, size.cx);
}
}
if (_hfontCapNormal)
SelectObject(hdc, hfontOld);
ReleaseDC(_hwnd, hdc);
// Now lets set up our rectangle...
// The width is 6 digits (a digit slop on both ends + size of
// : or sep and max AM or PM string...)
SetRect(&rc, 0, 0, size.cx,
size.cy + 4 * g_cyBorder);
AdjustWindowRectEx(&rc, GetWindowLong(_hwnd, GWL_STYLE), FALSE,
GetWindowLong(_hwnd, GWL_EXSTYLE));
// make sure we're at least the size of other buttons:
if (rc.bottom - rc.top < g_cySize + g_cyEdge)
rc.bottom = rc.top + g_cySize + g_cyEdge;
return MAKELRESULT((rc.right - rc.left),
(rc.bottom - rc.top));
}
LRESULT CClockCtl::_HandleIniChange(WPARAM wParam, LPTSTR pszSection)
{
if ((pszSection == NULL) || (lstrcmpi(pszSection, TEXT("WindowMetrics")) == 0) ||
wParam == SPI_SETNONCLIENTMETRICS)
{
_EnsureFontsInitialized(TRUE);
}
// Only process certain sections...
if ((pszSection == NULL) || (lstrcmpi(pszSection, TEXT("intl")) == 0) ||
(wParam == SPI_SETICONTITLELOGFONT))
{
TOOLINFO ti;
_szTimeFmt[0] = TEXT('\0'); // Go reread the format.
_szDateFmt[0] = TEXT('\0'); // Go reread the format.
// And make sure we have it recalc...
RECT rc;
GetClientRect(_hwnd, &rc);
//
// When the time/locale is changed, we get a WM_WININICHANGE.
// But the WM_WININICHANGE comes *AFTER* the "sizing" messages. By the time
// we are here, we have calculated the min. size of the clock window based
// on the *PREVIOUS* time. The tray sets the clock window size based on
// this "previous" size, but NOW we get the WININICHANGE, and can calculate
// the new size of the clock. So we have to tell the tray to change our
// size now, and then redraw ourselves.
c_tray.SizeWindows();
ti.cbSize = sizeof(ti);
ti.uFlags = 0;
ti.hwnd = v_hwndTray;
ti.uId = (UINT_PTR)_hwnd;
ti.lpszText = LPSTR_TEXTCALLBACK;
SendMessage(c_tray.GetTrayTips(), TTM_UPDATETIPTEXT, 0, (LPARAM)&ti);
_Reset();
}
return 0;
}
LRESULT CClockCtl::_OnNeedText(LPTOOLTIPTEXT lpttt)
{
int iDateFormat = DATE_LONGDATE;
//
// This code is really squirly. We don't know if the time has been
// clipped until we actually try to paint it, since the clip logic
// is in the WM_PAINT handler... Go figure...
//
if (!*_szCurTime)
{
InvalidateRect(_hwnd, NULL, FALSE);
UpdateWindow(_hwnd);
}
//
// If the current user locale is any BiDi locale, then
// Make the date reading order it RTL. SetBiDiDateFlags only adds
// DATE_RTLREADING if the locale is BiDi. [samera]
//
SetBiDiDateFlags(&iDateFormat);
if (_fClockClipped)
{
// we need to put the time in here too
TCHAR sz[80];
GetDateFormat(LOCALE_USER_DEFAULT, iDateFormat, NULL, NULL, sz, ARRAYSIZE(sz));
StringCchPrintf(lpttt->szText, ARRAYSIZE(lpttt->szText), TEXT("%s %s"), _szCurTime, sz);
}
else
{
GetDateFormat(LOCALE_USER_DEFAULT, iDateFormat, NULL, NULL, lpttt->szText, ARRAYSIZE(lpttt->szText));
}
return TRUE;
}
void CClockCtl::_HandleThemeChanged(WPARAM wParam)
{
if (_hTheme)
{
CloseThemeData(_hTheme);
_hTheme = NULL;
}
if (wParam)
{
_hTheme = OpenThemeData(_hwnd, L"Clock");
}
InvalidateRect(_hwnd, NULL, TRUE);
}
LRESULT CClockCtl::v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CALCMINSIZE:
return _CalcMinSize((int)wParam, (int)lParam);
case WM_NCCREATE:
return _HandleCreate();
case WM_NCDESTROY:
return _HandleDestroy();
case WM_ERASEBKGND:
return 1;
case WM_TIMER:
case WM_PAINT:
return _DoPaint((uMsg == WM_PAINT));
case WM_WININICHANGE:
return _HandleIniChange(wParam, (LPTSTR)lParam);
case WM_POWER:
//
// a critical resume does not generate a WM_POWERBROADCAST
// to windows for some reason, but it does generate a old
// WM_POWER message.
//
if (wParam != PWR_CRITICALRESUME)
break;
//
// Fall through...
//
case WM_TIMECHANGE:
return _HandleTimeChange();
case WM_NCHITTEST:
return(HTTRANSPARENT);
case WM_SHOWWINDOW:
if (wParam)
break;
// fall through
case TCM_RESET:
_Reset();
break;
case WM_NOTIFY:
{
NMHDR *pnm = (NMHDR*)lParam;
switch (pnm->code)
{
case TTN_NEEDTEXT:
return _OnNeedText((LPTOOLTIPTEXT)lParam);
break;
}
break;
}
case WM_THEMECHANGED:
_HandleThemeChanged(wParam);
break;
case WM_SETFOCUS:
case WM_KILLFOCUS:
_fHasFocus = (uMsg == WM_SETFOCUS);
InvalidateRect(_hwnd, NULL, TRUE);
break;
case WM_KEYDOWN:
case WM_KEYUP:
case WM_CHAR:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_SYSCHAR:
//
// forward all keyboard input to parent
//
if (SendMessage(GetParent(_hwnd), uMsg, wParam, lParam) == 0)
{
// The message has been handled...
break;
}
//
// else Fall through...
//
case WM_GETTEXT:
//
// Update the text if we are not running and somebody wants it.
//
if (uMsg == WM_GETTEXT)
{
if (!_fClockRunning)
_RecalcCurTime();
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
// Register the clock class.
BOOL ClockCtl_Class(HINSTANCE hinst)
{
WNDCLASS wc = {0};
wc.lpszClassName = WC_TRAYCLOCK;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = CClockCtl::s_WndProc;
wc.hInstance = hinst;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
wc.cbWndExtra = sizeof(CClockCtl*);
return RegisterClass(&wc);
}
HWND ClockCtl_Create(HWND hwndParent, UINT uID, HINSTANCE hInst)
{
HWND hwnd = NULL;
CClockCtl* pcc = new CClockCtl();
if (pcc)
{
hwnd = CreateWindowEx(0, WC_TRAYCLOCK,
NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, 0, 0, 0, 0,
hwndParent, IntToPtr_(HMENU, uID), hInst, pcc);
pcc->Release();
}
return hwnd;
}