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