2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Winlogon
4 * FILE: base/system/winlogon/screensaver.c
5 * PURPOSE: Screen saver management
6 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
9 /* INCLUDES *****************************************************************/
13 WINE_DEFAULT_DEBUG_CHANNEL(winlogon
);
15 /* FUNCTIONS ****************************************************************/
17 #ifndef USE_GETLASTINPUTINFO
21 KeyboardActivityProc(IN INT nCode
,
25 InterlockedExchange((LONG
*)&WLSession
->LastActivity
, ((PKBDLLHOOKSTRUCT
)lParam
)->time
);
26 return CallNextHookEx(NULL
, nCode
, wParam
, lParam
);
33 MouseActivityProc(IN INT nCode
,
37 InterlockedExchange((LONG
*)&WLSession
->LastActivity
, ((PMSLLHOOKSTRUCT
)lParam
)->time
);
38 return CallNextHookEx(NULL
, nCode
, wParam
, lParam
);
45 LoadScreenSaverParameters(OUT LPDWORD Timeout
)
49 if (!SystemParametersInfoW(SPI_GETSCREENSAVETIMEOUT
, 0, Timeout
, 0))
51 WARN("WL: Unable to get screen saver timeout (error %lu). Disabling it\n", GetLastError());
54 else if (!SystemParametersInfoW(SPI_GETSCREENSAVEACTIVE
, 0, &Enabled
, 0))
56 WARN("WL: Unable to check if screen saver is enabled (error %lu). Disabling it\n", GetLastError());
61 TRACE("WL: Screen saver is disabled\n");
66 TRACE("WL: Screen saver timeout: %lu seconds\n", *Timeout
);
75 ScreenSaverThreadMain(IN LPVOID lpParameter
)
77 PWLSESSION Session
= (PWLSESSION
)lpParameter
;
78 HANDLE HandleArray
[3];
79 #ifdef USE_GETLASTINPUTINFO
80 LASTINPUTINFO lastInputInfo
;
85 DWORD Timeout
; /* Timeout before screen saver starts, in milliseconds */
88 if (!ImpersonateLoggedOnUser(Session
->UserToken
))
90 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
94 Session
->hUserActivity
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
95 if (!Session
->hUserActivity
)
97 ERR("WL: Unable to create event (error %lu)\n", GetLastError());
101 Session
->hEndOfScreenSaver
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
102 if (!Session
->hEndOfScreenSaver
)
104 ERR("WL: Unable to create event (error %lu)\n", GetLastError());
108 HandleArray
[0] = Session
->hEndOfScreenSaverThread
;
109 HandleArray
[1] = Session
->hScreenSaverParametersChanged
;
110 HandleArray
[2] = Session
->hEndOfScreenSaver
;
112 LoadScreenSaverParameters(&Timeout
);
114 #ifndef USE_GETLASTINPUTINFO
115 InterlockedExchange((LONG
*)&Session
->LastActivity
, GetTickCount());
117 lastInputInfo
.cbSize
= sizeof(LASTINPUTINFO
);
121 /* See the time of last activity and calculate a timeout */
122 #ifndef USE_GETLASTINPUTINFO
123 LastActivity
= InterlockedCompareExchange((LONG
*)&Session
->LastActivity
, 0, 0);
124 TimeToWait
= Timeout
- (GetTickCount() - LastActivity
);
126 if (GetLastInputInfo(&lastInputInfo
))
127 TimeToWait
= Timeout
- (GetTickCount() - lastInputInfo
.dwTime
);
130 WARN("GetLastInputInfo() failed with error %lu\n", GetLastError());
131 TimeToWait
= 10; /* Try again in 10 ms */
135 if (TimeToWait
> Timeout
)
137 /* GetTickCount() got back to 0 */
138 TimeToWait
= Timeout
;
141 /* Wait for the timeout, or the end of this thread */
142 ret
= WaitForMultipleObjects(2, HandleArray
, FALSE
, TimeToWait
);
143 if (ret
== WAIT_OBJECT_0
)
145 else if (ret
== WAIT_OBJECT_0
+ 1)
146 LoadScreenSaverParameters(&Timeout
);
148 /* Check if we didn't had recent activity */
149 #ifndef USE_GETLASTINPUTINFO
150 LastActivity
= InterlockedCompareExchange((LONG
*)&Session
->LastActivity
, 0, 0);
151 if (LastActivity
+ Timeout
> GetTickCount())
154 if (!GetLastInputInfo(&lastInputInfo
))
156 WARN("GetLastInputInfo() failed with error %lu\n", GetLastError());
160 if (lastInputInfo
.dwTime
+ Timeout
> GetTickCount())
164 /* Run screen saver */
165 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_SCRNSVR_TIMEOUT
, 0);
167 /* Wait for the end of this thread or of the screen saver */
168 ret
= WaitForMultipleObjects(3, HandleArray
, FALSE
, INFINITE
);
169 if (ret
== WAIT_OBJECT_0
)
171 else if (ret
== WAIT_OBJECT_0
+ 1)
172 LoadScreenSaverParameters(&Timeout
);
173 else if (ret
== WAIT_OBJECT_0
+ 2)
174 SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING
, FALSE
, NULL
, 0);
179 if (Session
->hUserActivity
)
180 CloseHandle(Session
->hUserActivity
);
182 if (Session
->hEndOfScreenSaver
)
183 CloseHandle(Session
->hEndOfScreenSaver
);
185 #ifndef USE_GETLASTINPUTINFO
186 if (Session
->KeyboardHook
)
187 UnhookWindowsHookEx(Session
->KeyboardHook
);
189 if (Session
->MouseHook
)
190 UnhookWindowsHookEx(Session
->MouseHook
);
193 CloseHandle(Session
->hEndOfScreenSaverThread
);
194 CloseHandle(Session
->hScreenSaverParametersChanged
);
200 InitializeScreenSaver(IN OUT PWLSESSION Session
)
202 HANDLE ScreenSaverThread
;
204 #ifndef USE_GETLASTINPUTINFO
205 /* Register hooks to detect keyboard and mouse activity */
206 Session
->KeyboardHook
= SetWindowsHookEx(WH_KEYBOARD_LL
, KeyboardActivityProc
, hAppInstance
, 0);
207 if (!Session
->KeyboardHook
)
209 ERR("WL: Unable to register keyboard hook\n");
213 Session
->MouseHook
= SetWindowsHookEx(WH_MOUSE_LL
, MouseActivityProc
, hAppInstance
, 0);
214 if (!Session
->MouseHook
)
216 ERR("WL: Unable to register mouse hook\n");
221 Session
->hScreenSaverParametersChanged
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
222 if (!Session
->hScreenSaverParametersChanged
)
224 WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
228 Session
->hEndOfScreenSaverThread
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
229 if (!Session
->hEndOfScreenSaverThread
)
231 WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
232 CloseHandle(Session
->hScreenSaverParametersChanged
);
236 ScreenSaverThread
= CreateThread(NULL
,
238 ScreenSaverThreadMain
,
242 if (ScreenSaverThread
)
243 CloseHandle(ScreenSaverThread
);
245 ERR("WL: Unable to start screen saver thread\n");
252 StartScreenSaver(IN PWLSESSION Session
)
254 HKEY hKey
= NULL
, hCurrentUser
= NULL
;
255 WCHAR szApplicationName
[MAX_PATH
];
256 WCHAR szCommandLine
[MAX_PATH
+ 3];
257 DWORD bufferSize
= sizeof(szApplicationName
) - sizeof(WCHAR
);
259 STARTUPINFOW StartupInfo
;
260 PROCESS_INFORMATION ProcessInformation
;
261 HANDLE HandleArray
[2];
266 if (!ImpersonateLoggedOnUser(Session
->UserToken
))
268 ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
272 rc
= RegOpenCurrentUser(KEY_READ
,
274 if (rc
!= ERROR_SUCCESS
)
276 ERR("WL: RegOpenCurrentUser Error!\n");
280 rc
= RegOpenKeyExW(hCurrentUser
,
281 L
"Control Panel\\Desktop",
285 if (rc
!= ERROR_SUCCESS
)
287 ERR("WL: RegOpenKeyEx Error!\n");
291 rc
= RegQueryValueExW(hKey
,
295 (LPBYTE
)szApplicationName
,
297 if (rc
!= ERROR_SUCCESS
|| dwType
!= REG_SZ
)
299 ERR("WL: RegQueryValueEx Error!\n");
305 ERR("WL: Buffer size is NULL!\n");
309 szApplicationName
[bufferSize
/ sizeof(WCHAR
)] = 0; /* Terminate the string */
311 if (wcslen(szApplicationName
) == 0)
313 ERR("WL: Application Name length is zero!\n");
317 wsprintfW(szCommandLine
, L
"%s /s", szApplicationName
);
318 TRACE("WL: Executing %S\n", szCommandLine
);
320 ZeroMemory(&StartupInfo
, sizeof(STARTUPINFOW
));
321 ZeroMemory(&ProcessInformation
, sizeof(PROCESS_INFORMATION
));
322 StartupInfo
.cb
= sizeof(STARTUPINFOW
);
323 StartupInfo
.dwFlags
= STARTF_SCRNSAVER
;
325 /* FIXME: run the screen saver on the screen saver desktop */
326 ret
= CreateProcessW(szApplicationName
,
335 &ProcessInformation
);
338 ERR("WL: Unable to start %S, error %lu\n", szApplicationName
, GetLastError());
342 CloseHandle(ProcessInformation
.hThread
);
344 SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING
, TRUE
, NULL
, 0);
346 /* Wait the end of the process or some other activity */
347 ResetEvent(Session
->hUserActivity
);
348 HandleArray
[0] = ProcessInformation
.hProcess
;
349 HandleArray
[1] = Session
->hUserActivity
;
350 Status
= WaitForMultipleObjects(2, HandleArray
, FALSE
, INFINITE
);
351 if (Status
== WAIT_OBJECT_0
+ 1)
353 /* Kill the screen saver */
354 TerminateProcess(ProcessInformation
.hProcess
, 0);
357 SetEvent(Session
->hEndOfScreenSaver
);
359 CloseHandle(ProcessInformation
.hProcess
);
367 RegCloseKey(hCurrentUser
);
371 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_SCRNSVR_ACTIVITY
, 0);
372 #ifndef USE_GETLASTINPUTINFO
373 InterlockedExchange((LONG
*)&Session
->LastActivity
, GetTickCount());