1/*
2 * Copyright 2003-2014 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Jérôme Duval, jerome.duval@free.fr
7 *		Axel Dörfler, axeld@pinc-software.de
8 *		Ryan Leavengood, leavengood@gmail.com
9 *		Michael Phipps
10 *		John Scipione, jscipione@gmail.com
11 *		Puck Meerburg, puck@puckipedia.nl
12 */
13
14
15#include "ScreenBlanker.h"
16
17#include <Beep.h>
18#include <Debug.h>
19#include <File.h>
20#include <FindDirectory.h>
21#include <Path.h>
22#include <Screen.h>
23#include <StorageDefs.h>
24#include <SupportDefs.h>
25#include <image.h>
26
27#include <stdio.h>
28#include <string.h>
29#include <syslog.h>
30
31#include "ScreenSaverShared.h"
32
33const static uint32 kMsgTurnOffScreen = 'tofs';
34const static uint32 kMsgSuspendScreen = 'suss';
35const static uint32 kMsgStandByScreen = 'stbs';
36
37
38//	#pragma mark - ScreenBlanker
39
40
41ScreenBlanker::ScreenBlanker()
42	:
43	BApplication(SCREEN_BLANKER_SIG),
44	fWindow(NULL),
45	fSaverRunner(NULL),
46	fPasswordWindow(NULL),
47	fTestSaver(false),
48	fResumeRunner(NULL),
49	fStandByScreenRunner(NULL),
50	fSuspendScreenRunner(NULL),
51	fTurnOffScreenRunner(NULL)
52{
53	fBlankTime = system_time();
54}
55
56
57ScreenBlanker::~ScreenBlanker()
58{
59	delete fResumeRunner;
60	_TurnOnScreen();
61}
62
63
64void
65ScreenBlanker::ReadyToRun()
66{
67	if (!fSettings.Load())
68		fprintf(stderr, "could not load settings, using defaults\n");
69
70	// create a BDirectWindow and start the render thread.
71	// TODO: we need a window per screen...
72	BScreen screen(B_MAIN_SCREEN_ID);
73	fWindow = new ScreenSaverWindow(screen.Frame(), fTestSaver);
74	fPasswordWindow = new PasswordWindow();
75
76	BView* view = fWindow->ChildAt(0);
77	fSaverRunner = new ScreenSaverRunner(fWindow, view, fSettings);
78	fWindow->SetSaverRunner(fSaverRunner);
79
80	BScreenSaver* saver = fSaverRunner->ScreenSaver();
81	if (saver != NULL && saver->StartSaver(view, false) == B_OK)
82		fSaverRunner->Run();
83	else {
84		fprintf(stderr, "could not load the screensaver addon\n");
85		view->SetViewColor(0, 0, 0);
86			// needed for Blackness saver
87	}
88
89	fWindow->SetFullScreen(true);
90	fWindow->Show();
91	HideCursor();
92
93	_QueueTurnOffScreen();
94}
95
96
97void
98ScreenBlanker::_TurnOnScreen()
99{
100	delete fStandByScreenRunner;
101	delete fSuspendScreenRunner;
102	delete fTurnOffScreenRunner;
103
104	fStandByScreenRunner = fSuspendScreenRunner = fTurnOffScreenRunner = NULL;
105
106	BScreen screen;
107	screen.SetDPMS(B_DPMS_ON);
108}
109
110
111void
112ScreenBlanker::_SetDPMSMode(uint32 mode)
113{
114	BScreen screen;
115	screen.SetDPMS(mode);
116
117	if (fWindow->Lock()) {
118		fSaverRunner->Suspend();
119		fWindow->Unlock();
120	}
121}
122
123
124void
125ScreenBlanker::_ShowPasswordWindow()
126{
127	_TurnOnScreen();
128
129	if (fWindow->Lock()) {
130		fSaverRunner->Suspend();
131
132		fWindow->Sync();
133			// TODO: is that needed?
134		ShowCursor();
135		if (fPasswordWindow->IsHidden())
136			fPasswordWindow->Show();
137
138		fWindow->Unlock();
139	}
140
141	_QueueResumeScreenSaver();
142}
143
144
145void
146ScreenBlanker::_QueueResumeScreenSaver()
147{
148	delete fResumeRunner;
149
150	BMessage resume(kMsgResumeSaver);
151	fResumeRunner = new BMessageRunner(BMessenger(this), &resume,
152		fSettings.BlankTime(), 1);
153	if (fResumeRunner->InitCheck() != B_OK)
154		syslog(LOG_ERR, "resume screen saver runner failed\n");
155}
156
157
158void
159ScreenBlanker::_QueueTurnOffScreen()
160{
161	// stop running notifiers
162
163	delete fStandByScreenRunner;
164	delete fSuspendScreenRunner;
165	delete fTurnOffScreenRunner;
166
167	fStandByScreenRunner = fSuspendScreenRunner = fTurnOffScreenRunner = NULL;
168
169	// figure out which notifiers we need and which of them are supported
170
171	uint32 flags = fSettings.TimeFlags();
172	BScreen screen;
173	uint32 capabilities = screen.DPMSCapabilites();
174	if ((capabilities & B_DPMS_OFF) == 0)
175		flags &= ~ENABLE_DPMS_OFF;
176	if ((capabilities & B_DPMS_SUSPEND) == 0)
177		flags &= ~ENABLE_DPMS_SUSPEND;
178	if ((capabilities & B_DPMS_STAND_BY) == 0)
179		flags &= ~ENABLE_DPMS_STAND_BY;
180
181	if ((flags & ENABLE_DPMS_MASK) == 0)
182		return;
183
184	if (fSettings.OffTime() == fSettings.SuspendTime()
185		&& (flags & (ENABLE_DPMS_OFF | ENABLE_DPMS_SUSPEND))
186			== (ENABLE_DPMS_OFF | ENABLE_DPMS_SUSPEND))
187		flags &= ~ENABLE_DPMS_SUSPEND;
188	if (fSettings.SuspendTime() == fSettings.StandByTime()
189		&& (flags & (ENABLE_DPMS_SUSPEND | ENABLE_DPMS_STAND_BY))
190			== (ENABLE_DPMS_SUSPEND | ENABLE_DPMS_STAND_BY))
191		flags &= ~ENABLE_DPMS_STAND_BY;
192
193	// start them off again
194
195	if (flags & ENABLE_DPMS_STAND_BY) {
196		BMessage dpms(kMsgStandByScreen);
197		fStandByScreenRunner = new BMessageRunner(BMessenger(this), &dpms,
198			fSettings.StandByTime(), 1);
199		if (fStandByScreenRunner->InitCheck() != B_OK)
200			syslog(LOG_ERR, "standby screen saver runner failed\n");
201	}
202
203	if (flags & ENABLE_DPMS_SUSPEND) {
204		BMessage dpms(kMsgSuspendScreen);
205		fSuspendScreenRunner = new BMessageRunner(BMessenger(this), &dpms,
206			fSettings.SuspendTime(), 1);
207		if (fSuspendScreenRunner->InitCheck() != B_OK)
208			syslog(LOG_ERR, "suspend screen saver runner failed\n");
209	}
210
211	if (flags & ENABLE_DPMS_OFF) {
212		BMessage dpms(kMsgTurnOffScreen);
213		fTurnOffScreenRunner = new BMessageRunner(BMessenger(this), &dpms,
214			fSettings.OffTime(), 1);
215		if (fTurnOffScreenRunner->InitCheck() != B_OK)
216			syslog(LOG_ERR, "turn off screen saver runner failed\n");
217	}
218}
219
220
221void
222ScreenBlanker::MessageReceived(BMessage* message)
223{
224	switch (message->what) {
225		case kMsgUnlock:
226		{
227			if (strcmp(fSettings.Password(), crypt(fPasswordWindow->Password(),
228					fSettings.Password())) != 0) {
229				beep();
230				fPasswordWindow->SetPassword("");
231				_QueueResumeScreenSaver();
232			} else  {
233				PRINT(("Quitting!\n"));
234				_Shutdown();
235				Quit();
236			}
237			break;
238		}
239
240		case kMsgResumeSaver:
241		{
242			if (fWindow->Lock()) {
243				HideCursor();
244				fPasswordWindow->SetPassword("");
245				fPasswordWindow->Hide();
246
247				fSaverRunner->Resume();
248				fWindow->Unlock();
249			}
250
251			// Turn on the message filter again
252			BMessage enable(kMsgEnableFilter);
253			fWindow->PostMessage(&enable);
254
255			_QueueTurnOffScreen();
256			break;
257		}
258
259		case kMsgTurnOffScreen:
260			_SetDPMSMode(B_DPMS_OFF);
261			break;
262
263		case kMsgSuspendScreen:
264			_SetDPMSMode(B_DPMS_SUSPEND);
265			break;
266
267		case kMsgStandByScreen:
268			_SetDPMSMode(B_DPMS_STAND_BY);
269			break;
270
271		case kMsgTestSaver:
272			fTestSaver = true;
273			break;
274
275		default:
276			BApplication::MessageReceived(message);
277	}
278}
279
280
281bool
282ScreenBlanker::QuitRequested()
283{
284	if (fSettings.LockEnable()) {
285		bigtime_t minTime = fSettings.PasswordTime() - fSettings.BlankTime();
286		if (minTime == 0)
287			minTime = 5000000;
288		if (system_time() - fBlankTime > minTime) {
289			_ShowPasswordWindow();
290			return false;
291		}
292	}
293
294	_Shutdown();
295	return true;
296}
297
298
299bool
300ScreenBlanker::IsPasswordWindowShown() const
301{
302	return fPasswordWindow != NULL && !fPasswordWindow->IsHidden();
303}
304
305
306void
307ScreenBlanker::_Shutdown()
308{
309	if (fWindow != NULL) {
310		fWindow->Hide();
311
312		if (fWindow->Lock())
313			fWindow->Quit();
314	}
315
316	delete fSaverRunner;
317	fSaverRunner = NULL;
318}
319
320
321//	#pragma mark - main
322
323
324int
325main(int argc, char** argv)
326{
327	ScreenBlanker app;
328	app.Run();
329
330	return 0;
331}
332