ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

trayntfy.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.