2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: services/winlogon/screensaver.c
5 * PURPOSE: Screen saver management
6 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
12 #include <wine/debug.h>
14 #ifndef USE_GETLASTINPUTINFO
15 static LRESULT CALLBACK
21 InterlockedExchange((LONG
*)&WLSession
->LastActivity
, ((PKBDLLHOOKSTRUCT
)lParam
)->time
);
22 return CallNextHookEx(NULL
, nCode
, wParam
, lParam
);
25 static LRESULT CALLBACK
31 InterlockedExchange((LONG
*)&WLSession
->LastActivity
, ((PMSLLHOOKSTRUCT
)lParam
)->time
);
32 return CallNextHookEx(NULL
, nCode
, wParam
, lParam
);
37 LoadScreenSaverParameters(
42 if (!SystemParametersInfoW(SPI_GETSCREENSAVETIMEOUT
, 0, Timeout
, 0))
44 WARN("WL: Unable to get screen saver timeout (error %lu). Disabling it\n", GetLastError());
47 else if (!SystemParametersInfoW(SPI_GETSCREENSAVEACTIVE
, 0, &Enabled
, 0))
49 WARN("WL: Unable to check if screen saver is enabled (error %lu). Disabling it\n", GetLastError());
54 TRACE("WL: Screen saver is disabled\n");
59 TRACE("WL: Screen saver timeout: %lu seconds\n", *Timeout
);
65 ScreenSaverThreadMain(
66 IN LPVOID lpParameter
)
68 PWLSESSION Session
= (PWLSESSION
)lpParameter
;
69 HANDLE HandleArray
[3];
70 #ifdef USE_GETLASTINPUTINFO
71 LASTINPUTINFO lastInputInfo
;
76 DWORD Timeout
; /* Timeout before screen saver starts, in milliseconds */
79 if (!ImpersonateLoggedOnUser(Session
->UserToken
))
81 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
85 Session
->hUserActivity
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
86 if (!Session
->hUserActivity
)
88 ERR("WL: Unable to create event (error %lu)\n", GetLastError());
92 Session
->hEndOfScreenSaver
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
93 if (!Session
->hEndOfScreenSaver
)
95 ERR("WL: Unable to create event (error %lu)\n", GetLastError());
99 HandleArray
[0] = Session
->hEndOfScreenSaverThread
;
100 HandleArray
[1] = Session
->hScreenSaverParametersChanged
;
101 HandleArray
[2] = Session
->hEndOfScreenSaver
;
103 LoadScreenSaverParameters(&Timeout
);
105 #ifndef USE_GETLASTINPUTINFO
106 InterlockedExchange((LONG
*)&Session
->LastActivity
, GetTickCount());
108 lastInputInfo
.cbSize
= sizeof(LASTINPUTINFO
);
112 /* See the time of last activity and calculate a timeout */
113 #ifndef USE_GETLASTINPUTINFO
114 LastActivity
= InterlockedCompareExchange((LONG
*)&Session
->LastActivity
, 0, 0);
115 TimeToWait
= Timeout
- (GetTickCount() - LastActivity
);
117 if (GetLastInputInfo(&lastInputInfo
))
118 TimeToWait
= Timeout
- (GetTickCount() - lastInputInfo
.dwTime
);
121 WARN("GetLastInputInfo() failed with error %lu\n", GetLastError());
122 TimeToWait
= 10; /* Try again in 10 ms */
125 if (TimeToWait
> Timeout
)
127 /* GetTickCount() got back to 0 */
128 TimeToWait
= Timeout
;
131 /* Wait for the timeout, or the end of this thread */
132 ret
= WaitForMultipleObjects(2, HandleArray
, FALSE
, TimeToWait
);
133 if (ret
== WAIT_OBJECT_0
)
135 else if (ret
== WAIT_OBJECT_0
+ 1)
136 LoadScreenSaverParameters(&Timeout
);
138 /* Check if we didn't had recent activity */
139 #ifndef USE_GETLASTINPUTINFO
140 LastActivity
= InterlockedCompareExchange((LONG
*)&Session
->LastActivity
, 0, 0);
141 if (LastActivity
+ Timeout
> GetTickCount())
144 if (!GetLastInputInfo(&lastInputInfo
))
146 WARN("GetLastInputInfo() failed with error %lu\n", GetLastError());
149 if (lastInputInfo
.dwTime
+ Timeout
> GetTickCount())
153 /* Run screen saver */
154 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_SCRNSVR_TIMEOUT
, 0);
156 /* Wait for the end of this thread or of the screen saver */
157 ret
= WaitForMultipleObjects(3, HandleArray
, FALSE
, INFINITE
);
158 if (ret
== WAIT_OBJECT_0
)
160 else if (ret
== WAIT_OBJECT_0
+ 1)
161 LoadScreenSaverParameters(&Timeout
);
162 else if (ret
== WAIT_OBJECT_0
+ 2)
163 SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING
, FALSE
, NULL
, 0);
168 if (Session
->hUserActivity
)
169 CloseHandle(Session
->hUserActivity
);
170 if (Session
->hEndOfScreenSaver
)
171 CloseHandle(Session
->hEndOfScreenSaver
);
172 #ifndef USE_GETLASTINPUTINFO
173 if (Session
->KeyboardHook
)
174 UnhookWindowsHookEx(Session
->KeyboardHook
);
175 if (Session
->MouseHook
)
176 UnhookWindowsHookEx(Session
->MouseHook
);
178 CloseHandle(Session
->hEndOfScreenSaverThread
);
179 CloseHandle(Session
->hScreenSaverParametersChanged
);
184 InitializeScreenSaver(
185 IN OUT PWLSESSION Session
)
187 HANDLE ScreenSaverThread
;
189 #ifndef USE_GETLASTINPUTINFO
190 /* Register hooks to detect keyboard and mouse activity */
191 Session
->KeyboardHook
= SetWindowsHookEx(WH_KEYBOARD_LL
, KeyboardActivityProc
, hAppInstance
, 0);
192 if (!Session
->KeyboardHook
)
194 ERR("WL: Unable to register keyboard hook\n");
197 Session
->MouseHook
= SetWindowsHookEx(WH_MOUSE_LL
, MouseActivityProc
, hAppInstance
, 0);
198 if (!Session
->MouseHook
)
200 ERR("WL: Unable to register mouse hook\n");
205 Session
->hScreenSaverParametersChanged
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
206 if (!Session
->hScreenSaverParametersChanged
)
208 WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
211 Session
->hEndOfScreenSaverThread
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
212 if (!Session
->hEndOfScreenSaverThread
)
214 WARN("WL: Unable to create screen saver event (error %lu)\n", GetLastError());
215 CloseHandle(Session
->hScreenSaverParametersChanged
);
219 ScreenSaverThread
= CreateThread(
222 ScreenSaverThreadMain
,
226 if (ScreenSaverThread
)
227 CloseHandle(ScreenSaverThread
);
229 WARN("WL: Unable to start screen saver thread\n");
236 IN PWLSESSION Session
)
239 WCHAR szApplicationName
[MAX_PATH
];
240 WCHAR szCommandLine
[MAX_PATH
+ 3];
241 DWORD bufferSize
= sizeof(szApplicationName
)- 1;
243 STARTUPINFOW StartupInfo
;
244 PROCESS_INFORMATION ProcessInformation
;
245 HANDLE HandleArray
[2];
250 if (!ImpersonateLoggedOnUser(Session
->UserToken
))
252 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
258 L
"Control Panel\\Desktop",
262 if (rc
!= ERROR_SUCCESS
)
265 rc
= RegQueryValueExW(
270 (LPBYTE
)szApplicationName
,
272 if (rc
!= ERROR_SUCCESS
|| dwType
!= REG_SZ
)
278 szApplicationName
[bufferSize
] = 0; /* Terminate the string */
280 if (wcslen(szApplicationName
) == 0)
283 wsprintfW(szCommandLine
, L
"%s /s", szApplicationName
);
284 TRACE("WL: Executing %S\n", szCommandLine
);
286 ZeroMemory(&StartupInfo
, sizeof(STARTUPINFOW
));
287 ZeroMemory(&ProcessInformation
, sizeof(PROCESS_INFORMATION
));
288 StartupInfo
.cb
= sizeof(STARTUPINFOW
);
289 /* FIXME: run the screen saver on the screen saver desktop */
290 ret
= CreateProcessW(
300 &ProcessInformation
);
303 WARN("WL: Unable to start %S, error %lu\n", szApplicationName
, GetLastError());
306 CloseHandle(ProcessInformation
.hThread
);
308 SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING
, TRUE
, NULL
, 0);
310 /* Wait the end of the process or some other activity */
311 ResetEvent(Session
->hUserActivity
);
312 HandleArray
[0] = ProcessInformation
.hProcess
;
313 HandleArray
[1] = Session
->hUserActivity
;
314 Status
= WaitForMultipleObjects(2, HandleArray
, FALSE
, INFINITE
);
315 if (Status
== WAIT_OBJECT_0
+ 1)
317 /* Kill the screen saver */
318 TerminateProcess(ProcessInformation
.hProcess
, 0);
320 SetEvent(Session
->hEndOfScreenSaver
);
322 CloseHandle(ProcessInformation
.hProcess
);
330 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_SCRNSVR_ACTIVITY
, 0);
331 #ifndef USE_GETLASTINPUTINFO
332 InterlockedExchange((LONG
*)&Session
->LastActivity
, GetTickCount());