* Slap *some* sense into our header inclusions.
[reactos.git] / reactos / 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 case TIME_ZONE_ID_UNKNOWN:
127 wcscpy(TimeZoneName, TimeZoneInfo.StandardName);
128 break;
129
130 case TIME_ZONE_ID_DAYLIGHT:
131 wcscpy(TimeZoneName, TimeZoneInfo.DaylightName);
132 break;
133
134 case TIME_ZONE_ID_INVALID:
135 default:
136 LoadStringW(hApplet, IDS_TIMEZONEINVALID, TimeZoneName, 128);
137 break;
138 }
139
140 wsprintfW(TimeZoneString, TimeZoneText, TimeZoneName);
141 SendDlgItemMessageW(hwnd, IDC_TIMEZONE, WM_SETTEXT, 0, (LPARAM)TimeZoneString);
142 }
143
144
145 static VOID
146 FillMonthsComboBox(HWND hCombo)
147 {
148 SYSTEMTIME LocalDate = {0};
149 WCHAR szBuf[64];
150 INT i;
151 UINT Month;
152
153 GetLocalTime(&LocalDate);
154
155 SendMessageW(hCombo,
156 CB_RESETCONTENT,
157 0,
158 0);
159
160 for (Month = 1;
161 Month <= 13;
162 Month++)
163 {
164 i = GetLocaleInfoW(LOCALE_USER_DEFAULT,
165 ((Month < 13) ? LOCALE_SMONTHNAME1 + Month - 1 : LOCALE_SMONTHNAME13),
166 szBuf,
167 sizeof(szBuf) / sizeof(szBuf[0]));
168 if (i > 1)
169 {
170 i = (INT)SendMessageW(hCombo,
171 CB_ADDSTRING,
172 0,
173 (LPARAM)szBuf);
174 if (i != CB_ERR)
175 {
176 SendMessageW(hCombo,
177 CB_SETITEMDATA,
178 (WPARAM)i,
179 Month);
180
181 if (Month == (UINT)LocalDate.wMonth)
182 {
183 SendMessageW(hCombo,
184 CB_SETCURSEL,
185 (WPARAM)i,
186 0);
187 }
188 }
189 }
190 }
191 }
192
193
194 static WORD
195 GetCBSelectedMonth(HWND hCombo)
196 {
197 INT i;
198 WORD Ret = (WORD)-1;
199
200 i = (INT)SendMessageW(hCombo,
201 CB_GETCURSEL,
202 0,
203 0);
204 if (i != CB_ERR)
205 {
206 i = (INT)SendMessageW(hCombo,
207 CB_GETITEMDATA,
208 (WPARAM)i,
209 0);
210
211 if (i >= 1 && i <= 13)
212 Ret = (WORD)i;
213 }
214
215 return Ret;
216 }
217
218
219 static VOID
220 ChangeMonthCalDate(HWND hMonthCal,
221 WORD Day,
222 WORD Month,
223 WORD Year)
224 {
225 SendMessageW(hMonthCal,
226 MCCM_SETDATE,
227 MAKEWPARAM(Day,
228 Month),
229 MAKELPARAM(Year,
230 0));
231 }
232
233 static VOID
234 AutoUpdateMonthCal(HWND hwndDlg,
235 PNMMCCAUTOUPDATE lpAutoUpdate)
236 {
237 UNREFERENCED_PARAMETER(lpAutoUpdate);
238
239 /* Update the controls */
240 FillMonthsComboBox(GetDlgItem(hwndDlg,
241 IDC_MONTHCB));
242 }
243
244
245 static INT_PTR CALLBACK
246 DTPProc(HWND hwnd,
247 UINT uMsg,
248 WPARAM wParam,
249 LPARAM lParam)
250 {
251 switch (uMsg)
252 {
253 case WM_KEYDOWN:
254 /* Stop the timer when the user is about to change the time */
255 if ((wParam != VK_LEFT) & (wParam != VK_RIGHT))
256 KillTimer(GetParent(hwnd), ID_TIMER);
257 break;
258 }
259
260 return CallWindowProcW(pOldWndProc, hwnd, uMsg, wParam, lParam);
261 }
262
263 /* Property page dialog callback */
264 INT_PTR CALLBACK
265 DateTimePageProc(HWND hwndDlg,
266 UINT uMsg,
267 WPARAM wParam,
268 LPARAM lParam)
269 {
270 SYSTEMTIME st;
271 GetLocalTime(&st);
272
273 switch (uMsg)
274 {
275 case WM_INITDIALOG:
276 FillMonthsComboBox(GetDlgItem(hwndDlg,
277 IDC_MONTHCB));
278
279 SetTimer(hwndDlg, ID_TIMER, 1000, NULL);
280
281 /* Set range and current year */
282 SendMessageW(GetDlgItem(hwndDlg, IDC_YEAR), UDM_SETRANGE, 0, MAKELONG ((short) 9999, (short) 1900));
283 SendMessageW(GetDlgItem(hwndDlg, IDC_YEAR), UDM_SETPOS, 0, MAKELONG( (short) st.wYear, 0));
284
285 pOldWndProc = (WNDPROC) SetWindowLongPtrW(GetDlgItem(hwndDlg, IDC_TIMEPICKER), GWL_WNDPROC, (INT_PTR) DTPProc);
286 break;
287
288 case WM_TIMER:
289 SendMessageW(GetDlgItem(hwndDlg, IDC_TIMEPICKER), DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM) &st);
290 break;
291
292 case WM_COMMAND:
293 switch (LOWORD(wParam))
294 {
295 case IDC_MONTHCB:
296 if (HIWORD(wParam) == CBN_SELCHANGE)
297 {
298 ChangeMonthCalDate(GetDlgItem(hwndDlg,
299 IDC_MONTHCALENDAR),
300 (WORD) -1,
301 GetCBSelectedMonth((HWND)lParam),
302 (WORD) -1);
303 }
304 break;
305 }
306 break;
307
308 case WM_CTLCOLORSTATIC:
309 if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_YEARTEXT))
310 return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
311 break;
312
313 case WM_NOTIFY:
314 {
315 LPNMHDR lpnm = (LPNMHDR)lParam;
316
317 switch (lpnm->idFrom)
318 {
319 case IDC_YEAR:
320 switch (lpnm->code)
321 {
322 case UDN_DELTAPOS:
323 {
324 SHORT wYear;
325 LPNMUPDOWN updown = (LPNMUPDOWN)lpnm;
326 wYear = (SHORT)SendMessageW(GetDlgItem(hwndDlg, IDC_YEAR), UDM_GETPOS, 0, 0);
327 /* Enable the 'Apply' button */
328 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
329 ChangeMonthCalDate(GetDlgItem(hwndDlg,
330 IDC_MONTHCALENDAR),
331 (WORD) -1,
332 (WORD) -1,
333 (WORD) (wYear + updown->iDelta));
334 }
335 break;
336 }
337 break;
338
339 case IDC_TIMEPICKER:
340 switch (lpnm->code)
341 {
342 case DTN_DATETIMECHANGE:
343 /* Stop the timer */
344 KillTimer(hwndDlg, ID_TIMER);
345
346 /* Tell the clock to stop ticking */
347 SendDlgItemMessageW(hwndDlg, IDC_CLOCKWND, CLM_STOPCLOCK,
348 0, 0);
349
350 /* Enable the 'Apply' button */
351 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
352 break;
353 }
354 break;
355
356 case IDC_MONTHCALENDAR:
357 switch (lpnm->code)
358 {
359 case MCCN_SELCHANGE:
360 /* Enable the 'Apply' button */
361 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
362 break;
363
364 case MCCN_AUTOUPDATE:
365 AutoUpdateMonthCal(hwndDlg,
366 (PNMMCCAUTOUPDATE)lpnm);
367 break;
368 }
369 break;
370
371 default:
372 switch (lpnm->code)
373 {
374 case PSN_SETACTIVE:
375 SetTimeZoneName(hwndDlg);
376 break;
377
378 case PSN_APPLY:
379 SetLocalSystemTime(hwndDlg);
380 SetTimer(hwndDlg, ID_TIMER, 1000, NULL);
381
382 /* Tell the clock to start ticking */
383 SendDlgItemMessageW(hwndDlg, IDC_CLOCKWND, CLM_STARTCLOCK,
384 0, 0);
385 return TRUE;
386 }
387 break;
388 }
389 }
390 break;
391
392 case WM_TIMECHANGE:
393 /* FIXME: We don't get this message as we're not a top-level window... */
394 SendMessageW(GetDlgItem(hwndDlg,
395 IDC_MONTHCALENDAR),
396 MCCM_RESET,
397 0,
398 0);
399 break;
400
401 case WM_DESTROY:
402 KillTimer(hwndDlg, ID_TIMER);
403 break;
404 }
405
406 return FALSE;
407 }