Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygentrayntfy.c
Go to the documentation of this file.
00001 /* 00002 * ReactOS Explorer 00003 * 00004 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org> 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00021 #include <precomp.h> 00022 00023 /* 00024 * TrayClockWnd 00025 */ 00026 00027 static const TCHAR szTrayClockWndClass[] = TEXT("TrayClockWClass"); 00028 static LPCTSTR s_szRegistryKey = _T("Software\\ReactOS\\Features\\Explorer"); 00029 BOOL blShowSeconds; 00030 00031 #define ID_TRAYCLOCK_TIMER 0 00032 #define ID_TRAYCLOCK_TIMER_INIT 1 00033 00034 static const struct 00035 { 00036 BOOL IsTime; 00037 DWORD dwFormatFlags; 00038 LPCTSTR lpFormat; 00039 }ClockWndFormats[]= { 00040 {TRUE, 0, NULL}, 00041 {FALSE, 0, TEXT("dddd")}, 00042 {FALSE, DATE_SHORTDATE, NULL} 00043 }; 00044 00045 HRESULT RegGetDWord(HKEY hKey, LPCTSTR szValueName, DWORD * lpdwResult) 00046 { 00047 LONG lResult; 00048 DWORD dwDataSize = sizeof(DWORD); 00049 DWORD dwType = 0; 00050 00051 // Check input parameters... 00052 if (hKey == NULL || lpdwResult == NULL) return E_INVALIDARG; 00053 00054 // Get dword value from the registry... 00055 lResult = RegQueryValueEx(hKey, szValueName, 0, &dwType, (LPBYTE) lpdwResult, &dwDataSize ); 00056 00057 // Check result and make sure the registry value is a DWORD(REG_DWORD)... 00058 if (lResult != ERROR_SUCCESS) return HRESULT_FROM_WIN32(lResult); 00059 else if (dwType != REG_DWORD) return DISP_E_TYPEMISMATCH; 00060 00061 return NOERROR; 00062 } 00063 00064 void LoadSettings(void) 00065 { 00066 HKEY hKey = NULL; 00067 DWORD dwValue; 00068 00069 if (RegOpenKey(HKEY_CURRENT_USER, s_szRegistryKey, &hKey) == ERROR_SUCCESS) 00070 { 00071 RegGetDWord(hKey, TEXT("blShowSeconds"), &dwValue); 00072 if (dwValue == 1) 00073 { 00074 blShowSeconds = TRUE; 00075 } 00076 else 00077 { 00078 blShowSeconds = FALSE; 00079 } 00080 00081 RegCloseKey(hKey); 00082 } 00083 } 00084 00085 #define CLOCKWND_FORMAT_COUNT (sizeof(ClockWndFormats) / sizeof(ClockWndFormats[0])) 00086 00087 #define TRAY_CLOCK_WND_SPACING_X 0 00088 #define TRAY_CLOCK_WND_SPACING_Y 0 00089 00090 typedef struct _TRAY_CLOCK_WND_DATA 00091 { 00092 HWND hWnd; 00093 HWND hWndNotify; 00094 HFONT hFont; 00095 RECT rcText; 00096 SYSTEMTIME LocalTime; 00097 00098 union 00099 { 00100 DWORD dwFlags; 00101 struct 00102 { 00103 DWORD IsTimerEnabled : 1; 00104 DWORD IsInitTimerEnabled : 1; 00105 DWORD LinesMeasured : 1; 00106 DWORD IsHorizontal : 1; 00107 }; 00108 }; 00109 DWORD LineSpacing; 00110 SIZE CurrentSize; 00111 WORD VisibleLines; 00112 SIZE LineSizes[CLOCKWND_FORMAT_COUNT]; 00113 TCHAR szLines[CLOCKWND_FORMAT_COUNT][48]; 00114 } TRAY_CLOCK_WND_DATA, *PTRAY_CLOCK_WND_DATA; 00115 00116 static BOOL 00117 TrayClockWnd_MeasureLines(IN OUT PTRAY_CLOCK_WND_DATA This) 00118 { 00119 HDC hDC; 00120 HFONT hPrevFont; 00121 INT c, i; 00122 BOOL bRet = TRUE; 00123 00124 hDC = GetDC(This->hWnd); 00125 if (hDC != NULL) 00126 { 00127 hPrevFont = SelectObject(hDC, 00128 This->hFont); 00129 00130 for (i = 0; 00131 i != CLOCKWND_FORMAT_COUNT && bRet; 00132 i++) 00133 { 00134 if (This->szLines[i][0] != TEXT('\0') && 00135 !GetTextExtentPoint(hDC, 00136 This->szLines[i], 00137 _tcslen(This->szLines[i]), 00138 &This->LineSizes[i])) 00139 { 00140 bRet = FALSE; 00141 break; 00142 } 00143 } 00144 00145 SelectObject(hDC, 00146 hPrevFont); 00147 00148 ReleaseDC(This->hWnd, 00149 hDC); 00150 00151 if (bRet) 00152 { 00153 This->LineSpacing = 0; 00154 00155 /* calculate the line spacing */ 00156 for (i = 0, c = 0; 00157 i != CLOCKWND_FORMAT_COUNT; 00158 i++) 00159 { 00160 if (This->LineSizes[i].cx > 0) 00161 { 00162 This->LineSpacing += This->LineSizes[i].cy; 00163 c++; 00164 } 00165 } 00166 00167 if (c > 0) 00168 { 00169 /* We want a spaceing of 1/2 line */ 00170 This->LineSpacing = (This->LineSpacing / c) / 2; 00171 } 00172 00173 return TRUE; 00174 } 00175 } 00176 00177 return FALSE; 00178 } 00179 00180 static WORD 00181 TrayClockWnd_GetMinimumSize(IN OUT PTRAY_CLOCK_WND_DATA This, 00182 IN BOOL Horizontal, 00183 IN OUT PSIZE pSize) 00184 { 00185 WORD iLinesVisible = 0; 00186 INT i; 00187 SIZE szMax = { 0, 0 }; 00188 00189 if (!This->LinesMeasured) 00190 This->LinesMeasured = TrayClockWnd_MeasureLines(This); 00191 00192 if (!This->LinesMeasured) 00193 return 0; 00194 00195 for (i = 0; 00196 i != CLOCKWND_FORMAT_COUNT; 00197 i++) 00198 { 00199 if (This->LineSizes[i].cx != 0) 00200 { 00201 if (iLinesVisible > 0) 00202 { 00203 if (Horizontal) 00204 { 00205 if (szMax.cy + This->LineSizes[i].cy + (LONG)This->LineSpacing > 00206 pSize->cy - (2 * TRAY_CLOCK_WND_SPACING_Y)) 00207 { 00208 break; 00209 } 00210 } 00211 else 00212 { 00213 if (This->LineSizes[i].cx > pSize->cx - (2 * TRAY_CLOCK_WND_SPACING_X)) 00214 break; 00215 } 00216 00217 /* Add line spacing */ 00218 szMax.cy += This->LineSpacing; 00219 } 00220 00221 iLinesVisible++; 00222 00223 /* Increase maximum rectangle */ 00224 szMax.cy += This->LineSizes[i].cy; 00225 if (This->LineSizes[i].cx > szMax.cx - (2 * TRAY_CLOCK_WND_SPACING_X)) 00226 szMax.cx = This->LineSizes[i].cx + (2 * TRAY_CLOCK_WND_SPACING_X); 00227 } 00228 } 00229 00230 szMax.cx += 2 * TRAY_CLOCK_WND_SPACING_X; 00231 szMax.cy += 2 * TRAY_CLOCK_WND_SPACING_Y; 00232 00233 *pSize = szMax; 00234 00235 return iLinesVisible; 00236 } 00237 00238 00239 static VOID 00240 TrayClockWnd_UpdateWnd(IN OUT PTRAY_CLOCK_WND_DATA This) 00241 { 00242 SIZE szPrevCurrent; 00243 INT BufSize, iRet, i; 00244 RECT rcClient; 00245 00246 ZeroMemory(This->LineSizes, 00247 sizeof(This->LineSizes)); 00248 00249 szPrevCurrent = This->CurrentSize; 00250 00251 for (i = 0; 00252 i != CLOCKWND_FORMAT_COUNT; 00253 i++) 00254 { 00255 This->szLines[i][0] = TEXT('\0'); 00256 BufSize = sizeof(This->szLines[0]) / sizeof(This->szLines[0][0]); 00257 00258 if (ClockWndFormats[i].IsTime) 00259 { 00260 iRet = GetTimeFormat(LOCALE_USER_DEFAULT, 00261 ClockWndFormats[i].dwFormatFlags, 00262 &This->LocalTime, 00263 ClockWndFormats[i].lpFormat, 00264 This->szLines[i], 00265 BufSize); 00266 } 00267 else 00268 { 00269 iRet = GetDateFormat(LOCALE_USER_DEFAULT, 00270 ClockWndFormats[i].dwFormatFlags, 00271 &This->LocalTime, 00272 ClockWndFormats[i].lpFormat, 00273 This->szLines[i], 00274 BufSize); 00275 } 00276 00277 if (iRet != 0 && i == 0) 00278 { 00279 if (blShowSeconds == FALSE) 00280 { 00281 (This->szLines[0][5] = '\0'); 00282 }; 00283 00284 /* Set the window text to the time only */ 00285 SetWindowText(This->hWnd, 00286 This->szLines[i]); 00287 } 00288 } 00289 00290 This->LinesMeasured = TrayClockWnd_MeasureLines(This); 00291 00292 if (This->LinesMeasured && 00293 GetClientRect(This->hWnd, 00294 &rcClient)) 00295 { 00296 SIZE szWnd; 00297 00298 szWnd.cx = rcClient.right; 00299 szWnd.cy = rcClient.bottom; 00300 00301 This->VisibleLines = TrayClockWnd_GetMinimumSize(This, 00302 This->IsHorizontal, 00303 &szWnd); 00304 This->CurrentSize = szWnd; 00305 } 00306 00307 if (IsWindowVisible(This->hWnd)) 00308 { 00309 InvalidateRect(This->hWnd, 00310 NULL, 00311 TRUE); 00312 00313 if (This->hWndNotify != NULL && 00314 (szPrevCurrent.cx != This->CurrentSize.cx || 00315 szPrevCurrent.cy != This->CurrentSize.cy)) 00316 { 00317 NMHDR nmh; 00318 00319 nmh.hwndFrom = This->hWnd; 00320 nmh.idFrom = GetWindowLongPtr(This->hWnd, 00321 GWL_ID); 00322 nmh.code = NTNWM_REALIGN; 00323 00324 SendMessage(This->hWndNotify, 00325 WM_NOTIFY, 00326 (WPARAM)nmh.idFrom, 00327 (LPARAM)&nmh); 00328 } 00329 } 00330 } 00331 00332 static VOID 00333 TrayClockWnd_Update(IN OUT PTRAY_CLOCK_WND_DATA This) 00334 { 00335 GetLocalTime(&This->LocalTime); 00336 TrayClockWnd_UpdateWnd(This); 00337 } 00338 00339 static UINT 00340 TrayClockWnd_CalculateDueTime(IN OUT PTRAY_CLOCK_WND_DATA This) 00341 { 00342 UINT uiDueTime; 00343 00344 /* Calculate the due time */ 00345 GetLocalTime(&This->LocalTime); 00346 uiDueTime = 1000 - (UINT)This->LocalTime.wMilliseconds; 00347 if (blShowSeconds == TRUE) 00348 uiDueTime += ( (UINT)This->LocalTime.wSecond) * 100; 00349 else 00350 uiDueTime += (59 - (UINT)This->LocalTime.wSecond) * 1000; 00351 00352 if (uiDueTime < USER_TIMER_MINIMUM || uiDueTime > USER_TIMER_MAXIMUM) 00353 uiDueTime = 1000; 00354 else 00355 { 00356 /* Add an artificial delay of 0.05 seconds to make sure the timer 00357 doesn't fire too early*/ 00358 uiDueTime += 50; 00359 } 00360 00361 return uiDueTime; 00362 } 00363 00364 static BOOL 00365 TrayClockWnd_ResetTime(IN OUT PTRAY_CLOCK_WND_DATA This) 00366 { 00367 UINT uiDueTime; 00368 BOOL Ret; 00369 00370 /* Disable all timers */ 00371 if (This->IsTimerEnabled) 00372 { 00373 KillTimer(This->hWnd, 00374 ID_TRAYCLOCK_TIMER); 00375 This->IsTimerEnabled = FALSE; 00376 } 00377 00378 if (This->IsInitTimerEnabled) 00379 { 00380 KillTimer(This->hWnd, 00381 ID_TRAYCLOCK_TIMER_INIT); 00382 } 00383 00384 uiDueTime = TrayClockWnd_CalculateDueTime(This); 00385 00386 /* Set the new timer */ 00387 Ret = SetTimer(This->hWnd, 00388 ID_TRAYCLOCK_TIMER_INIT, 00389 uiDueTime, 00390 NULL) != 0; 00391 This->IsInitTimerEnabled = Ret; 00392 00393 /* Update the time */ 00394 TrayClockWnd_Update(This); 00395 00396 return Ret; 00397 } 00398 00399 static VOID 00400 TrayClockWnd_CalibrateTimer(IN OUT PTRAY_CLOCK_WND_DATA This) 00401 { 00402 UINT uiDueTime; 00403 BOOL Ret; 00404 int intWait1, intWait2; 00405 00406 /* Kill the initialization timer */ 00407 KillTimer(This->hWnd, 00408 ID_TRAYCLOCK_TIMER_INIT); 00409 This->IsInitTimerEnabled = FALSE; 00410 00411 uiDueTime = TrayClockWnd_CalculateDueTime(This); 00412 00413 if (blShowSeconds == TRUE) 00414 { 00415 intWait1 = 1000-200; 00416 intWait2 = 1000; 00417 } 00418 else 00419 { 00420 intWait1 = 60*1000-200; 00421 intWait2 = 60*1000; 00422 } 00423 00424 if (uiDueTime > intWait1) 00425 { 00426 /* The update of the clock will be up to 200 ms late, but that's 00427 acceptable. We're going to setup a timer that fires depending 00428 intWait2. */ 00429 Ret = SetTimer(This->hWnd, 00430 ID_TRAYCLOCK_TIMER, 00431 intWait2, 00432 NULL) != 0; 00433 This->IsTimerEnabled = Ret; 00434 00435 /* Update the time */ 00436 TrayClockWnd_Update(This); 00437 } 00438 else 00439 { 00440 /* Recalibrate the timer and recalculate again when the current 00441 minute/second ends. */ 00442 TrayClockWnd_ResetTime(This); 00443 } 00444 } 00445 00446 static VOID 00447 TrayClockWnd_NCDestroy(IN OUT PTRAY_CLOCK_WND_DATA This) 00448 { 00449 /* Disable all timers */ 00450 if (This->IsTimerEnabled) 00451 { 00452 KillTimer(This->hWnd, 00453 ID_TRAYCLOCK_TIMER); 00454 } 00455 00456 if (This->IsInitTimerEnabled) 00457 { 00458 KillTimer(This->hWnd, 00459 ID_TRAYCLOCK_TIMER_INIT); 00460 } 00461 00462 /* Free allocated resources */ 00463 SetWindowLongPtr(This->hWnd, 00464 0, 00465 0); 00466 HeapFree(hProcessHeap, 00467 0, 00468 This); 00469 } 00470 00471 static VOID 00472 TrayClockWnd_Paint(IN OUT PTRAY_CLOCK_WND_DATA This, 00473 IN HDC hDC) 00474 { 00475 RECT rcClient; 00476 HFONT hPrevFont; 00477 int iPrevBkMode, i, line; 00478 00479 if (This->LinesMeasured && 00480 GetClientRect(This->hWnd, 00481 &rcClient)) 00482 { 00483 iPrevBkMode = SetBkMode(hDC, 00484 TRANSPARENT); 00485 00486 hPrevFont = SelectObject(hDC, 00487 This->hFont); 00488 00489 rcClient.left = (rcClient.right / 2) - (This->CurrentSize.cx / 2); 00490 rcClient.top = (rcClient.bottom / 2) - (This->CurrentSize.cy / 2); 00491 rcClient.right = rcClient.left + This->CurrentSize.cx; 00492 rcClient.bottom = rcClient.top + This->CurrentSize.cy; 00493 00494 for (i = 0, line = 0; 00495 i != CLOCKWND_FORMAT_COUNT && line < This->VisibleLines; 00496 i++) 00497 { 00498 if (This->LineSizes[i].cx != 0) 00499 { 00500 TextOut(hDC, 00501 rcClient.left + (This->CurrentSize.cx / 2) - (This->LineSizes[i].cx / 2) + 00502 TRAY_CLOCK_WND_SPACING_X, 00503 rcClient.top + TRAY_CLOCK_WND_SPACING_Y, 00504 This->szLines[i], 00505 _tcslen(This->szLines[i])); 00506 00507 rcClient.top += This->LineSizes[i].cy + This->LineSpacing; 00508 line++; 00509 } 00510 } 00511 00512 SelectObject(hDC, 00513 hPrevFont); 00514 00515 SetBkMode(hDC, 00516 iPrevBkMode); 00517 } 00518 } 00519 00520 static VOID 00521 TrayClockWnd_SetFont(IN OUT PTRAY_CLOCK_WND_DATA This, 00522 IN HFONT hNewFont, 00523 IN BOOL bRedraw) 00524 { 00525 This->hFont = hNewFont; 00526 This->LinesMeasured = TrayClockWnd_MeasureLines(This); 00527 if (bRedraw) 00528 { 00529 InvalidateRect(This->hWnd, 00530 NULL, 00531 TRUE); 00532 } 00533 } 00534 00535 static LRESULT CALLBACK 00536 TrayClockWndProc(IN HWND hwnd, 00537 IN UINT uMsg, 00538 IN WPARAM wParam, 00539 IN LPARAM lParam) 00540 { 00541 PTRAY_CLOCK_WND_DATA This = NULL; 00542 LRESULT Ret = FALSE; 00543 00544 if (uMsg != WM_NCCREATE) 00545 { 00546 This = (PTRAY_CLOCK_WND_DATA)GetWindowLongPtr(hwnd, 00547 0); 00548 } 00549 00550 if (This != NULL || uMsg == WM_NCCREATE) 00551 { 00552 switch (uMsg) 00553 { 00554 case WM_PAINT: 00555 case WM_PRINTCLIENT: 00556 { 00557 PAINTSTRUCT ps; 00558 HDC hDC = (HDC)wParam; 00559 00560 if (wParam == 0) 00561 { 00562 hDC = BeginPaint(This->hWnd, 00563 &ps); 00564 } 00565 00566 if (hDC != NULL) 00567 { 00568 TrayClockWnd_Paint(This, 00569 hDC); 00570 00571 if (wParam == 0) 00572 { 00573 EndPaint(This->hWnd, 00574 &ps); 00575 } 00576 } 00577 break; 00578 } 00579 00580 case WM_TIMER: 00581 switch (wParam) 00582 { 00583 case ID_TRAYCLOCK_TIMER: 00584 TrayClockWnd_Update(This); 00585 break; 00586 00587 case ID_TRAYCLOCK_TIMER_INIT: 00588 TrayClockWnd_CalibrateTimer(This); 00589 break; 00590 } 00591 break; 00592 00593 case WM_NCHITTEST: 00594 /* We want the user to be able to drag the task bar when clicking the clock */ 00595 Ret = HTTRANSPARENT; 00596 break; 00597 00598 case TCWM_GETMINIMUMSIZE: 00599 { 00600 This->IsHorizontal = (BOOL)wParam; 00601 00602 Ret = (LRESULT)TrayClockWnd_GetMinimumSize(This, 00603 (BOOL)wParam, 00604 (PSIZE)lParam) != 0; 00605 break; 00606 } 00607 00608 case TCWM_UPDATETIME: 00609 { 00610 Ret = (LRESULT)TrayClockWnd_ResetTime(This); 00611 break; 00612 } 00613 00614 case WM_NCCREATE: 00615 { 00616 LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam; 00617 This = (PTRAY_CLOCK_WND_DATA)CreateStruct->lpCreateParams; 00618 This->hWnd = hwnd; 00619 This->hWndNotify = CreateStruct->hwndParent; 00620 00621 SetWindowLongPtr(hwnd, 00622 0, 00623 (LONG_PTR)This); 00624 00625 return TRUE; 00626 } 00627 00628 case WM_SETFONT: 00629 { 00630 TrayClockWnd_SetFont(This, 00631 (HFONT)wParam, 00632 (BOOL)LOWORD(lParam)); 00633 break; 00634 } 00635 00636 case WM_CREATE: 00637 TrayClockWnd_ResetTime(This); 00638 break; 00639 00640 case WM_NCDESTROY: 00641 TrayClockWnd_NCDestroy(This); 00642 break; 00643 00644 case WM_SIZE: 00645 { 00646 SIZE szClient; 00647 00648 szClient.cx = LOWORD(lParam); 00649 szClient.cy = HIWORD(lParam); 00650 This->VisibleLines = TrayClockWnd_GetMinimumSize(This, 00651 This->IsHorizontal, 00652 &szClient); 00653 This->CurrentSize = szClient; 00654 00655 InvalidateRect(This->hWnd, 00656 NULL, 00657 TRUE); 00658 break; 00659 } 00660 00661 default: 00662 Ret = DefWindowProc(hwnd, 00663 uMsg, 00664 wParam, 00665 lParam); 00666 break; 00667 } 00668 } 00669 00670 return Ret; 00671 } 00672 00673 static HWND 00674 CreateTrayClockWnd(IN HWND hWndParent, 00675 IN BOOL bVisible) 00676 { 00677 PTRAY_CLOCK_WND_DATA TcData; 00678 DWORD dwStyle; 00679 HWND hWnd = NULL; 00680 LoadSettings(); 00681 00682 TcData = HeapAlloc(hProcessHeap, 00683 0, 00684 sizeof(*TcData)); 00685 if (TcData != NULL) 00686 { 00687 ZeroMemory(TcData, 00688 sizeof(*TcData)); 00689 00690 TcData->IsHorizontal = TRUE; 00691 /* Create the window. The tray window is going to move it to the correct 00692 position and resize it as needed. */ 00693 dwStyle = WS_CHILD | WS_CLIPSIBLINGS; 00694 if (bVisible) 00695 dwStyle |= WS_VISIBLE; 00696 00697 hWnd = CreateWindowEx(0, 00698 szTrayClockWndClass, 00699 NULL, 00700 dwStyle, 00701 0, 00702 0, 00703 0, 00704 0, 00705 hWndParent, 00706 NULL, 00707 hExplorerInstance, 00708 (LPVOID)TcData); 00709 00710 if (hWnd == NULL) 00711 { 00712 HeapFree(hProcessHeap, 00713 0, 00714 TcData); 00715 } 00716 } 00717 00718 return hWnd; 00719 00720 } 00721 00722 static BOOL 00723 RegisterTrayClockWndClass(VOID) 00724 { 00725 WNDCLASS wcTrayClock; 00726 00727 wcTrayClock.style = CS_DBLCLKS; 00728 wcTrayClock.lpfnWndProc = TrayClockWndProc; 00729 wcTrayClock.cbClsExtra = 0; 00730 wcTrayClock.cbWndExtra = sizeof(PTRAY_CLOCK_WND_DATA); 00731 wcTrayClock.hInstance = hExplorerInstance; 00732 wcTrayClock.hIcon = NULL; 00733 wcTrayClock.hCursor = LoadCursor(NULL, 00734 IDC_ARROW); 00735 wcTrayClock.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); 00736 wcTrayClock.lpszMenuName = NULL; 00737 wcTrayClock.lpszClassName = szTrayClockWndClass; 00738 00739 return RegisterClass(&wcTrayClock) != 0; 00740 } 00741 00742 static VOID 00743 UnregisterTrayClockWndClass(VOID) 00744 { 00745 UnregisterClass(szTrayClockWndClass, 00746 hExplorerInstance); 00747 } 00748 00749 /* 00750 * TrayNotifyWnd 00751 */ 00752 00753 static const TCHAR szTrayNotifyWndClass[] = TEXT("TrayNotifyWnd"); 00754 00755 #define TRAY_NOTIFY_WND_SPACING_X 2 00756 #define TRAY_NOTIFY_WND_SPACING_Y 2 00757 00758 typedef struct _TRAY_NOTIFY_WND_DATA 00759 { 00760 HWND hWnd; 00761 HWND hWndTrayClock; 00762 HWND hWndNotify; 00763 SIZE szTrayClockMin; 00764 SIZE szNonClient; 00765 ITrayWindow *TrayWindow; 00766 union 00767 { 00768 DWORD dwFlags; 00769 struct 00770 { 00771 DWORD HideClock : 1; 00772 DWORD IsHorizontal : 1; 00773 }; 00774 }; 00775 } TRAY_NOTIFY_WND_DATA, *PTRAY_NOTIFY_WND_DATA; 00776 00777 static VOID 00778 TrayNotifyWnd_UpdateStyle(IN OUT PTRAY_NOTIFY_WND_DATA This) 00779 { 00780 RECT rcClient = { 0, 0, 0, 0 }; 00781 00782 if (AdjustWindowRectEx(&rcClient, 00783 GetWindowLongPtr(This->hWnd, 00784 GWL_STYLE), 00785 FALSE, 00786 GetWindowLongPtr(This->hWnd, 00787 GWL_EXSTYLE))) 00788 { 00789 This->szNonClient.cx = rcClient.right - rcClient.left; 00790 This->szNonClient.cy = rcClient.bottom - rcClient.top; 00791 } 00792 else 00793 This->szNonClient.cx = This->szNonClient.cy = 0; 00794 } 00795 00796 static VOID 00797 TrayNotifyWnd_Create(IN OUT PTRAY_NOTIFY_WND_DATA This) 00798 { 00799 This->hWndTrayClock = CreateTrayClockWnd(This->hWnd, 00800 !This->HideClock); 00801 00802 TrayNotifyWnd_UpdateStyle(This); 00803 } 00804 00805 static VOID 00806 TrayNotifyWnd_NCDestroy(IN OUT PTRAY_NOTIFY_WND_DATA This) 00807 { 00808 SetWindowLongPtr(This->hWnd, 00809 0, 00810 0); 00811 HeapFree(hProcessHeap, 00812 0, 00813 This); 00814 } 00815 00816 static BOOL 00817 TrayNotifyWnd_GetMinimumSize(IN OUT PTRAY_NOTIFY_WND_DATA This, 00818 IN BOOL Horizontal, 00819 IN OUT PSIZE pSize) 00820 { 00821 This->IsHorizontal = Horizontal; 00822 00823 if (!This->HideClock) 00824 { 00825 SIZE szClock = { 0, 0 }; 00826 00827 if (Horizontal) 00828 { 00829 szClock.cy = pSize->cy - This->szNonClient.cy - (2 * TRAY_NOTIFY_WND_SPACING_Y); 00830 if (szClock.cy <= 0) 00831 goto NoClock; 00832 } 00833 else 00834 { 00835 szClock.cx = pSize->cx - This->szNonClient.cx - (2 * TRAY_NOTIFY_WND_SPACING_X); 00836 if (szClock.cx <= 0) 00837 goto NoClock; 00838 } 00839 00840 SendMessage(This->hWndTrayClock, 00841 TCWM_GETMINIMUMSIZE, 00842 (WPARAM)Horizontal, 00843 (LPARAM)&szClock); 00844 00845 This->szTrayClockMin = szClock; 00846 } 00847 else 00848 NoClock: 00849 This->szTrayClockMin = This->szNonClient; 00850 00851 if (Horizontal) 00852 { 00853 pSize->cx = This->szNonClient.cx + (2 * TRAY_NOTIFY_WND_SPACING_X); 00854 00855 if (!This->HideClock) 00856 pSize->cx += TRAY_NOTIFY_WND_SPACING_X + This->szTrayClockMin.cx; 00857 } 00858 else 00859 { 00860 pSize->cy = This->szNonClient.cy + (2 * TRAY_NOTIFY_WND_SPACING_Y); 00861 00862 if (!This->HideClock) 00863 pSize->cy += TRAY_NOTIFY_WND_SPACING_Y + This->szTrayClockMin.cy; 00864 } 00865 00866 return TRUE; 00867 } 00868 00869 static VOID 00870 TrayNotifyWnd_Size(IN OUT PTRAY_NOTIFY_WND_DATA This, 00871 IN const SIZE *pszClient) 00872 { 00873 if (!This->HideClock) 00874 { 00875 POINT ptClock; 00876 SIZE szClock; 00877 00878 if (This->IsHorizontal) 00879 { 00880 ptClock.x = pszClient->cx - TRAY_NOTIFY_WND_SPACING_X - This->szTrayClockMin.cx; 00881 ptClock.y = TRAY_NOTIFY_WND_SPACING_Y; 00882 szClock.cx = This->szTrayClockMin.cx; 00883 szClock.cy = pszClient->cy - (2 * TRAY_NOTIFY_WND_SPACING_Y); 00884 } 00885 else 00886 { 00887 ptClock.x = TRAY_NOTIFY_WND_SPACING_X; 00888 ptClock.y = pszClient->cy - TRAY_NOTIFY_WND_SPACING_Y - This->szTrayClockMin.cy; 00889 szClock.cx = pszClient->cx - (2 * TRAY_NOTIFY_WND_SPACING_X); 00890 szClock.cy = This->szTrayClockMin.cy; 00891 } 00892 00893 SetWindowPos(This->hWndTrayClock, 00894 NULL, 00895 ptClock.x, 00896 ptClock.y, 00897 szClock.cx, 00898 szClock.cy, 00899 SWP_NOZORDER); 00900 } 00901 } 00902 00903 static LRESULT CALLBACK 00904 TrayNotifyWndProc(IN HWND hwnd, 00905 IN UINT uMsg, 00906 IN WPARAM wParam, 00907 IN LPARAM lParam) 00908 { 00909 PTRAY_NOTIFY_WND_DATA This = NULL; 00910 LRESULT Ret = FALSE; 00911 00912 if (uMsg != WM_NCCREATE) 00913 { 00914 This = (PTRAY_NOTIFY_WND_DATA)GetWindowLongPtr(hwnd, 00915 0); 00916 } 00917 00918 if (This != NULL || uMsg == WM_NCCREATE) 00919 { 00920 switch (uMsg) 00921 { 00922 case TNWM_GETMINIMUMSIZE: 00923 { 00924 Ret = (LRESULT)TrayNotifyWnd_GetMinimumSize(This, 00925 (BOOL)wParam, 00926 (PSIZE)lParam); 00927 break; 00928 } 00929 00930 case TNWM_UPDATETIME: 00931 { 00932 if (This->hWndTrayClock != NULL) 00933 { 00934 /* Forward the message to the tray clock window procedure */ 00935 Ret = TrayClockWndProc(This->hWndTrayClock, 00936 TCWM_UPDATETIME, 00937 wParam, 00938 lParam); 00939 } 00940 break; 00941 } 00942 00943 case WM_SIZE: 00944 { 00945 SIZE szClient; 00946 00947 szClient.cx = LOWORD(lParam); 00948 szClient.cy = HIWORD(lParam); 00949 00950 TrayNotifyWnd_Size(This, 00951 &szClient); 00952 break; 00953 } 00954 00955 case WM_NCHITTEST: 00956 /* We want the user to be able to drag the task bar when clicking the 00957 tray notification window */ 00958 Ret = HTTRANSPARENT; 00959 break; 00960 00961 case TNWM_SHOWCLOCK: 00962 { 00963 BOOL PrevHidden = This->HideClock; 00964 This->HideClock = (wParam == 0); 00965 00966 if (This->hWndTrayClock != NULL && PrevHidden != This->HideClock) 00967 { 00968 ShowWindow(This->hWndTrayClock, 00969 This->HideClock ? SW_HIDE : SW_SHOW); 00970 } 00971 00972 Ret = (LRESULT)(!PrevHidden); 00973 break; 00974 } 00975 00976 case WM_NOTIFY: 00977 { 00978 const NMHDR *nmh = (const NMHDR *)lParam; 00979 00980 if (nmh->hwndFrom == This->hWndTrayClock) 00981 { 00982 /* Pass down notifications */ 00983 Ret = SendMessage(This->hWndNotify, 00984 WM_NOTIFY, 00985 wParam, 00986 lParam); 00987 } 00988 break; 00989 } 00990 00991 case WM_SETFONT: 00992 { 00993 if (This->hWndTrayClock != NULL) 00994 { 00995 SendMessage(This->hWndTrayClock, 00996 WM_SETFONT, 00997 wParam, 00998 lParam); 00999 } 01000 goto HandleDefaultMessage; 01001 } 01002 01003 case WM_NCCREATE: 01004 { 01005 LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam; 01006 This = (PTRAY_NOTIFY_WND_DATA)CreateStruct->lpCreateParams; 01007 This->hWnd = hwnd; 01008 This->hWndNotify = CreateStruct->hwndParent; 01009 01010 SetWindowLongPtr(hwnd, 01011 0, 01012 (LONG_PTR)This); 01013 01014 return TRUE; 01015 } 01016 01017 case WM_CREATE: 01018 TrayNotifyWnd_Create(This); 01019 break; 01020 01021 case WM_NCDESTROY: 01022 TrayNotifyWnd_NCDestroy(This); 01023 break; 01024 01025 default: 01026 HandleDefaultMessage: 01027 Ret = DefWindowProc(hwnd, 01028 uMsg, 01029 wParam, 01030 lParam); 01031 break; 01032 } 01033 } 01034 01035 return Ret; 01036 } 01037 01038 HWND 01039 CreateTrayNotifyWnd(IN OUT ITrayWindow *TrayWindow, 01040 IN BOOL bHideClock) 01041 { 01042 PTRAY_NOTIFY_WND_DATA TnData; 01043 HWND hWndTrayWindow; 01044 HWND hWnd = NULL; 01045 01046 hWndTrayWindow = ITrayWindow_GetHWND(TrayWindow); 01047 if (hWndTrayWindow == NULL) 01048 return NULL; 01049 01050 TnData = HeapAlloc(hProcessHeap, 01051 0, 01052 sizeof(*TnData)); 01053 if (TnData != NULL) 01054 { 01055 ZeroMemory(TnData, 01056 sizeof(*TnData)); 01057 01058 TnData->TrayWindow = TrayWindow; 01059 TnData->HideClock = bHideClock; 01060 01061 /* Create the window. The tray window is going to move it to the correct 01062 position and resize it as needed. */ 01063 hWnd = CreateWindowEx(WS_EX_STATICEDGE, 01064 szTrayNotifyWndClass, 01065 NULL, 01066 WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 01067 0, 01068 0, 01069 0, 01070 0, 01071 hWndTrayWindow, 01072 NULL, 01073 hExplorerInstance, 01074 (LPVOID)TnData); 01075 01076 if (hWnd == NULL) 01077 { 01078 HeapFree(hProcessHeap, 01079 0, 01080 TnData); 01081 } 01082 } 01083 01084 return hWnd; 01085 } 01086 01087 BOOL 01088 RegisterTrayNotifyWndClass(VOID) 01089 { 01090 WNDCLASS wcTrayWnd; 01091 BOOL Ret; 01092 01093 wcTrayWnd.style = CS_DBLCLKS; 01094 wcTrayWnd.lpfnWndProc = TrayNotifyWndProc; 01095 wcTrayWnd.cbClsExtra = 0; 01096 wcTrayWnd.cbWndExtra = sizeof(PTRAY_NOTIFY_WND_DATA); 01097 wcTrayWnd.hInstance = hExplorerInstance; 01098 wcTrayWnd.hIcon = NULL; 01099 wcTrayWnd.hCursor = LoadCursor(NULL, 01100 IDC_ARROW); 01101 wcTrayWnd.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); 01102 wcTrayWnd.lpszMenuName = NULL; 01103 wcTrayWnd.lpszClassName = szTrayNotifyWndClass; 01104 01105 Ret = RegisterClass(&wcTrayWnd) != 0; 01106 01107 if (Ret) 01108 { 01109 Ret = RegisterTrayClockWndClass(); 01110 if (!Ret) 01111 { 01112 UnregisterClass(szTrayNotifyWndClass, 01113 hExplorerInstance); 01114 } 01115 } 01116 01117 return Ret; 01118 } 01119 01120 VOID 01121 UnregisterTrayNotifyWndClass(VOID) 01122 { 01123 UnregisterTrayClockWndClass(); 01124 01125 UnregisterClass(szTrayNotifyWndClass, 01126 hExplorerInstance); 01127 } Generated on Sat May 26 2012 04:17:24 for ReactOS by
1.7.6.1
|