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
26 InterlockedExchange((LONG
*)&WLSession
->LastActivity
, ((PKBDLLHOOKSTRUCT
)lParam
)->time
);
27 return CallNextHookEx(NULL
, nCode
, wParam
, lParam
);
39 InterlockedExchange((LONG
*)&WLSession
->LastActivity
, ((PMSLLHOOKSTRUCT
)lParam
)->time
);
40 return CallNextHookEx(NULL
, nCode
, wParam
, lParam
);
47 LoadScreenSaverParameters(
52 if (!SystemParametersInfoW(SPI_GETSCREENSAVETIMEOUT
, 0, Timeout
, 0))
54 WARN("WL: Unable to get screen saver timeout (error %lu). Disabling it\n", GetLastError());
57 else if (!SystemParametersInfoW(SPI_GETSCREENSAVEACTIVE
, 0, &Enabled
, 0))
59 WARN("WL: Unable to check if screen saver is enabled (error %lu). Disabling it\n", GetLastError());
64 TRACE("WL: Screen saver is disabled\n");
69 TRACE("WL: Screen saver timeout: %lu seconds\n", *Timeout
);
78 ScreenSaverThreadMain(
79 IN LPVOID lpParameter
)
81 PWLSESSION Session
= (PWLSESSION
)lpParameter
;
82 HANDLE HandleArray
[3];
83 #ifdef USE_GETLASTINPUTINFO
84 LASTINPUTINFO lastInputInfo
;
89 DWORD Timeout
; /* Timeout before screen saver starts, in milliseconds */
92 if (!ImpersonateLoggedOnUser(Session
->UserToken
))
94 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
98 Session
->hUserActivity
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
99 if (!Session
->hUserActivity
)
101 ERR("WL: Unable to create event (error %lu)\n", GetLastError());
105 Session
->hEndOfScreenSaver
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
106 if (!Session
->hEndOfScreenSaver
)
108 ERR("WL: Unable to create event (error %lu)\n", GetLastError());
112 HandleArray
[0] = Session
->hEndOfScreenSaverThread
;
113 HandleArray
[1] = Session
->hScreenSaverParametersChanged
;
114 HandleArray
[2] = Session
->hEndOfScreenSaver
;
116 LoadScreenSaverParameters(&Timeout
);
118 #ifndef USE_GETLASTINPUTINFO
119 InterlockedExchange((LONG
*)&Session
->LastActivity
, GetTickCount());
121 lastInputInfo
.cbSize
= sizeof(LASTINPUTINFO
);
125 /* See the time of last activity and calculate a timeout */
126 #ifndef USE_GETLASTINPUTINFO
127 LastActivity
= InterlockedCompareExchange((LONG
*)&Session
->LastActivity
, 0, 0);
128 TimeToWait
= Timeout
- (GetTickCount() - LastActivity
);
130 if (GetLastInputInfo(&lastInputInfo
))
131 TimeToWait
= Timeout
- (GetTickCount() - lastInputInfo
.dwTime
);
134 WARN("GetLastInputInfo() failed with error %lu\n", GetLastError());
135 TimeToWait
= 10; /* Try again in 10 ms */
139 if (TimeToWait
> Timeout
)
141 /* GetTickCount() got back to 0 */
142 TimeToWait
= Timeout
;
145 /* Wait for the timeout, or the end of this thread */
146 ret
= WaitForMultipleObjects(2, HandleArray
, FALSE
, TimeToWait
);
147 if (ret
== WAIT_OBJECT_0
)
149 else if (ret
== WAIT_OBJECT_0
+ 1)
150 LoadScreenSaverParameters(&Timeout
);
152 /* Check if we didn't had recent activity */
153 #ifndef USE_GETLASTINPUTINFO
154 LastActivity
= InterlockedCompareExchange((LONG
*)&Session
->LastActivity
, 0, 0);
155 if (LastActivity
+ Timeout
> GetTickCount())
158 if (!GetLastInputInfo(&lastInputInfo
))
160 WARN("GetLastInputInfo() failed with error %lu\n", GetLastError());
164 if (lastInputInfo
.dwTime
+ Timeout
> GetTickCount())
168 /* Run screen saver */
169 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_SCRNSVR_TIMEOUT
, 0);
171 /* Wait for the end of this thread or of the screen saver */
172 ret
= WaitForMultipleObjects(3, HandleArray
, FALSE
, INFINITE
);
173 if (ret
== WAIT_OBJECT_0
)
175 else if (ret
== WAIT_OBJECT_0
+ 1)
176 LoadScreenSaverParameters(&Timeout
);
177 else if (ret
== WAIT_OBJECT_0
+ 2)
178 SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING
, FALSE
, NULL
, 0);
183 if (Session
->hUserActivity
)
184 CloseHandle(Session
->hUserActivity
);
186 if (Session
->hEndOfScreenSaver
)
187 CloseHandle(Session
->hEndOfScreenSaver
);
189 #ifndef USE_GETLASTINPUTINFO
190 if (Session
->KeyboardHook
)
191 UnhookWindowsHookEx(Session
->KeyboardHook
);
193 if (Session
->MouseHook
)
194 UnhookWindowsHookEx(Session
->MouseHook
);
197 CloseHandle(Session
->hEndOfScreenSaverThread
);
198 CloseHandle(Session
->hScreenSaverParametersChanged
);
204 InitializeScreenSaver(
205 IN OUT PWLSESSION Session
)
207 HANDLE ScreenSaverThread
;
209 #ifndef USE_GETLASTINPUTINFO
210 /* Register hooks to detect keyboard and mouse activity */
211 Session
->KeyboardHook
= SetWindowsHookEx(WH_KEYBOARD_LL
, KeyboardActivityProc
, hAppInstance
, 0);
212 if (!Session
->KeyboardHook
)
214 ERR("WL: Unable to register keyboard hook\n");
218 Session
->MouseHook
= SetWindowsHookEx(WH_MOUSE_LL
, MouseActivityProc
, hAppInstance
, 0);
219 if (!Session
->MouseHook
)
221 ERR("WL: Unable to register mouse hook\n");
226 Session
->hScreenSaverParametersChanged
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
227 if (!Session
->hScreenSaverParametersChanged
)
229 WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
233 Session
->hEndOfScreenSaverThread
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
234 if (!Session
->hEndOfScreenSaverThread
)
236 WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
237 CloseHandle(Session
->hScreenSaverParametersChanged
);
241 ScreenSaverThread
= CreateThread(NULL
,
243 ScreenSaverThreadMain
,
247 if (ScreenSaverThread
)
248 CloseHandle(ScreenSaverThread
);
250 ERR("WL: Unable to start screen saver thread\n");
258 IN PWLSESSION Session
)
260 HKEY hKey
= NULL
, hCurrentUser
= NULL
;
261 WCHAR szApplicationName
[MAX_PATH
];
262 WCHAR szCommandLine
[MAX_PATH
+ 3];
263 DWORD bufferSize
= sizeof(szApplicationName
) - sizeof(WCHAR
);
265 STARTUPINFOW StartupInfo
;
266 PROCESS_INFORMATION ProcessInformation
;
267 HANDLE HandleArray
[2];
272 if (!ImpersonateLoggedOnUser(Session
->UserToken
))
274 ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
278 rc
= RegOpenCurrentUser(KEY_READ
,
280 if (rc
!= ERROR_SUCCESS
)
282 ERR("WL: RegOpenCurrentUser Error!\n");
286 rc
= RegOpenKeyExW(hCurrentUser
,
287 L
"Control Panel\\Desktop",
291 if (rc
!= ERROR_SUCCESS
)
293 ERR("WL: RegOpenKeyEx Error!\n");
297 rc
= RegQueryValueExW(hKey
,
301 (LPBYTE
)szApplicationName
,
303 if (rc
!= ERROR_SUCCESS
|| dwType
!= REG_SZ
)
305 ERR("WL: RegQueryValueEx Error!\n");
311 ERR("WL: Buffer size is NULL!\n");
315 szApplicationName
[bufferSize
/ sizeof(WCHAR
)] = 0; /* Terminate the string */
317 if (wcslen(szApplicationName
) == 0)
319 ERR("WL: Application Name length is zero!\n");
323 wsprintfW(szCommandLine
, L
"%s /s", szApplicationName
);
324 TRACE("WL: Executing %S\n", szCommandLine
);
326 ZeroMemory(&StartupInfo
, sizeof(STARTUPINFOW
));
327 ZeroMemory(&ProcessInformation
, sizeof(PROCESS_INFORMATION
));
328 StartupInfo
.cb
= sizeof(STARTUPINFOW
);
329 StartupInfo
.dwFlags
= STARTF_SCRNSAVER
;
331 /* FIXME: run the screen saver on the screen saver desktop */
332 ret
= CreateProcessW(szApplicationName
,
341 &ProcessInformation
);
344 ERR("WL: Unable to start %S, error %lu\n", szApplicationName
, GetLastError());
348 CloseHandle(ProcessInformation
.hThread
);
350 SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING
, TRUE
, NULL
, 0);
352 /* Wait the end of the process or some other activity */
353 ResetEvent(Session
->hUserActivity
);
354 HandleArray
[0] = ProcessInformation
.hProcess
;
355 HandleArray
[1] = Session
->hUserActivity
;
356 Status
= WaitForMultipleObjects(2, HandleArray
, FALSE
, INFINITE
);
357 if (Status
== WAIT_OBJECT_0
+ 1)
359 /* Kill the screen saver */
360 TerminateProcess(ProcessInformation
.hProcess
, 0);
363 SetEvent(Session
->hEndOfScreenSaver
);
365 CloseHandle(ProcessInformation
.hProcess
);
373 RegCloseKey(hCurrentUser
);
377 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_SCRNSVR_ACTIVITY
, 0);
378 #ifndef USE_GETLASTINPUTINFO
379 InterlockedExchange((LONG
*)&Session
->LastActivity
, GetTickCount());