1 /* 2 * PROJECT: ReactOS Timedate Control Panel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: dll/cpl/timedate/timezone.c 5 * PURPOSE: Time Zone property page 6 * COPYRIGHT: Copyright 2004-2005 Eric Kohl 7 * Copyright 2006 Ged Murphy <gedmurphy@gmail.com> 8 * Copyright 2006 Christoph v. Wittich <Christoph@ActiveVB.de> 9 * 10 */ 11 12 #include "timedate.h" 13 #include <tzlib.h> 14 15 typedef struct _TIMEZONE_ENTRY 16 { 17 struct _TIMEZONE_ENTRY *Prev; 18 struct _TIMEZONE_ENTRY *Next; 19 WCHAR Description[128]; /* 'Display' */ 20 WCHAR StandardName[33]; /* 'Std' */ 21 WCHAR DaylightName[33]; /* 'Dlt' */ 22 REG_TZI_FORMAT TimezoneInfo; /* 'TZI' */ 23 } TIMEZONE_ENTRY, *PTIMEZONE_ENTRY; 24 25 26 static HBITMAP hBitmap = NULL; 27 static int cxSource, cySource; 28 29 PTIMEZONE_ENTRY TimeZoneListHead = NULL; 30 PTIMEZONE_ENTRY TimeZoneListTail = NULL; 31 32 static 33 PTIMEZONE_ENTRY 34 GetLargerTimeZoneEntry( 35 LONG Bias, 36 LPWSTR lpDescription) 37 { 38 PTIMEZONE_ENTRY Entry; 39 40 Entry = TimeZoneListHead; 41 while (Entry != NULL) 42 { 43 if (Entry->TimezoneInfo.Bias < Bias) 44 return Entry; 45 46 if (Entry->TimezoneInfo.Bias == Bias) 47 { 48 if (_wcsicmp(Entry->Description, lpDescription) > 0) 49 return Entry; 50 } 51 52 Entry = Entry->Next; 53 } 54 55 return NULL; 56 } 57 58 static LONG 59 RetrieveTimeZone( 60 IN HKEY hZoneKey, 61 IN PVOID Context) 62 { 63 LONG lError; 64 PTIMEZONE_ENTRY Entry; 65 PTIMEZONE_ENTRY Current; 66 ULONG DescriptionSize; 67 ULONG StandardNameSize; 68 ULONG DaylightNameSize; 69 70 Entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TIMEZONE_ENTRY)); 71 if (Entry == NULL) 72 { 73 return ERROR_NOT_ENOUGH_MEMORY; 74 } 75 76 DescriptionSize = sizeof(Entry->Description); 77 StandardNameSize = sizeof(Entry->StandardName); 78 DaylightNameSize = sizeof(Entry->DaylightName); 79 80 lError = QueryTimeZoneData(hZoneKey, 81 NULL, 82 &Entry->TimezoneInfo, 83 Entry->Description, 84 &DescriptionSize, 85 Entry->StandardName, 86 &StandardNameSize, 87 Entry->DaylightName, 88 &DaylightNameSize); 89 if (lError != ERROR_SUCCESS) 90 { 91 HeapFree(GetProcessHeap(), 0, Entry); 92 return lError; 93 } 94 95 if (TimeZoneListHead == NULL && 96 TimeZoneListTail == NULL) 97 { 98 Entry->Prev = NULL; 99 Entry->Next = NULL; 100 TimeZoneListHead = Entry; 101 TimeZoneListTail = Entry; 102 } 103 else 104 { 105 Current = GetLargerTimeZoneEntry(Entry->TimezoneInfo.Bias, Entry->Description); 106 if (Current != NULL) 107 { 108 if (Current == TimeZoneListHead) 109 { 110 /* Prepend to head */ 111 Entry->Prev = NULL; 112 Entry->Next = TimeZoneListHead; 113 TimeZoneListHead->Prev = Entry; 114 TimeZoneListHead = Entry; 115 } 116 else 117 { 118 /* Insert before current */ 119 Entry->Prev = Current->Prev; 120 Entry->Next = Current; 121 Current->Prev->Next = Entry; 122 Current->Prev = Entry; 123 } 124 } 125 else 126 { 127 /* Append to tail */ 128 Entry->Prev = TimeZoneListTail; 129 Entry->Next = NULL; 130 TimeZoneListTail->Next = Entry; 131 TimeZoneListTail = Entry; 132 } 133 } 134 135 return ERROR_SUCCESS; 136 } 137 138 static VOID 139 CreateTimeZoneList(VOID) 140 { 141 EnumerateTimeZoneList(RetrieveTimeZone, NULL); 142 } 143 144 static VOID 145 DestroyTimeZoneList(VOID) 146 { 147 PTIMEZONE_ENTRY Entry; 148 149 while (TimeZoneListHead != NULL) 150 { 151 Entry = TimeZoneListHead; 152 153 TimeZoneListHead = Entry->Next; 154 if (TimeZoneListHead != NULL) 155 { 156 TimeZoneListHead->Prev = NULL; 157 } 158 159 HeapFree(GetProcessHeap(), 0, Entry); 160 } 161 162 TimeZoneListTail = NULL; 163 } 164 165 166 static VOID 167 ShowTimeZoneList(HWND hwnd) 168 { 169 TIME_ZONE_INFORMATION TimeZoneInfo; 170 PTIMEZONE_ENTRY Entry; 171 BOOL bDoAdvancedTest; 172 DWORD dwIndex; 173 DWORD i; 174 175 GetTimeZoneInformation(&TimeZoneInfo); 176 bDoAdvancedTest = (!*TimeZoneInfo.StandardName); 177 178 dwIndex = 0; 179 i = 0; 180 Entry = TimeZoneListHead; 181 while (Entry != NULL) 182 { 183 SendMessageW(hwnd, 184 CB_ADDSTRING, 185 0, 186 (LPARAM)Entry->Description); 187 188 if ( (!bDoAdvancedTest && *Entry->StandardName && 189 wcscmp(Entry->StandardName, TimeZoneInfo.StandardName) == 0) || 190 ( (Entry->TimezoneInfo.Bias == TimeZoneInfo.Bias) && 191 (Entry->TimezoneInfo.StandardBias == TimeZoneInfo.StandardBias) && 192 (Entry->TimezoneInfo.DaylightBias == TimeZoneInfo.DaylightBias) && 193 (memcmp(&Entry->TimezoneInfo.StandardDate, &TimeZoneInfo.StandardDate, sizeof(SYSTEMTIME)) == 0) && 194 (memcmp(&Entry->TimezoneInfo.DaylightDate, &TimeZoneInfo.DaylightDate, sizeof(SYSTEMTIME)) == 0) ) ) 195 { 196 dwIndex = i; 197 } 198 199 i++; 200 Entry = Entry->Next; 201 } 202 203 SendMessageW(hwnd, 204 CB_SETCURSEL, 205 (WPARAM)dwIndex, 206 0); 207 } 208 209 210 static VOID 211 SetLocalTimeZone(HWND hwnd) 212 { 213 TIME_ZONE_INFORMATION TimeZoneInformation; 214 PTIMEZONE_ENTRY Entry; 215 DWORD dwIndex; 216 DWORD i; 217 218 dwIndex = (DWORD)SendMessageW(hwnd, 219 CB_GETCURSEL, 220 0, 221 0); 222 223 i = 0; 224 Entry = TimeZoneListHead; 225 while (i < dwIndex) 226 { 227 if (Entry == NULL) 228 return; 229 230 i++; 231 Entry = Entry->Next; 232 } 233 234 wcscpy(TimeZoneInformation.StandardName, 235 Entry->StandardName); 236 wcscpy(TimeZoneInformation.DaylightName, 237 Entry->DaylightName); 238 239 TimeZoneInformation.Bias = Entry->TimezoneInfo.Bias; 240 TimeZoneInformation.StandardBias = Entry->TimezoneInfo.StandardBias; 241 TimeZoneInformation.DaylightBias = Entry->TimezoneInfo.DaylightBias; 242 243 memcpy(&TimeZoneInformation.StandardDate, 244 &Entry->TimezoneInfo.StandardDate, 245 sizeof(SYSTEMTIME)); 246 memcpy(&TimeZoneInformation.DaylightDate, 247 &Entry->TimezoneInfo.DaylightDate, 248 sizeof(SYSTEMTIME)); 249 250 /* Set time zone information */ 251 SetTimeZoneInformation(&TimeZoneInformation); 252 } 253 254 255 /* Property page dialog callback */ 256 INT_PTR CALLBACK 257 TimeZonePageProc(HWND hwndDlg, 258 UINT uMsg, 259 WPARAM wParam, 260 LPARAM lParam) 261 { 262 BITMAP bitmap; 263 264 switch (uMsg) 265 { 266 case WM_INITDIALOG: 267 { 268 CreateTimeZoneList(); 269 ShowTimeZoneList(GetDlgItem(hwndDlg, IDC_TIMEZONELIST)); 270 271 SendDlgItemMessage(hwndDlg, IDC_AUTODAYLIGHT, BM_SETCHECK, 272 (WPARAM)(GetAutoDaylight() ? BST_CHECKED : BST_UNCHECKED), 0); 273 274 hBitmap = LoadImageW(hApplet, MAKEINTRESOURCEW(IDC_WORLD), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); 275 if (hBitmap != NULL) 276 { 277 GetObjectW(hBitmap, sizeof(bitmap), &bitmap); 278 279 cxSource = bitmap.bmWidth; 280 cySource = bitmap.bmHeight; 281 } 282 break; 283 } 284 285 case WM_DRAWITEM: 286 { 287 LPDRAWITEMSTRUCT lpDrawItem; 288 lpDrawItem = (LPDRAWITEMSTRUCT)lParam; 289 if(lpDrawItem->CtlID == IDC_WORLD_BACKGROUND) 290 { 291 HDC hdcMem; 292 hdcMem = CreateCompatibleDC(lpDrawItem->hDC); 293 if (hdcMem != NULL) 294 { 295 SelectObject(hdcMem, hBitmap); 296 StretchBlt(lpDrawItem->hDC, lpDrawItem->rcItem.left, lpDrawItem->rcItem.top, 297 lpDrawItem->rcItem.right - lpDrawItem->rcItem.left, 298 lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top, 299 hdcMem, 0, 0, cxSource, cySource, SRCCOPY); 300 DeleteDC(hdcMem); 301 } 302 } 303 } 304 break; 305 306 case WM_COMMAND: 307 if ((LOWORD(wParam) == IDC_TIMEZONELIST && HIWORD(wParam) == CBN_SELCHANGE) || 308 (LOWORD(wParam) == IDC_AUTODAYLIGHT && HIWORD(wParam) == BN_CLICKED)) 309 { 310 /* Enable the 'Apply' button */ 311 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 312 } 313 break; 314 315 case WM_DESTROY: 316 DestroyTimeZoneList(); 317 DeleteObject(hBitmap); 318 break; 319 320 case WM_NOTIFY: 321 { 322 LPNMHDR lpnm = (LPNMHDR)lParam; 323 324 switch (lpnm->code) 325 { 326 case PSN_APPLY: 327 { 328 SetAutoDaylight(SendDlgItemMessage(hwndDlg, IDC_AUTODAYLIGHT, 329 BM_GETCHECK, 0, 0) != BST_UNCHECKED); 330 SetLocalTimeZone(GetDlgItem(hwndDlg, IDC_TIMEZONELIST)); 331 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); 332 return TRUE; 333 } 334 335 default: 336 break; 337 } 338 } 339 break; 340 } 341 342 return FALSE; 343 } 344