[CMAKE]
[reactos.git] / dll / cpl / timedate / dateandtime.c
1 /*
2 * PROJECT: ReactOS Timedate Control Panel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/cpl/timedate/dateandtime.c
5 * PURPOSE: Date & Time property page
6 * COPYRIGHT: Copyright 2004-2007 Eric Kohl
7 * Copyright 2006 Ged Murphy <gedmurphy@gmail.com>
8 * Copyright 2006 Thomas Weidenmueller <w3seek@reactos.com>
9 *
10 */
11
12 #include <timedate.h>
13
14 static WNDPROC pOldWndProc = NULL;
15
16 BOOL
17 SystemSetLocalTime(LPSYSTEMTIME lpSystemTime)
18 {
19 HANDLE hToken;
20 DWORD PrevSize;
21 TOKEN_PRIVILEGES priv, previouspriv;
22 BOOL Ret = FALSE;
23
24 /*
25 * Enable the SeSystemtimePrivilege privilege
26 */
27
28 if (OpenProcessToken(GetCurrentProcess(),
29 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
30 &hToken))
31 {
32 priv.PrivilegeCount = 1;
33 priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
34
35 if (LookupPrivilegeValueW(NULL,
36 SE_SYSTEMTIME_NAME,
37 &priv.Privileges[0].Luid))
38 {
39 if (AdjustTokenPrivileges(hToken,
40 FALSE,
41 &priv,
42 sizeof(previouspriv),
43 &previouspriv,
44 &PrevSize) &&
45 GetLastError() == ERROR_SUCCESS)
46 {
47 /*
48 * We successfully enabled it, we're permitted to change the system time
49 * Call SetLocalTime twice to ensure correct results
50 */
51 Ret = SetLocalTime(lpSystemTime) &&
52 SetLocalTime(lpSystemTime);
53
54 /*
55 * For the sake of security, restore the previous status again
56 */
57 if (previouspriv.PrivilegeCount > 0)
58 {
59 AdjustTokenPrivileges(hToken,
60 FALSE,
61 &previouspriv,
62 0,
63 NULL,
64 0);
65 }
66 }
67 }
68 CloseHandle(hToken);
69 }
70
71 return Ret;
72 }
73
74
75 static VOID
76 SetLocalSystemTime(HWND hwnd)
77 {
78 SYSTEMTIME Time;
79
80 if (DateTime_GetSystemtime(GetDlgItem(hwnd,
81 IDC_TIMEPICKER),
82 &Time) == GDT_VALID &&
83 SendMessageW(GetDlgItem(hwnd,
84 IDC_MONTHCALENDAR),
85 MCCM_GETDATE,
86 (WPARAM)&Time,
87 0))
88 {
89 SystemSetLocalTime(&Time);
90
91 SetWindowLongPtrW(hwnd,
92 DWL_MSGRESULT,
93 PSNRET_NOERROR);
94
95 SendMessageW(GetDlgItem(hwnd,
96 IDC_MONTHCALENDAR),
97 MCCM_RESET,
98 (WPARAM)&Time,
99 0);
100
101 /* Broadcast the time change message */
102 SendMessageW(HWND_BROADCAST,
103 WM_TIMECHANGE,
104 0,
105 0);
106 }
107 }
108
109
110 static VOID
111 SetTimeZoneName(HWND hwnd)
112 {
113 TIME_ZONE_INFORMATION TimeZoneInfo;
114 WCHAR TimeZoneString[128];
115 WCHAR TimeZoneText[128];
116 WCHAR TimeZoneName[128];
117 DWORD TimeZoneId;
118
119 TimeZoneId = GetTimeZoneInformation(&TimeZoneInfo);
120
121 LoadStringW(hApplet, IDS_TIMEZONETEXT, TimeZoneText, 128);
122
123 switch (TimeZoneId)
124 {
125 case TIME_ZONE_ID_STANDARD:
126 wcscpy(TimeZoneName, TimeZoneInfo.StandardName);
127 break;
128
129 case TIME_ZONE_ID_DAYLIGHT:
130 wcscpy(TimeZoneName, TimeZoneInfo.DaylightName);
131 break;
132
133 case TIME_ZONE_ID_UNKNOWN:
134 LoadStringW(hApplet, IDS_TIMEZONEUNKNOWN, TimeZoneName, 128);
135 break;
136
137 case TIME_ZONE_ID_INVALID:
138 default:
139 LoadStringW(hApplet, IDS_TIMEZONEINVALID, TimeZoneName, 128);
140 break;
141 }
142
143 wsprintfW(TimeZoneString, TimeZoneText, TimeZoneName);
144 SendDlgItemMessageW(hwnd, IDC_TIMEZONE, WM_SETTEXT, 0, (LPARAM)TimeZoneString);
145 }
146
147
148 static VOID
149 FillMonthsComboBox(HWND hCombo)
150 {
151 SYSTEMTIME LocalDate = {0};
152 WCHAR szBuf[64];
153 INT i;
154 UINT Month;
155
156 GetLocalTime(&LocalDate);
157
158 SendMessageW(hCombo,
159 CB_RESETCONTENT,
160 0,
161 0);
162
163 for (Month = 1;
164 Month <= 13;
165 Month++)
166 {
167 i = GetLocaleInfoW(LOCALE_USER_DEFAULT,
168 ((Month < 13) ? LOCALE_SMONTHNAME1 + Month - 1 : LOCALE_SMONTHNAME13),
169 szBuf,
170 sizeof(szBuf) / sizeof(szBuf[0]));
171 if (i > 1)
172 {
173 i = (INT)SendMessageW(hCombo,
174 CB_ADDSTRING,
175 0,
176 (LPARAM)szBuf);
177 if (i != CB_ERR)
178 {
179 SendMessageW(hCombo,
180 CB_SETITEMDATA,
181 (WPARAM)i,
182 Month);
183
184 if (Month == (UINT)LocalDate.wMonth)
185 {
186 SendMessageW(hCombo,
187 CB_SETCURSEL,
188 (WPARAM)i,
189 0);
190 }
191 }
192 }
193 }
194 }
195
196
197 static WORD
198 GetCBSelectedMonth(HWND hCombo)
199 {
200 INT i;
201 WORD Ret = (WORD)-1;
202
203 i = (INT)SendMessageW(hCombo,
204 CB_GETCURSEL,
205 0,
206 0);
207 if (i != CB_ERR)
208 {
209 i = (INT)SendMessageW(hCombo,
210 CB_GETITEMDATA,
211 (WPARAM)i,
212 0);
213
214 if (i >= 1 && i <= 13)
215 Ret = (WORD)i;
216 }
217
218 return Ret;
219 }
220
221
222 static VOID
223 ChangeMonthCalDate(HWND hMonthCal,
224 WORD Day,
225 WORD Month,
226 WORD Year)
227 {
228 SendMessageW(hMonthCal,
229 MCCM_SETDATE,
230 MAKEWPARAM(Day,
231 Month),
232 MAKELPARAM(Year,
233 0));
234 }
235
236 static VOID
237 AutoUpdateMonthCal(HWND hwndDlg,
238 PNMMCCAUTOUPDATE lpAutoUpdate)
239 {
240 UNREFERENCED_PARAMETER(lpAutoUpdate);
241
242 /* update the controls */
243 FillMonthsComboBox(GetDlgItem(hwndDlg,
244 IDC_MONTHCB));
245 }
246
247
248 static INT_PTR CALLBACK
249 DTPProc(HWND hwnd,
250 UINT uMsg,
251 WPARAM wParam,
252 LPARAM lParam)
253 {
254 switch (uMsg)
255 {
256 case WM_KEYDOWN:
257 /* stop the timer when the user is about to change the time */
258 if ((wParam != VK_LEFT) & (wParam != VK_RIGHT))
259 KillTimer(GetParent(hwnd), ID_TIMER);
260 break;
261 }
262
263 return CallWindowProcW(pOldWndProc, hwnd, uMsg, wParam, lParam);
264 }
265
266 /* Property page dialog callback */
267 INT_PTR CALLBACK
268 DateTimePageProc(HWND hwndDlg,
269 UINT uMsg,
270 WPARAM wParam,
271 LPARAM lParam)
272 {
273 SYSTEMTIME st;
274 GetLocalTime(&st);
275
276 switch (uMsg)
277 {
278 case WM_INITDIALOG:
279 FillMonthsComboBox(GetDlgItem(hwndDlg,
280 IDC_MONTHCB));
281
282 SetTimer(hwndDlg, ID_TIMER, 1000, NULL);
283
284 /* set range and current year */
285 SendMessageW(GetDlgItem(hwndDlg, IDC_YEAR), UDM_SETRANGE, 0, MAKELONG ((short) 9999, (short) 1900));
286 SendMessageW(GetDlgItem(hwndDlg, IDC_YEAR), UDM_SETPOS, 0, MAKELONG( (short) st.wYear, 0));
287
288 pOldWndProc = (WNDPROC) SetWindowLongPtrW(GetDlgItem(hwndDlg, IDC_TIMEPICKER), GWL_WNDPROC, (INT_PTR) DTPProc);
289 break;
290
291 case WM_TIMER:
292 SendMessageW(GetDlgItem(hwndDlg, IDC_TIMEPICKER), DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM) &st);
293 break;
294
295 case WM_COMMAND:
296 switch (LOWORD(wParam))
297 {
298 case IDC_MONTHCB:
299 if (HIWORD(wParam) == CBN_SELCHANGE)
300 {
301 ChangeMonthCalDate(GetDlgItem(hwndDlg,
302 IDC_MONTHCALENDAR),
303 (WORD) -1,
304 GetCBSelectedMonth((HWND)lParam),
305 (WORD) -1);
306 }
307 break;
308 }
309 break;
310
311 case WM_CTLCOLORSTATIC:
312 if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_YEARTEXT))
313 return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
314 break;
315
316 case WM_NOTIFY:
317 {
318 LPNMHDR lpnm = (LPNMHDR)lParam;
319
320 switch (lpnm->idFrom)
321 {
322 case IDC_YEAR:
323 switch (lpnm->code)
324 {
325 case UDN_DELTAPOS:
326 {
327 SHORT wYear;
328 LPNMUPDOWN updown = (LPNMUPDOWN)lpnm;
329 wYear = (SHORT)SendMessageW(GetDlgItem(hwndDlg, IDC_YEAR), UDM_GETPOS, 0, 0);
330 /* Enable the 'Apply' button */
331 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
332 ChangeMonthCalDate(GetDlgItem(hwndDlg,
333 IDC_MONTHCALENDAR),
334 (WORD) -1,
335 (WORD) -1,
336 (WORD) (wYear + updown->iDelta));
337 }
338 break;
339 }
340 break;
341
342 case IDC_TIMEPICKER:
343 switch (lpnm->code)
344 {
345 case DTN_DATETIMECHANGE:
346 /* Stop the timer */
347 KillTimer(hwndDlg, ID_TIMER);
348
349 /* Tell the clock to stop ticking */
350 SendDlgItemMessageW(hwndDlg, IDC_CLOCKWND, CLM_STOPCLOCK,
351 0, 0);
352
353 /* Enable the 'Apply' button */
354 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
355 break;
356 }
357 break;
358
359 case IDC_MONTHCALENDAR:
360 switch (lpnm->code)
361 {
362 case MCCN_SELCHANGE:
363 /* Enable the 'Apply' button */
364 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
365 break;
366
367 case MCCN_AUTOUPDATE:
368 AutoUpdateMonthCal(hwndDlg,
369 (PNMMCCAUTOUPDATE)lpnm);
370 break;
371 }
372 break;
373
374 default:
375 switch (lpnm->code)
376 {
377 case PSN_SETACTIVE:
378 SetTimeZoneName(hwndDlg);
379 break;
380
381 case PSN_APPLY:
382 SetLocalSystemTime(hwndDlg);
383 SetTimer(hwndDlg, ID_TIMER, 1000, NULL);
384
385 /* Tell the clock to start ticking */
386 SendDlgItemMessageW(hwndDlg, IDC_CLOCKWND, CLM_STARTCLOCK,
387 0, 0);
388 return TRUE;
389 }
390 break;
391 }
392 }
393 break;
394
395 case WM_TIMECHANGE:
396 /* FIXME - we don't get this message as we're not a top-level window... */
397 SendMessageW(GetDlgItem(hwndDlg,
398 IDC_MONTHCALENDAR),
399 MCCM_RESET,
400 0,
401 0);
402 break;
403
404 case WM_DESTROY:
405 KillTimer(hwndDlg, ID_TIMER);
406 break;
407 }
408
409 return FALSE;
410 }