[WINE]
[reactos.git] / 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 INT i;
414 ScreenSaverItem *ScreenSaverItem = NULL;
415 LPTSTR lpBackSlash;
416
417 /* Add the "None" item */
418 ScreenSaverItem = pData->ScreenSaverItems;
419
420 ScreenSaverItem->bIsScreenSaver = FALSE;
421
422 LoadString(hApplet,
423 IDS_NONE,
424 ScreenSaverItem->szDisplayName,
425 sizeof(ScreenSaverItem->szDisplayName) / sizeof(TCHAR));
426
427 i = SendMessage(hwndScreenSavers,
428 CB_ADDSTRING,
429 0,
430 (LPARAM)ScreenSaverItem->szDisplayName);
431
432 SendMessage(hwndScreenSavers,
433 CB_SETITEMDATA,
434 i,
435 (LPARAM)0);
436
437 // Initialize number of items into the list
438 pData->ScreenSaverCount = 1;
439
440 // Add all the screensavers in the C:\ReactOS\System32 directory.
441 GetSystemDirectory(szSearchPath, MAX_PATH);
442 SearchScreenSavers(hwndScreenSavers, szSearchPath, pData);
443
444 // Add all the screensavers in the C:\ReactOS directory.
445 GetWindowsDirectory(szSearchPath, MAX_PATH);
446 SearchScreenSavers(hwndScreenSavers, szSearchPath, pData);
447
448 // Add all the screensavers where the applet is stored.
449 GetModuleFileName(hApplet, szSearchPath, MAX_PATH);
450 lpBackSlash = _tcsrchr(szSearchPath, _T('\\'));
451 if (lpBackSlash != NULL)
452 {
453 lpBackSlash = '\0';
454 SearchScreenSavers(hwndScreenSavers, szSearchPath, pData);
455 }
456 }
457
458
459 static VOID
460 SetScreenSaver(HWND hwndDlg, PDATA pData)
461 {
462 HKEY regKey;
463
464 if (RegOpenKeyEx(HKEY_CURRENT_USER,
465 _T("Control Panel\\Desktop"),
466 0,
467 KEY_ALL_ACCESS,
468 &regKey) == ERROR_SUCCESS)
469 {
470 INT Time;
471 BOOL bRet;
472 TCHAR szTime[256], Sec;
473 UINT Ret;
474
475 /* set the screensaver */
476 if (pData->ScreenSaverItems[pData->Selection].bIsScreenSaver)
477 {
478 RegSetValueEx(regKey,
479 _T("SCRNSAVE.EXE"),
480 0,
481 REG_SZ,
482 (PBYTE)pData->ScreenSaverItems[pData->Selection].szFilename,
483 _tcslen(pData->ScreenSaverItems[pData->Selection].szFilename) * sizeof(TCHAR));
484 }
485 else
486 {
487 /* Windows deletes the value if no screensaver is set */
488 RegDeleteValue(regKey, _T("SCRNSAVE.EXE"));
489 }
490
491 /* set the screensaver time delay */
492 Time = GetDlgItemInt(hwndDlg,
493 IDC_SCREENS_TIMEDELAY,
494 &bRet,
495 FALSE);
496 if (Time == 0)
497 Time = 60;
498 else
499 Time *= 60;
500
501 _itot(Time, szTime, 10);
502 RegSetValueEx(regKey,
503 _T("ScreenSaveTimeOut"),
504 0,
505 REG_SZ,
506 (PBYTE)szTime,
507 _tcslen(szTime) * sizeof(TCHAR));
508
509 /* set the secure value */
510 Ret = SendDlgItemMessage(hwndDlg,
511 IDC_SCREENS_USEPASSCHK,
512 BM_GETCHECK,
513 0,
514 0);
515 Sec = (Ret == BST_CHECKED) ? _T('1') : _T('0');
516 RegSetValueEx(regKey,
517 _T("ScreenSaverIsSecure"),
518 0,
519 REG_SZ,
520 (PBYTE)&Sec,
521 sizeof(TCHAR));
522
523 RegCloseKey(regKey);
524 }
525 }
526
527
528 static BOOL
529 OnInitDialog(HWND hwndDlg, PDATA pData)
530 {
531 LPTSTR lpCurSs;
532 HWND hwndSSCombo = GetDlgItem(hwndDlg, IDC_SCREENS_LIST);
533 INT Num;
534
535 pData = HeapAlloc(GetProcessHeap(),
536 HEAP_ZERO_MEMORY,
537 sizeof(DATA));
538 if (!pData)
539 {
540 EndDialog(hwndDlg, -1);
541 return FALSE;
542 }
543
544 SetWindowLongPtr(hwndDlg,
545 DWLP_USER,
546 (LONG_PTR)pData);
547
548 pData->Selection = -1;
549
550 SendDlgItemMessage(hwndDlg,
551 IDC_SCREENS_TIME,
552 UDM_SETRANGE,
553 0,
554 MAKELONG
555 ((short) 240, (short) 1));
556
557 AddScreenSavers(hwndDlg,
558 pData);
559
560 CheckRegScreenSaverIsSecure(hwndDlg);
561
562 /* set the current screensaver in the combo box */
563 lpCurSs = GetCurrentScreenSaverValue(_T("SCRNSAVE.EXE"));
564 if (lpCurSs)
565 {
566 BOOL bFound = FALSE;
567 INT i;
568
569 for (i = 0; i < MAX_SCREENSAVERS; i++)
570 {
571 if (!_tcscmp(lpCurSs, pData->ScreenSaverItems[i].szFilename))
572 {
573 bFound = TRUE;
574 break;
575 }
576 }
577
578 if (bFound)
579 {
580 Num = SendMessage(hwndSSCombo,
581 CB_FINDSTRINGEXACT,
582 -1,
583 (LPARAM)pData->ScreenSaverItems[i].szDisplayName);
584 if (Num != CB_ERR)
585 SendMessage(hwndSSCombo,
586 CB_SETCURSEL,
587 Num,
588 0);
589 }
590 else
591 {
592 SendMessage(hwndSSCombo,
593 CB_SETCURSEL,
594 0,
595 0);
596 }
597
598 HeapFree(GetProcessHeap(),
599 0,
600 lpCurSs);
601 }
602 else
603 {
604 /* set screensaver to (none) */
605 SendMessage(hwndSSCombo,
606 CB_SETCURSEL,
607 0,
608 0);
609 }
610
611 /* set the current timeout */
612 lpCurSs = GetCurrentScreenSaverValue(_T("ScreenSaveTimeOut"));
613 if (lpCurSs)
614 {
615 UINT Time = _ttoi(lpCurSs);
616
617 Time /= 60;
618
619 SendDlgItemMessage(hwndDlg,
620 IDC_SCREENS_TIME,
621 UDM_SETPOS32,
622 0,
623 Time);
624
625 HeapFree(GetProcessHeap(),
626 0,
627 lpCurSs);
628
629 }
630
631 SelectionChanged(hwndDlg,
632 pData);
633
634 return TRUE;
635 }
636
637
638 INT_PTR CALLBACK
639 ScreenSaverPageProc(HWND hwndDlg,
640 UINT uMsg,
641 WPARAM wParam,
642 LPARAM lParam)
643 {
644 PDATA pData;
645
646 pData = (PDATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
647
648 switch (uMsg)
649 {
650 case WM_INITDIALOG:
651 {
652 OnInitDialog(hwndDlg, pData);
653 break;
654 }
655
656 case WM_DESTROY:
657 {
658 if (pData->PrevWindowPi.hProcess)
659 {
660 TerminateProcess(pData->PrevWindowPi.hProcess, 0);
661 CloseHandle(pData->PrevWindowPi.hProcess);
662 CloseHandle(pData->PrevWindowPi.hThread);
663 }
664 HeapFree(GetProcessHeap(),
665 0,
666 pData);
667 break;
668 }
669
670 case WM_ENDSESSION:
671 {
672 SetScreenSaverPreviewBox(hwndDlg,
673 pData);
674 break;
675 }
676
677 case WM_COMMAND:
678 {
679 DWORD controlId = LOWORD(wParam);
680 DWORD command = HIWORD(wParam);
681
682 switch (controlId)
683 {
684 case IDC_SCREENS_LIST:
685 {
686 if (HIWORD(wParam) == CBN_SELCHANGE)
687 {
688 SelectionChanged(hwndDlg, pData);
689 SetScreenSaverPreviewBox(hwndDlg, pData);
690 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
691 }
692 break;
693 }
694
695 case IDC_SCREENS_TIMEDELAY:
696 {
697 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
698 break;
699 }
700
701 case IDC_SCREENS_POWER_BUTTON: // Start Powercfg.Cpl
702 {
703 if (command == BN_CLICKED)
704 WinExec("rundll32 shell32.dll,Control_RunDLL powercfg.cpl",SW_SHOWNORMAL);
705 break;
706 }
707
708 case IDC_SCREENS_TESTSC: // Screensaver Preview
709 {
710 if(command == BN_CLICKED)
711 {
712 ScreensaverPreview(hwndDlg, pData);
713 SetScreenSaverPreviewBox(hwndDlg, pData);
714 }
715 break;
716 }
717
718 case IDC_SCREENS_SETTINGS: // Screensaver Settings
719 {
720 if (command == BN_CLICKED)
721 ScreensaverConfig(hwndDlg, pData);
722 break;
723 }
724
725 case IDC_SCREENS_USEPASSCHK: // Screensaver Is Secure
726 {
727 if (command == BN_CLICKED)
728 {
729 MessageBox(NULL, TEXT("Feature not yet implemented"), TEXT("Sorry"), MB_OK);
730 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
731 }
732 break;
733 }
734 }
735 break;
736 }
737
738 case WM_NOTIFY:
739 {
740 LPNMHDR lpnm = (LPNMHDR)lParam;
741
742 switch(lpnm->code)
743 {
744 case PSN_APPLY:
745 {
746 SetScreenSaver(hwndDlg, pData);
747 return TRUE;
748 }
749
750 case PSN_SETACTIVE:
751 {
752 /* activate screen saver support */
753 SystemParametersInfoW(SPI_SETSCREENSAVEACTIVE, TRUE, 0, SPIF_SENDCHANGE);
754 SetScreenSaverPreviewBox(hwndDlg, pData);
755 break;
756 }
757
758 case PSN_KILLACTIVE:
759 {
760 /* Disable screensaver support */
761 SystemParametersInfoW(SPI_SETSCREENSAVEACTIVE, FALSE, 0, SPIF_SENDCHANGE);
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 }