[DESK]
[reactos.git] / reactos / dll / cpl / desk / screensaver.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Display Control Panel
4 * FILE: dll/cpl/desk/screensaver.c
5 * PURPOSE: Screen saver property page
6 *
7 * PROGRAMMERS: Trevor McCort (lycan359@gmail.com)
8 * Ged Murphy (gedmurphy@reactos.org)
9 */
10
11 #include "desk.h"
12
13 #define MAX_SCREENSAVERS 100
14
15 typedef struct
16 {
17 BOOL bIsScreenSaver; /* Is this background a wallpaper */
18 TCHAR szFilename[MAX_PATH];
19 TCHAR szDisplayName[256];
20 } ScreenSaverItem;
21
22
23 typedef struct _GLOBAL_DATA
24 {
25 ScreenSaverItem ScreenSaverItems[MAX_SCREENSAVERS];
26 PROCESS_INFORMATION PrevWindowPi;
27 int Selection;
28 } GLOBAL_DATA, *PGLOBAL_DATA;
29
30
31 static LPTSTR
32 GetCurrentScreenSaverValue(LPTSTR lpValue)
33 {
34 HKEY hKey;
35 LPTSTR lpBuf = NULL;
36 DWORD BufSize, Type = REG_SZ;
37 LONG Ret;
38
39 Ret = RegOpenKeyEx(HKEY_CURRENT_USER,
40 _T("Control Panel\\Desktop"),
41 0,
42 KEY_READ,
43 &hKey);
44 if (Ret != ERROR_SUCCESS)
45 return NULL;
46
47 Ret = RegQueryValueEx(hKey,
48 lpValue,
49 0,
50 &Type,
51 NULL,
52 &BufSize);
53 if (Ret == ERROR_SUCCESS)
54 {
55 lpBuf = HeapAlloc(GetProcessHeap(),
56 0,
57 BufSize);
58 if (lpBuf)
59 {
60 Ret = RegQueryValueEx(hKey,
61 lpValue,
62 0,
63 &Type,
64 (LPBYTE)lpBuf,
65 &BufSize);
66 if (Ret != ERROR_SUCCESS)
67 lpBuf = NULL;
68 }
69 }
70
71 RegCloseKey(hKey);
72
73 return lpBuf;
74 }
75
76
77 static VOID
78 SelectionChanged(HWND hwndDlg, PGLOBAL_DATA pGlobalData)
79 {
80 HWND hwndCombo;
81 BOOL bEnable;
82 INT i;
83
84 hwndCombo = GetDlgItem(hwndDlg, IDC_SCREENS_LIST);
85
86 i = (INT)SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
87 i = (INT)SendMessage(hwndCombo, CB_GETITEMDATA, i, 0);
88
89 pGlobalData->Selection = i;
90
91 bEnable = (i != 0);
92
93 EnableWindow(GetDlgItem(hwndDlg, IDC_SCREENS_SETTINGS), bEnable);
94 EnableWindow(GetDlgItem(hwndDlg, IDC_SCREENS_TESTSC), bEnable);
95 EnableWindow(GetDlgItem(hwndDlg, IDC_SCREENS_USEPASSCHK), bEnable);
96 EnableWindow(GetDlgItem(hwndDlg, IDC_SCREENS_TIMEDELAY), bEnable);
97 EnableWindow(GetDlgItem(hwndDlg, IDC_SCREENS_TIME), bEnable);
98 EnableWindow(GetDlgItem(hwndDlg, IDC_WAITTEXT), bEnable);
99 EnableWindow(GetDlgItem(hwndDlg, IDC_MINTEXT), bEnable);
100 }
101
102
103 static VOID
104 SetScreenSaverPreviewBox(HWND hwndDlg, PGLOBAL_DATA pGlobalData)
105 {
106 HWND hPreview = GetDlgItem(hwndDlg, IDC_SCREENS_PREVIEW);
107 STARTUPINFO si;
108 TCHAR szCmdline[2048];
109
110 /* kill off the previous preview process*/
111 if (pGlobalData->PrevWindowPi.hProcess)
112 {
113 TerminateProcess(pGlobalData->PrevWindowPi.hProcess, 0);
114 CloseHandle(pGlobalData->PrevWindowPi.hProcess);
115 CloseHandle(pGlobalData->PrevWindowPi.hThread);
116 pGlobalData->PrevWindowPi.hThread = pGlobalData->PrevWindowPi.hProcess = NULL;
117 }
118
119 if (pGlobalData->Selection > 0)
120 {
121 _stprintf(szCmdline,
122 _T("%s /p %u"),
123 pGlobalData->ScreenSaverItems[pGlobalData->Selection].szFilename,
124 hPreview);
125
126 ZeroMemory(&si, sizeof(si));
127 si.cb = sizeof(si);
128 ZeroMemory(&pGlobalData->PrevWindowPi, sizeof(pGlobalData->PrevWindowPi));
129
130 if (!CreateProcess(NULL,
131 szCmdline,
132 NULL,
133 NULL,
134 FALSE,
135 0,
136 NULL,
137 NULL,
138 &si,
139 &pGlobalData->PrevWindowPi))
140 {
141 pGlobalData->PrevWindowPi.hThread = pGlobalData->PrevWindowPi.hProcess = NULL;
142 }
143 }
144 }
145
146 static BOOL
147 WaitForSettingsDialog(HWND hwndDlg,
148 HANDLE hProcess)
149 {
150 DWORD dwResult;
151 MSG msg;
152
153 while (TRUE)
154 {
155 dwResult = MsgWaitForMultipleObjects(1,
156 &hProcess,
157 FALSE,
158 INFINITE,
159 QS_ALLINPUT);
160 if (dwResult == WAIT_OBJECT_0 + 1)
161 {
162 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
163 {
164 if (msg.message == WM_QUIT)
165 {
166 return FALSE;
167 }
168 if (IsDialogMessage(hwndDlg, &msg))
169 {
170 TranslateMessage(&msg);
171 DispatchMessage(&msg);
172 }
173 }
174 }
175 else
176 {
177 return TRUE;
178 }
179 }
180 }
181
182
183 static VOID
184 ScreensaverConfig(HWND hwndDlg, PGLOBAL_DATA pGlobalData)
185 {
186 /*
187 /c:<hwnd> Run configuration, hwnd is handle of calling window
188 */
189
190 TCHAR szCmdline[2048];
191 STARTUPINFO si;
192 PROCESS_INFORMATION pi;
193
194 if (pGlobalData->Selection < 1)
195 return;
196
197 _stprintf(szCmdline,
198 _T("%s /c:%u"),
199 pGlobalData->ScreenSaverItems[pGlobalData->Selection].szFilename,
200 hwndDlg);
201
202 ZeroMemory(&si, sizeof(si));
203 si.cb = sizeof(si);
204 ZeroMemory(&pi, sizeof(pi));
205 if(CreateProcess(NULL,
206 szCmdline,
207 NULL,
208 NULL,
209 FALSE,
210 0,
211 NULL,
212 NULL,
213 &si,
214 &pi))
215 {
216 /* kill off the previous preview process */
217 if (pGlobalData->PrevWindowPi.hProcess)
218 {
219 TerminateProcess(pGlobalData->PrevWindowPi.hProcess, 0);
220 CloseHandle(pGlobalData->PrevWindowPi.hProcess);
221 CloseHandle(pGlobalData->PrevWindowPi.hThread);
222 pGlobalData->PrevWindowPi.hThread = pGlobalData->PrevWindowPi.hProcess = NULL;
223 }
224
225 if (WaitForSettingsDialog(hwndDlg, pi.hProcess))
226 SetScreenSaverPreviewBox(hwndDlg, pGlobalData);
227 }
228 }
229
230
231 static VOID
232 ScreensaverPreview(HWND hwndDlg, PGLOBAL_DATA pGlobalData)
233 {
234 /*
235 /s Run normal
236 */
237
238 WCHAR szCmdline[2048];
239 STARTUPINFO si;
240 PROCESS_INFORMATION pi;
241
242 if (pGlobalData->Selection < 1)
243 return;
244
245 /* kill off the previous preview process*/
246 if (pGlobalData->PrevWindowPi.hProcess)
247 {
248 TerminateProcess(pGlobalData->PrevWindowPi.hProcess, 0);
249 CloseHandle(pGlobalData->PrevWindowPi.hProcess);
250 CloseHandle(pGlobalData->PrevWindowPi.hThread);
251 pGlobalData->PrevWindowPi.hThread = pGlobalData->PrevWindowPi.hProcess = NULL;
252 }
253
254 _stprintf(szCmdline,
255 _T("%s /s"),
256 pGlobalData->ScreenSaverItems[pGlobalData->Selection].szFilename);
257
258 ZeroMemory(&si, sizeof(si));
259 si.cb = sizeof(si);
260 ZeroMemory(&pi, sizeof(pi));
261 if(CreateProcess(NULL,
262 szCmdline,
263 NULL,
264 NULL,
265 FALSE,
266 0,
267 NULL,
268 NULL,
269 &si,
270 &pi))
271 {
272 WaitForSingleObject(pi.hProcess, INFINITE);
273 CloseHandle(pi.hProcess);
274 CloseHandle(pi.hThread);
275 }
276 }
277
278
279 static VOID
280 CheckRegScreenSaverIsSecure(HWND hwndDlg)
281 {
282 HKEY hKey;
283 TCHAR szBuffer[2];
284 DWORD bufferSize = sizeof(szBuffer);
285 DWORD varType = REG_SZ;
286 LONG result;
287
288 if (RegOpenKeyEx(HKEY_CURRENT_USER,
289 _T("Control Panel\\Desktop"),
290 0,
291 KEY_ALL_ACCESS,
292 &hKey) == ERROR_SUCCESS)
293 {
294 result = RegQueryValueEx(hKey,
295 _T("ScreenSaverIsSecure"),
296 0,
297 &varType,
298 (LPBYTE)szBuffer,
299 &bufferSize);
300 RegCloseKey(hKey);
301
302 if (result == ERROR_SUCCESS)
303 {
304 if (_ttoi(szBuffer) == 1)
305 {
306 SendDlgItemMessage(hwndDlg,
307 IDC_SCREENS_USEPASSCHK,
308 BM_SETCHECK,
309 (WPARAM)BST_CHECKED,
310 0);
311 return;
312 }
313 }
314
315 SendDlgItemMessage(hwndDlg,
316 IDC_SCREENS_USEPASSCHK,
317 BM_SETCHECK,
318 (WPARAM)BST_UNCHECKED,
319 0);
320 }
321 }
322
323
324 static VOID
325 AddScreenSavers(HWND hwndDlg, PGLOBAL_DATA pGlobalData)
326 {
327 HWND hwndScreenSavers = GetDlgItem(hwndDlg, IDC_SCREENS_LIST);
328 WIN32_FIND_DATA fd;
329 HANDLE hFind;
330 TCHAR szSearchPath[MAX_PATH];
331 INT i;
332 int ScreenSaverCount = 0;
333 ScreenSaverItem *ScreenSaverItem = NULL;
334 HANDLE hModule = NULL;
335
336 /* Add the "None" item */
337 ScreenSaverItem = &pGlobalData->ScreenSaverItems[ScreenSaverCount];
338
339 ScreenSaverItem->bIsScreenSaver = FALSE;
340
341 LoadString(hApplet,
342 IDS_NONE,
343 ScreenSaverItem->szDisplayName,
344 sizeof(ScreenSaverItem->szDisplayName) / sizeof(TCHAR));
345
346 i = SendMessage(hwndScreenSavers,
347 CB_ADDSTRING,
348 0,
349 (LPARAM)ScreenSaverItem->szDisplayName);
350
351 SendMessage(hwndScreenSavers,
352 CB_SETITEMDATA,
353 i,
354 (LPARAM)ScreenSaverCount);
355
356 ScreenSaverCount++;
357
358 /* Add all the screensavers in the C:\ReactOS\System32 directory. */
359
360 GetSystemDirectory(szSearchPath, MAX_PATH);
361 _tcscat(szSearchPath, TEXT("\\*.scr"));
362
363 hFind = FindFirstFile(szSearchPath, &fd);
364 while (ScreenSaverCount < MAX_SCREENSAVERS-1 &&
365 hFind != INVALID_HANDLE_VALUE)
366 {
367 /* Don't add any hidden screensavers */
368 if ((fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == 0)
369 {
370 TCHAR filename[MAX_PATH];
371
372 GetSystemDirectory(filename, MAX_PATH);
373
374 _tcscat(filename, TEXT("\\"));
375 _tcscat(filename, fd.cFileName);
376
377 ScreenSaverItem = &pGlobalData->ScreenSaverItems[ScreenSaverCount];
378
379 ScreenSaverItem->bIsScreenSaver = TRUE;
380
381 hModule = LoadLibraryEx(filename,
382 NULL,
383 DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
384 if (hModule)
385 {
386 LoadString(hModule,
387 1,
388 ScreenSaverItem->szDisplayName,
389 sizeof(ScreenSaverItem->szDisplayName) / sizeof(TCHAR));
390 FreeLibrary(hModule);
391 }
392 else
393 {
394 _tcscpy(ScreenSaverItem->szDisplayName, _T("Unknown"));
395 }
396
397 _tcscpy(ScreenSaverItem->szFilename, filename);
398
399 i = SendMessage(hwndScreenSavers,
400 CB_ADDSTRING,
401 0,
402 (LPARAM)ScreenSaverItem->szDisplayName);
403
404 SendMessage(hwndScreenSavers,
405 CB_SETITEMDATA,
406 i,
407 (LPARAM)ScreenSaverCount);
408
409 ScreenSaverCount++;
410 }
411
412 if (!FindNextFile(hFind, &fd))
413 hFind = INVALID_HANDLE_VALUE;
414 }
415 }
416
417
418 static VOID
419 SetScreenSaver(HWND hwndDlg, PGLOBAL_DATA pGlobalData)
420 {
421 HKEY regKey;
422
423 if (RegOpenKeyEx(HKEY_CURRENT_USER,
424 _T("Control Panel\\Desktop"),
425 0,
426 KEY_ALL_ACCESS,
427 &regKey) == ERROR_SUCCESS)
428 {
429 INT Time;
430 BOOL bRet;
431 TCHAR szTime[256], Sec;
432 UINT Ret;
433
434 /* set the screensaver */
435 if (pGlobalData->ScreenSaverItems[pGlobalData->Selection].bIsScreenSaver)
436 {
437 RegSetValueEx(regKey,
438 _T("SCRNSAVE.EXE"),
439 0,
440 REG_SZ,
441 (PBYTE)pGlobalData->ScreenSaverItems[pGlobalData->Selection].szFilename,
442 _tcslen(pGlobalData->ScreenSaverItems[pGlobalData->Selection].szFilename) * sizeof(TCHAR));
443 }
444 else
445 {
446 /* Windows deletes the value if no screensaver is set */
447 RegDeleteValue(regKey, _T("SCRNSAVE.EXE"));
448 }
449
450 /* set the screensaver time delay */
451 Time = GetDlgItemInt(hwndDlg,
452 IDC_SCREENS_TIMEDELAY,
453 &bRet,
454 FALSE);
455 if (Time == 0)
456 Time = 60;
457 else
458 Time *= 60;
459
460 _itot(Time, szTime, 10);
461 RegSetValueEx(regKey,
462 _T("ScreenSaveTimeOut"),
463 0,
464 REG_SZ,
465 (PBYTE)szTime,
466 _tcslen(szTime) * sizeof(TCHAR));
467
468 /* set the secure value */
469 Ret = SendDlgItemMessage(hwndDlg,
470 IDC_SCREENS_USEPASSCHK,
471 BM_GETCHECK,
472 0,
473 0);
474 Sec = (Ret == BST_CHECKED) ? _T('1') : _T('0');
475 RegSetValueEx(regKey,
476 _T("ScreenSaverIsSecure"),
477 0,
478 REG_SZ,
479 (PBYTE)&Sec,
480 sizeof(TCHAR));
481
482 RegCloseKey(regKey);
483 }
484 }
485
486
487 static BOOL
488 OnInitDialog(HWND hwndDlg, PGLOBAL_DATA pGlobalData)
489 {
490 LPTSTR lpCurSs;
491 HWND hwndSSCombo = GetDlgItem(hwndDlg, IDC_SCREENS_LIST);
492 INT Num;
493
494 pGlobalData = HeapAlloc(GetProcessHeap(),
495 HEAP_ZERO_MEMORY,
496 sizeof(GLOBAL_DATA));
497 if (!pGlobalData)
498 {
499 EndDialog(hwndDlg, -1);
500 return FALSE;
501 }
502
503 SetWindowLongPtr(hwndDlg,
504 DWLP_USER,
505 (LONG_PTR)pGlobalData);
506
507 pGlobalData->Selection = -1;
508
509 SendDlgItemMessage(hwndDlg,
510 IDC_SCREENS_TIME,
511 UDM_SETRANGE,
512 0,
513 MAKELONG
514 ((short) 240, (short) 1));
515
516 AddScreenSavers(hwndDlg,
517 pGlobalData);
518
519 CheckRegScreenSaverIsSecure(hwndDlg);
520
521 /* set the current screensaver in the combo box */
522 lpCurSs = GetCurrentScreenSaverValue(_T("SCRNSAVE.EXE"));
523 if (lpCurSs)
524 {
525 BOOL bFound = FALSE;
526 INT i;
527
528 for (i = 0; i < MAX_SCREENSAVERS; i++)
529 {
530 if (!_tcscmp(lpCurSs, pGlobalData->ScreenSaverItems[i].szFilename))
531 {
532 bFound = TRUE;
533 break;
534 }
535 }
536
537 if (bFound)
538 {
539 Num = SendMessage(hwndSSCombo,
540 CB_FINDSTRINGEXACT,
541 -1,
542 (LPARAM)pGlobalData->ScreenSaverItems[i].szDisplayName);
543 if (Num != CB_ERR)
544 SendMessage(hwndSSCombo,
545 CB_SETCURSEL,
546 Num,
547 0);
548 }
549 else
550 {
551 SendMessage(hwndSSCombo,
552 CB_SETCURSEL,
553 0,
554 0);
555 }
556
557 HeapFree(GetProcessHeap(),
558 0,
559 lpCurSs);
560 }
561 else
562 {
563 /* set screensaver to (none) */
564 SendMessage(hwndSSCombo,
565 CB_SETCURSEL,
566 0,
567 0);
568 }
569
570 /* set the current timeout */
571 lpCurSs = GetCurrentScreenSaverValue(_T("ScreenSaveTimeOut"));
572 if (lpCurSs)
573 {
574 UINT Time = _ttoi(lpCurSs);
575
576 Time /= 60;
577
578 SendDlgItemMessage(hwndDlg,
579 IDC_SCREENS_TIME,
580 UDM_SETPOS32,
581 0,
582 Time);
583
584 HeapFree(GetProcessHeap(),
585 0,
586 lpCurSs);
587
588 }
589
590 SelectionChanged(hwndDlg,
591 pGlobalData);
592
593 return TRUE;
594 }
595
596
597 INT_PTR CALLBACK
598 ScreenSaverPageProc(HWND hwndDlg,
599 UINT uMsg,
600 WPARAM wParam,
601 LPARAM lParam)
602 {
603 PGLOBAL_DATA pGlobalData;
604
605 pGlobalData = (PGLOBAL_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
606
607 switch (uMsg)
608 {
609 case WM_INITDIALOG:
610 {
611 OnInitDialog(hwndDlg, pGlobalData);
612 break;
613 }
614
615 case WM_DESTROY:
616 {
617 if (pGlobalData->PrevWindowPi.hProcess)
618 {
619 TerminateProcess(pGlobalData->PrevWindowPi.hProcess, 0);
620 CloseHandle(pGlobalData->PrevWindowPi.hProcess);
621 CloseHandle(pGlobalData->PrevWindowPi.hThread);
622 }
623 HeapFree(GetProcessHeap(),
624 0,
625 pGlobalData);
626 break;
627 }
628
629 case WM_ENDSESSION:
630 {
631 SetScreenSaverPreviewBox(hwndDlg,
632 pGlobalData);
633 break;
634 }
635
636 case WM_COMMAND:
637 {
638 DWORD controlId = LOWORD(wParam);
639 DWORD command = HIWORD(wParam);
640
641 switch (controlId)
642 {
643 case IDC_SCREENS_LIST:
644 {
645 if (HIWORD(wParam) == CBN_SELCHANGE)
646 {
647 SelectionChanged(hwndDlg, pGlobalData);
648 SetScreenSaverPreviewBox(hwndDlg, pGlobalData);
649 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
650 }
651 break;
652 }
653
654 case IDC_SCREENS_TIMEDELAY:
655 {
656 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
657 break;
658 }
659
660 case IDC_SCREENS_POWER_BUTTON: // Start Powercfg.Cpl
661 {
662 if (command == BN_CLICKED)
663 WinExec("rundll32 shell32.dll,Control_RunDLL powercfg.cpl",SW_SHOWNORMAL);
664 break;
665 }
666
667 case IDC_SCREENS_TESTSC: // Screensaver Preview
668 {
669 if(command == BN_CLICKED)
670 {
671 ScreensaverPreview(hwndDlg, pGlobalData);
672 SetScreenSaverPreviewBox(hwndDlg, pGlobalData);
673 }
674 break;
675 }
676
677 case IDC_SCREENS_SETTINGS: // Screensaver Settings
678 {
679 if (command == BN_CLICKED)
680 ScreensaverConfig(hwndDlg, pGlobalData);
681 break;
682 }
683
684 case IDC_SCREENS_USEPASSCHK: // Screensaver Is Secure
685 {
686 if (command == BN_CLICKED)
687 {
688 MessageBox(NULL, TEXT("Feature not yet implemented"), TEXT("Sorry"), MB_OK);
689 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
690 }
691 break;
692 }
693 }
694 break;
695 }
696
697 case WM_NOTIFY:
698 {
699 LPNMHDR lpnm = (LPNMHDR)lParam;
700
701 switch(lpnm->code)
702 {
703 case PSN_APPLY:
704 {
705 SetScreenSaver(hwndDlg, pGlobalData);
706 return TRUE;
707 }
708
709 case PSN_SETACTIVE:
710 {
711 /* activate screen saver support */
712 SystemParametersInfoW(SPI_SETSCREENSAVEACTIVE, TRUE, 0, SPIF_SENDCHANGE);
713 SetScreenSaverPreviewBox(hwndDlg, pGlobalData);
714 break;
715 }
716
717 case PSN_KILLACTIVE:
718 {
719 /* Disable screensaver support */
720 SystemParametersInfoW(SPI_SETSCREENSAVEACTIVE, FALSE, 0, SPIF_SENDCHANGE);
721 if (pGlobalData->PrevWindowPi.hProcess)
722 {
723 TerminateProcess(pGlobalData->PrevWindowPi.hProcess, 0);
724 CloseHandle(pGlobalData->PrevWindowPi.hProcess);
725 CloseHandle(pGlobalData->PrevWindowPi.hThread);
726 pGlobalData->PrevWindowPi.hThread = pGlobalData->PrevWindowPi.hProcess = NULL;
727 }
728 break;
729 }
730 }
731 }
732 break;
733 }
734
735 return FALSE;
736 }