[BROWSEUI]
[reactos.git] / dll / cpl / timedate / timezone.c
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
14 typedef struct _TZ_INFO
15 {
16 LONG Bias;
17 LONG StandardBias;
18 LONG DaylightBias;
19 SYSTEMTIME StandardDate;
20 SYSTEMTIME DaylightDate;
21 } TZ_INFO, *PTZ_INFO;
22
23 typedef struct _TIMEZONE_ENTRY
24 {
25 struct _TIMEZONE_ENTRY *Prev;
26 struct _TIMEZONE_ENTRY *Next;
27 WCHAR Description[64]; /* 'Display' */
28 WCHAR StandardName[33]; /* 'Std' */
29 WCHAR DaylightName[33]; /* 'Dlt' */
30 TZ_INFO TimezoneInfo; /* 'TZI' */
31 ULONG Index; /* 'Index ' */
32 } TIMEZONE_ENTRY, *PTIMEZONE_ENTRY;
33
34
35 static HBITMAP hBitmap = NULL;
36 static int cxSource, cySource;
37
38 PTIMEZONE_ENTRY TimeZoneListHead = NULL;
39 PTIMEZONE_ENTRY TimeZoneListTail = NULL;
40
41 static PTIMEZONE_ENTRY
42 GetLargerTimeZoneEntry(DWORD Index)
43 {
44 PTIMEZONE_ENTRY Entry;
45
46 Entry = TimeZoneListHead;
47 while (Entry != NULL)
48 {
49 if (Entry->Index >= Index)
50 return Entry;
51
52 Entry = Entry->Next;
53 }
54
55 return NULL;
56 }
57
58
59 static VOID
60 CreateTimeZoneList(VOID)
61 {
62 WCHAR szKeyName[256];
63 DWORD dwIndex;
64 DWORD dwNameSize;
65 DWORD dwValueSize;
66 LONG lError;
67 HKEY hZonesKey;
68 HKEY hZoneKey;
69
70 PTIMEZONE_ENTRY Entry;
71 PTIMEZONE_ENTRY Current;
72
73 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
74 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
75 0,
76 KEY_ENUMERATE_SUB_KEYS,
77 &hZonesKey))
78 return;
79
80 dwIndex = 0;
81 while (TRUE)
82 {
83 dwNameSize = 256 * sizeof(WCHAR);
84 lError = RegEnumKeyExW(hZonesKey,
85 dwIndex,
86 szKeyName,
87 &dwNameSize,
88 NULL,
89 NULL,
90 NULL,
91 NULL);
92 if (lError == ERROR_NO_MORE_ITEMS)
93 break;
94
95 if (RegOpenKeyEx (hZonesKey,
96 szKeyName,
97 0,
98 KEY_QUERY_VALUE,
99 &hZoneKey))
100 break;
101
102 Entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TIMEZONE_ENTRY));
103 if (Entry == NULL)
104 {
105 RegCloseKey(hZoneKey);
106 break;
107 }
108
109 dwValueSize = 64 * sizeof(WCHAR);
110 lError = RegQueryValueExW(hZoneKey,
111 L"Display",
112 NULL,
113 NULL,
114 (LPBYTE)&Entry->Description,
115 &dwValueSize);
116 if (lError != ERROR_SUCCESS)
117 {
118 RegCloseKey(hZoneKey);
119 dwIndex++;
120 HeapFree(GetProcessHeap(), 0, Entry);
121 continue;
122 }
123
124 dwValueSize = 33 * sizeof(WCHAR);
125 if (RegQueryValueExW(hZoneKey,
126 L"Std",
127 NULL,
128 NULL,
129 (LPBYTE)&Entry->StandardName,
130 &dwValueSize))
131 {
132 RegCloseKey(hZoneKey);
133 break;
134 }
135
136 dwValueSize = 33 * sizeof(WCHAR);
137 if (RegQueryValueExW(hZoneKey,
138 L"Dlt",
139 NULL,
140 NULL,
141 (LPBYTE)&Entry->DaylightName,
142 &dwValueSize))
143 {
144 RegCloseKey(hZoneKey);
145 break;
146 }
147
148 dwValueSize = sizeof(DWORD);
149 if (RegQueryValueExW(hZoneKey,
150 L"Index",
151 NULL,
152 NULL,
153 (LPBYTE)&Entry->Index,
154 &dwValueSize))
155 {
156 RegCloseKey(hZoneKey);
157 break;
158 }
159
160 dwValueSize = sizeof(TZ_INFO);
161 if (RegQueryValueExW(hZoneKey,
162 L"TZI",
163 NULL,
164 NULL,
165 (LPBYTE)&Entry->TimezoneInfo,
166 &dwValueSize))
167 {
168 RegCloseKey(hZoneKey);
169 break;
170 }
171
172 RegCloseKey(hZoneKey);
173
174 if (TimeZoneListHead == NULL &&
175 TimeZoneListTail == NULL)
176 {
177 Entry->Prev = NULL;
178 Entry->Next = NULL;
179 TimeZoneListHead = Entry;
180 TimeZoneListTail = Entry;
181 }
182 else
183 {
184 Current = GetLargerTimeZoneEntry(Entry->Index);
185 if (Current != NULL)
186 {
187 if (Current == TimeZoneListHead)
188 {
189 /* Prepend to head */
190 Entry->Prev = NULL;
191 Entry->Next = TimeZoneListHead;
192 TimeZoneListHead->Prev = Entry;
193 TimeZoneListHead = Entry;
194 }
195 else
196 {
197 /* Insert before current */
198 Entry->Prev = Current->Prev;
199 Entry->Next = Current;
200 Current->Prev->Next = Entry;
201 Current->Prev = Entry;
202 }
203 }
204 else
205 {
206 /* Append to tail */
207 Entry->Prev = TimeZoneListTail;
208 Entry->Next = NULL;
209 TimeZoneListTail->Next = Entry;
210 TimeZoneListTail = Entry;
211 }
212 }
213
214 dwIndex++;
215 }
216
217 RegCloseKey(hZonesKey);
218 }
219
220
221 static VOID
222 DestroyTimeZoneList(VOID)
223 {
224 PTIMEZONE_ENTRY Entry;
225
226 while (TimeZoneListHead != NULL)
227 {
228 Entry = TimeZoneListHead;
229
230 TimeZoneListHead = Entry->Next;
231 if (TimeZoneListHead != NULL)
232 {
233 TimeZoneListHead->Prev = NULL;
234 }
235
236 HeapFree(GetProcessHeap(), 0, Entry);
237 }
238
239 TimeZoneListTail = NULL;
240 }
241
242
243 static VOID
244 ShowTimeZoneList(HWND hwnd)
245 {
246 TIME_ZONE_INFORMATION TimeZoneInfo;
247 PTIMEZONE_ENTRY Entry;
248 DWORD dwIndex;
249 DWORD i;
250
251 GetTimeZoneInformation(&TimeZoneInfo);
252
253 dwIndex = 0;
254 i = 0;
255 Entry = TimeZoneListHead;
256 while (Entry != NULL)
257 {
258 SendMessageW(hwnd,
259 CB_ADDSTRING,
260 0,
261 (LPARAM)Entry->Description);
262
263 if (!wcscmp(Entry->StandardName, TimeZoneInfo.StandardName))
264 dwIndex = i;
265
266 i++;
267 Entry = Entry->Next;
268 }
269
270 SendMessageW(hwnd,
271 CB_SETCURSEL,
272 (WPARAM)dwIndex,
273 0);
274 }
275
276
277 static VOID
278 SetLocalTimeZone(HWND hwnd)
279 {
280 TIME_ZONE_INFORMATION TimeZoneInformation;
281 PTIMEZONE_ENTRY Entry;
282 DWORD dwIndex;
283 DWORD i;
284
285 dwIndex = (DWORD)SendMessageW(hwnd,
286 CB_GETCURSEL,
287 0,
288 0);
289
290 i = 0;
291 Entry = TimeZoneListHead;
292 while (i < dwIndex)
293 {
294 if (Entry == NULL)
295 return;
296
297 i++;
298 Entry = Entry->Next;
299 }
300
301 wcscpy(TimeZoneInformation.StandardName,
302 Entry->StandardName);
303 wcscpy(TimeZoneInformation.DaylightName,
304 Entry->DaylightName);
305
306 TimeZoneInformation.Bias = Entry->TimezoneInfo.Bias;
307 TimeZoneInformation.StandardBias = Entry->TimezoneInfo.StandardBias;
308 TimeZoneInformation.DaylightBias = Entry->TimezoneInfo.DaylightBias;
309
310 memcpy(&TimeZoneInformation.StandardDate,
311 &Entry->TimezoneInfo.StandardDate,
312 sizeof(SYSTEMTIME));
313 memcpy(&TimeZoneInformation.DaylightDate,
314 &Entry->TimezoneInfo.DaylightDate,
315 sizeof(SYSTEMTIME));
316
317 /* Set time zone information */
318 SetTimeZoneInformation(&TimeZoneInformation);
319 }
320
321
322 static VOID
323 GetAutoDaylightInfo(HWND hwnd)
324 {
325 HKEY hKey;
326
327 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
328 L"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation",
329 0,
330 KEY_QUERY_VALUE,
331 &hKey))
332 return;
333
334 /* If the call fails (non zero), the reg value isn't available,
335 * which means it shouldn't be disabled, so we should check the button.
336 */
337 if (RegQueryValueExW(hKey,
338 L"DisableAutoDaylightTimeSet",
339 NULL,
340 NULL,
341 NULL,
342 NULL))
343 {
344 SendMessageW(hwnd, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
345 }
346 else
347 {
348 SendMessageW(hwnd, BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
349 }
350
351 RegCloseKey(hKey);
352 }
353
354
355 static VOID
356 SetAutoDaylightInfo(HWND hwnd)
357 {
358 HKEY hKey;
359 DWORD dwValue = 1;
360
361 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
362 L"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation",
363 0,
364 KEY_SET_VALUE,
365 &hKey))
366 return;
367
368 if (SendMessageW(hwnd, BM_GETCHECK, 0, 0) == BST_UNCHECKED)
369 {
370 RegSetValueExW(hKey,
371 L"DisableAutoDaylightTimeSet",
372 0,
373 REG_DWORD,
374 (LPBYTE)&dwValue,
375 sizeof(DWORD));
376 }
377 else
378 {
379 RegDeleteValueW(hKey,
380 L"DisableAutoDaylightTimeSet");
381 }
382
383 RegCloseKey(hKey);
384 }
385
386
387 /* Property page dialog callback */
388 INT_PTR CALLBACK
389 TimeZonePageProc(HWND hwndDlg,
390 UINT uMsg,
391 WPARAM wParam,
392 LPARAM lParam)
393 {
394 BITMAP bitmap;
395
396 switch (uMsg)
397 {
398 case WM_INITDIALOG:
399 CreateTimeZoneList();
400 ShowTimeZoneList(GetDlgItem(hwndDlg, IDC_TIMEZONELIST));
401 GetAutoDaylightInfo(GetDlgItem(hwndDlg, IDC_AUTODAYLIGHT));
402 hBitmap = LoadImageW(hApplet, MAKEINTRESOURCEW(IDC_WORLD), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
403 if (hBitmap != NULL)
404 {
405 GetObjectW(hBitmap, sizeof(BITMAP), &bitmap);
406
407 cxSource = bitmap.bmWidth;
408 cySource = bitmap.bmHeight;
409 }
410 break;
411
412 case WM_DRAWITEM:
413 {
414 LPDRAWITEMSTRUCT lpDrawItem;
415 lpDrawItem = (LPDRAWITEMSTRUCT) lParam;
416 if(lpDrawItem->CtlID == IDC_WORLD_BACKGROUND)
417 {
418 HDC hdcMem;
419 hdcMem = CreateCompatibleDC(lpDrawItem->hDC);
420 if (hdcMem != NULL)
421 {
422 SelectObject(hdcMem, hBitmap);
423 StretchBlt(lpDrawItem->hDC, lpDrawItem->rcItem.left, lpDrawItem->rcItem.top,
424 lpDrawItem->rcItem.right - lpDrawItem->rcItem.left,
425 lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top,
426 hdcMem, 0, 0, cxSource, cySource, SRCCOPY);
427 DeleteDC(hdcMem);
428 }
429 }
430 }
431 break;
432
433 case WM_COMMAND:
434 if ((LOWORD(wParam) == IDC_TIMEZONELIST && HIWORD(wParam) == CBN_SELCHANGE) ||
435 (LOWORD(wParam) == IDC_AUTODAYLIGHT && HIWORD(wParam) == BN_CLICKED))
436 {
437 /* Enable the 'Apply' button */
438 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
439 }
440 break;
441
442 case WM_DESTROY:
443 DestroyTimeZoneList();
444 DeleteObject(hBitmap);
445 break;
446
447 case WM_NOTIFY:
448 {
449 LPNMHDR lpnm = (LPNMHDR)lParam;
450
451 switch (lpnm->code)
452 {
453 case PSN_APPLY:
454 {
455 SetAutoDaylightInfo(GetDlgItem(hwndDlg, IDC_AUTODAYLIGHT));
456 SetLocalTimeZone(GetDlgItem(hwndDlg, IDC_TIMEZONELIST));
457 SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR);
458 return TRUE;
459 }
460
461 default:
462 break;
463 }
464 }
465 break;
466 }
467
468 return FALSE;
469 }