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 #include <wine/debug.h>
15 WINE_DEFAULT_DEBUG_CHANNEL(winlogon
);
17 /* FUNCTIONS ****************************************************************/
19 #ifndef USE_GETLASTINPUTINFO
20 static LRESULT CALLBACK
26 InterlockedExchange((LONG
*)&WLSession
->LastActivity
, ((PKBDLLHOOKSTRUCT
)lParam
)->time
);
27 return CallNextHookEx(NULL
, nCode
, wParam
, lParam
);
30 static LRESULT CALLBACK
36 InterlockedExchange((LONG
*)&WLSession
->LastActivity
, ((PMSLLHOOKSTRUCT
)lParam
)->time
);
37 return CallNextHookEx(NULL
, nCode
, wParam
, lParam
);
42 LoadScreenSaverParameters(
47 if (!SystemParametersInfoW(SPI_GETSCREENSAVETIMEOUT
, 0, Timeout
, 0))
49 WARN("WL: Unable to get screen saver timeout (error %lu). Disabling it\n", GetLastError());
52 else if (!SystemParametersInfoW(SPI_GETSCREENSAVEACTIVE
, 0, &Enabled
, 0))
54 WARN("WL: Unable to check if screen saver is enabled (error %lu). Disabling it\n", GetLastError());
59 TRACE("WL: Screen saver is disabled\n");
64 TRACE("WL: Screen saver timeout: %lu seconds\n", *Timeout
);
70 ScreenSaverThreadMain(
71 IN LPVOID lpParameter
)
73 PWLSESSION Session
= (PWLSESSION
)lpParameter
;
74 HANDLE HandleArray
[3];
75 #ifdef USE_GETLASTINPUTINFO
76 LASTINPUTINFO lastInputInfo
;
81 DWORD Timeout
; /* Timeout before screen saver starts, in milliseconds */
84 if (!ImpersonateLoggedOnUser(Session
->UserToken
))
86 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
90 Session
->hUserActivity
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
91 if (!Session
->hUserActivity
)
93 ERR("WL: Unable to create event (error %lu)\n", GetLastError());
97 Session
->hEndOfScreenSaver
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
98 if (!Session
->hEndOfScreenSaver
)
100 ERR("WL: Unable to create event (error %lu)\n", GetLastError());
104 HandleArray
[0] = Session
->hEndOfScreenSaverThread
;
105 HandleArray
[1] = Session
->hScreenSaverParametersChanged
;
106 HandleArray
[2] = Session
->hEndOfScreenSaver
;
108 LoadScreenSaverParameters(&Timeout
);
110 #ifndef USE_GETLASTINPUTINFO
111 InterlockedExchange((LONG
*)&Session
->LastActivity
, GetTickCount());
113 lastInputInfo
.cbSize
= sizeof(LASTINPUTINFO
);
117 /* See the time of last activity and calculate a timeout */
118 #ifndef USE_GETLASTINPUTINFO
119 LastActivity
= InterlockedCompareExchange((LONG
*)&Session
->LastActivity
, 0, 0);
120 TimeToWait
= Timeout
- (GetTickCount() - LastActivity
);
122 if (GetLastInputInfo(&lastInputInfo
))
123 TimeToWait
= Timeout
- (GetTickCount() - lastInputInfo
.dwTime
);
126 WARN("GetLastInputInfo() failed with error %lu\n", GetLastError());
127 TimeToWait
= 10; /* Try again in 10 ms */
130 if (TimeToWait
> Timeout
)
132 /* GetTickCount() got back to 0 */
133 TimeToWait
= Timeout
;
136 /* Wait for the timeout, or the end of this thread */
137 ret
= WaitForMultipleObjects(2, HandleArray
, FALSE
, TimeToWait
);
138 if (ret
== WAIT_OBJECT_0
)
140 else if (ret
== WAIT_OBJECT_0
+ 1)
141 LoadScreenSaverParameters(&Timeout
);
143 /* Check if we didn't had recent activity */
144 #ifndef USE_GETLASTINPUTINFO
145 LastActivity
= InterlockedCompareExchange((LONG
*)&Session
->LastActivity
, 0, 0);
146 if (LastActivity
+ Timeout
> GetTickCount())
149 if (!GetLastInputInfo(&lastInputInfo
))
151 WARN("GetLastInputInfo() failed with error %lu\n", GetLastError());
154 if (lastInputInfo
.dwTime
+ Timeout
> GetTickCount())
158 /* Run screen saver */
159 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_SCRNSVR_TIMEOUT
, 0);
161 /* Wait for the end of this thread or of the screen saver */
162 ret
= WaitForMultipleObjects(3, HandleArray
, FALSE
, INFINITE
);
163 if (ret
== WAIT_OBJECT_0
)
165 else if (ret
== WAIT_OBJECT_0
+ 1)
166 LoadScreenSaverParameters(&Timeout
);
167 else if (ret
== WAIT_OBJECT_0
+ 2)
168 SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING
, FALSE
, NULL
, 0);
173 if (Session
->hUserActivity
)
174 CloseHandle(Session
->hUserActivity
);
175 if (Session
->hEndOfScreenSaver
)
176 CloseHandle(Session
->hEndOfScreenSaver
);
177 #ifndef USE_GETLASTINPUTINFO
178 if (Session
->KeyboardHook
)
179 UnhookWindowsHookEx(Session
->KeyboardHook
);
180 if (Session
->MouseHook
)
181 UnhookWindowsHookEx(Session
->MouseHook
);
183 CloseHandle(Session
->hEndOfScreenSaverThread
);
184 CloseHandle(Session
->hScreenSaverParametersChanged
);
189 InitializeScreenSaver(
190 IN OUT PWLSESSION Session
)
192 HANDLE ScreenSaverThread
;
194 #ifndef USE_GETLASTINPUTINFO
195 /* Register hooks to detect keyboard and mouse activity */
196 Session
->KeyboardHook
= SetWindowsHookEx(WH_KEYBOARD_LL
, KeyboardActivityProc
, hAppInstance
, 0);
197 if (!Session
->KeyboardHook
)
199 ERR("WL: Unable to register keyboard hook\n");
202 Session
->MouseHook
= SetWindowsHookEx(WH_MOUSE_LL
, MouseActivityProc
, hAppInstance
, 0);
203 if (!Session
->MouseHook
)
205 ERR("WL: Unable to register mouse hook\n");
210 Session
->hScreenSaverParametersChanged
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
211 if (!Session
->hScreenSaverParametersChanged
)
213 WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
216 Session
->hEndOfScreenSaverThread
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
217 if (!Session
->hEndOfScreenSaverThread
)
219 WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
220 CloseHandle(Session
->hScreenSaverParametersChanged
);
224 ScreenSaverThread
= CreateThread(
227 ScreenSaverThreadMain
,
231 if (ScreenSaverThread
)
232 CloseHandle(ScreenSaverThread
);
234 WARN("WL: Unable to start screen saver thread\n");
241 IN PWLSESSION Session
)
244 WCHAR szApplicationName
[MAX_PATH
];
245 WCHAR szCommandLine
[MAX_PATH
+ 3];
246 DWORD bufferSize
= sizeof(szApplicationName
) - sizeof(WCHAR
);
248 STARTUPINFOW StartupInfo
;
249 PROCESS_INFORMATION ProcessInformation
;
250 HANDLE HandleArray
[2];
255 if (!ImpersonateLoggedOnUser(Session
->UserToken
))
257 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
263 L
"Control Panel\\Desktop",
267 if (rc
!= ERROR_SUCCESS
)
270 rc
= RegQueryValueExW(
275 (LPBYTE
)szApplicationName
,
277 if (rc
!= ERROR_SUCCESS
|| dwType
!= REG_SZ
)
283 szApplicationName
[bufferSize
/ sizeof(WCHAR
)] = 0; /* Terminate the string */
285 if (wcslen(szApplicationName
) == 0)
288 wsprintfW(szCommandLine
, L
"%s /s", szApplicationName
);
289 TRACE("WL: Executing %S\n", szCommandLine
);
291 ZeroMemory(&StartupInfo
, sizeof(STARTUPINFOW
));
292 ZeroMemory(&ProcessInformation
, sizeof(PROCESS_INFORMATION
));
293 StartupInfo
.cb
= sizeof(STARTUPINFOW
);
294 /* FIXME: run the screen saver on the screen saver desktop */
295 ret
= CreateProcessW(
305 &ProcessInformation
);
308 WARN("WL: Unable to start %S, error %lu\n", szApplicationName
, GetLastError());
311 CloseHandle(ProcessInformation
.hThread
);
313 SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING
, TRUE
, NULL
, 0);
315 /* Wait the end of the process or some other activity */
316 ResetEvent(Session
->hUserActivity
);
317 HandleArray
[0] = ProcessInformation
.hProcess
;
318 HandleArray
[1] = Session
->hUserActivity
;
319 Status
= WaitForMultipleObjects(2, HandleArray
, FALSE
, INFINITE
);
320 if (Status
== WAIT_OBJECT_0
+ 1)
322 /* Kill the screen saver */
323 TerminateProcess(ProcessInformation
.hProcess
, 0);
325 SetEvent(Session
->hEndOfScreenSaver
);
327 CloseHandle(ProcessInformation
.hProcess
);
335 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_SCRNSVR_ACTIVITY
, 0);
336 #ifndef USE_GETLASTINPUTINFO
337 InterlockedExchange((LONG
*)&Session
->LastActivity
, GetTickCount());