xref: /haiku/src/preferences/screensaver/ScreenSaverWindow.cpp (revision 9bf8dbc8290a520b6f7c09ec2c93e4f9a746ab8a)
1 /*
2  * Copyright 2003-2006, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Phipps
7  *		Jérôme Duval, jerome.duval@free.fr
8  *		Axel Dörfler, axeld@pinc-software.de
9  */
10 
11 
12 #include "MouseAreaView.h"
13 #include "PreviewView.h"
14 #include "ScreenSaverItem.h"
15 #include "ScreenSaverWindow.h"
16 
17 #include <Application.h>
18 #include <Box.h>
19 #include <Button.h>
20 #include <Directory.h>
21 #include <Entry.h>
22 #include <File.h>
23 #include <FindDirectory.h>
24 #include <Font.h>
25 #include <ListView.h>
26 #include <Path.h>
27 #include <Roster.h>
28 #include <Screen.h>
29 #include <ScreenSaver.h>
30 #include <ScrollView.h>
31 #include <Slider.h>
32 #include <StringView.h>
33 #include <TabView.h>
34 
35 #include <stdio.h>
36 
37 #include <Debug.h>
38 #define CALLED() PRINT(("%s\n", __PRETTY_FUNCTION__))
39 
40 
41 const uint32 kPreviewMonitorGap = 16;
42 const uint32 kMinSettingsWidth = 230;
43 const uint32 kMinSettingsHeight = 120;
44 
45 const int32 kMsgSaverSelected = 'SSEL';
46 const int32 kMsgTestSaver = 'TEST';
47 const int32 kMsgAddSaver = 'ADD ';
48 const int32 kMsgPasswordCheckBox = 'PWCB';
49 const int32 kMsgRunSliderChanged = 'RSCG';
50 const int32 kMsgPasswordSliderChanged = 'PWCG';
51 const int32 kMsgChangePassword = 'PWBT';
52 const int32 kMsgEnableScreenSaverBox = 'ESCH';
53 
54 const int32 kMsgTurnOffCheckBox = 'TUOF';
55 const int32 kMsgTurnOffSliderChanged = 'TUCG';
56 
57 static const uint32 kTimeSliderChanged = 'tsch';
58 
59 class TimeSlider : public BSlider {
60 	public:
61 		TimeSlider(BRect frame, const char* name, uint32 modificationMessage);
62 		virtual ~TimeSlider();
63 
64 		virtual void AttachedToWindow();
65 		virtual void MessageReceived(BMessage* message);
66 		virtual void SetValue(int32 value);
67 
68 		void SetTime(bigtime_t useconds);
69 		bigtime_t Time();
70 
71 	private:
72 		void _TimeToString(bigtime_t useconds, BString& string);
73 
74 		uint32	fModificationMessage;
75 };
76 
77 class FadeView : public BView {
78 	public:
79 		FadeView(BRect frame, const char* name, ScreenSaverPrefs& prefs);
80 
81 		virtual void AttachedToWindow();
82 };
83 
84 class ModulesView : public BView {
85 	public:
86 		ModulesView(BRect frame, const char* name, ScreenSaverPrefs& prefs);
87 		virtual ~ModulesView();
88 
89 		virtual void DetachedFromWindow();
90 		virtual void AttachedToWindow();
91 		virtual void AllAttached();
92 		virtual void MessageReceived(BMessage* message);
93 
94 		void PopulateScreenSaverList();
95 		void SaveState();
96 
97 	private:
98 		static int _CompareScreenSaverItems(const void* left, const void* right);
99 		BScreenSaver* _ScreenSaver();
100 		void _CloseSaver();
101 		void _OpenSaver();
102 
103 		BFilePanel*		fFilePanel;
104 		BListView*		fListView;
105 		BButton*		fTestButton;
106 		BButton*		fAddButton;
107 
108 		ScreenSaverPrefs& fPrefs;
109 		ScreenSaverRunner* fSaverRunner;
110 		BString			fCurrentName;
111 
112 		BBox*			fSettingsBox;
113 		BView*			fSettingsView;
114 
115 		PreviewView*	fPreviewView;
116 };
117 
118 static const int32 kTimeInUnits[] = {
119 	30,    60,   90,
120 	120,   150,  180,
121 	240,   300,  360,
122 	420,   480,  540,
123 	600,   900,  1200,
124 	1500,  1800, 2400,
125 	3000,  3600, 5400,
126 	7200,  9000, 10800,
127 	14400, 18000
128 };
129 static const int32 kTimeUnitCount = sizeof(kTimeInUnits) / sizeof(kTimeInUnits[0]);
130 
131 
132 TimeSlider::TimeSlider(BRect frame, const char* name, uint32 modificationMessage)
133 	: BSlider(frame, name, "0 minutes", new BMessage(kTimeSliderChanged),
134 		0, kTimeUnitCount - 1, B_TRIANGLE_THUMB, B_FOLLOW_LEFT_RIGHT),
135 	fModificationMessage(modificationMessage)
136 {
137 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
138 	SetModificationMessage(new BMessage(kTimeSliderChanged));
139 	SetBarThickness(10);
140 }
141 
142 
143 TimeSlider::~TimeSlider()
144 {
145 }
146 
147 
148 void
149 TimeSlider::AttachedToWindow()
150 {
151 	SetTarget(this);
152 }
153 
154 
155 void
156 TimeSlider::MessageReceived(BMessage* message)
157 {
158 	switch (message->what) {
159 		case kTimeSliderChanged:
160 			Window()->PostMessage(fModificationMessage);
161 			break;
162 
163 		default:
164 			BSlider::MessageReceived(message);
165 	}
166 }
167 
168 
169 void
170 TimeSlider::SetValue(int32 value)
171 {
172 	int32 oldValue = Value();
173 	BSlider::SetValue(value);
174 
175 	if (oldValue != Value()) {
176 		BString label;
177 		_TimeToString(kTimeInUnits[Value()] * 1000000LL, label);
178 		SetLabel(label.String());
179 	}
180 }
181 
182 
183 void
184 TimeSlider::SetTime(bigtime_t useconds)
185 {
186 	for (int t = 0; t < kTimeUnitCount; t++) {
187 		if (kTimeInUnits[t] * 1000000LL == useconds) {
188 			SetValue(t);
189 			break;
190 		}
191 	}
192 }
193 
194 
195 bigtime_t
196 TimeSlider::Time()
197 {
198 	return 1000000LL * kTimeInUnits[Value()];
199 }
200 
201 
202 void
203 TimeSlider::_TimeToString(bigtime_t useconds, BString& string)
204 {
205 	useconds /= 1000000LL;
206 		// convert to seconds
207 
208 	string = "";
209 
210 	// hours
211 	uint32 hours = useconds / 3600;
212 	if (hours != 0)
213 		string << hours << " hours";
214 
215 	useconds %= 3600;
216 
217 	// minutes
218 	uint32 minutes = useconds / 60;
219 	if (hours != 0)
220 		string << " ";
221 	if (minutes != 0)
222 		string << minutes << " minutes";
223 
224 	useconds %= 60;
225 
226 	// seconds
227 	uint32 seconds = useconds / 60;
228 	if (hours != 0 || minutes != 0)
229 		string << " ";
230 	if (seconds != 0)
231 		string << seconds << " seconds";
232 }
233 
234 
235 //	#pragma mark -
236 
237 
238 FadeView::FadeView(BRect rect, const char* name, ScreenSaverPrefs& prefs)
239 	: BView(rect, name, B_FOLLOW_ALL, B_WILL_DRAW)
240 {
241 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
242 }
243 
244 
245 void
246 FadeView::AttachedToWindow()
247 {
248 	if (Parent() != NULL) {
249 		// We adopt the size of our parent view (in case the window
250 		// was resized during our absence (BTabView...)
251 		ResizeTo(Parent()->Bounds().Width(), Parent()->Bounds().Height());
252 	}
253 }
254 
255 
256 //	#pragma mark -
257 
258 
259 ModulesView::ModulesView(BRect rect, const char* name, ScreenSaverPrefs& prefs)
260 	: BView(rect, name, B_FOLLOW_ALL, B_WILL_DRAW),
261 	fPrefs(prefs),
262 	fSaverRunner(NULL),
263 	fSettingsView(NULL)
264 {
265 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
266 
267 	fTestButton = new BButton(rect, "TestButton", "Test", new BMessage(kMsgTestSaver),
268 		B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
269 	float width, height;
270 	fTestButton->GetPreferredSize(&width, &height);
271 	fTestButton->ResizeTo(width + 16, height);
272 	fTestButton->MoveTo(8, rect.bottom - 8 - height);
273 	AddChild(fTestButton);
274 
275 	rect = fTestButton->Frame();
276 	rect.OffsetBy(fTestButton->Bounds().Width() + 8, 0);
277 	fAddButton = new BButton(rect, "AddButton", "Add" B_UTF8_ELLIPSIS,
278 		new BMessage(kMsgAddSaver), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
279 	AddChild(fAddButton);
280 
281 	rect = Bounds().InsetByCopy(8 + kPreviewMonitorGap, 12);
282 	rect.right = fAddButton->Frame().right - kPreviewMonitorGap;
283 	rect.bottom = rect.top + 3 * rect.Width() / 4;
284 		// 4:3 monitor
285 
286 	fPreviewView = new PreviewView(rect, "preview");
287 	AddChild(fPreviewView);
288 
289 	rect.left = 8;
290 	rect.right -= B_V_SCROLL_BAR_WIDTH + 2 - kPreviewMonitorGap;
291 		// scroll view border
292 	rect.top = rect.bottom + 14;
293 	rect.bottom = fTestButton->Frame().top - 10;
294 	fListView = new BListView(rect, "SaversListView", B_SINGLE_SELECTION_LIST,
295 		B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM);
296 	fListView->SetSelectionMessage(new BMessage(kMsgSaverSelected));
297 	AddChild(new BScrollView("scroll_list", fListView,
298 		B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM, 0, false, true));
299 
300 	rect = Bounds().InsetByCopy(8, 8);
301 	rect.left = fAddButton->Frame().right + 8;
302 	AddChild(fSettingsBox = new BBox(rect, "SettingsBox", B_FOLLOW_ALL, B_WILL_DRAW));
303 	fSettingsBox->SetLabel("Module settings");
304 
305 	PopulateScreenSaverList();
306 	fFilePanel = new BFilePanel();
307 }
308 
309 
310 ModulesView::~ModulesView()
311 {
312 	delete fFilePanel;
313 }
314 
315 
316 void
317 ModulesView::DetachedFromWindow()
318 {
319 	_CloseSaver();
320 }
321 
322 
323 void
324 ModulesView::AttachedToWindow()
325 {
326 	if (Parent() != NULL) {
327 		// We adopt the size of our parent view (in case the window
328 		// was resized during our absence (BTabView...)
329 		ResizeTo(Parent()->Bounds().Width(), Parent()->Bounds().Height());
330 	}
331 
332 	_OpenSaver();
333 
334 	fListView->SetTarget(this);
335 	fTestButton->SetTarget(this);
336 	fAddButton->SetTarget(this);
337 }
338 
339 
340 void
341 ModulesView::AllAttached()
342 {
343 	// This only works after the view has been attached
344 	fListView->ScrollToSelection();
345 }
346 
347 
348 void
349 ModulesView::MessageReceived(BMessage* message)
350 {
351 	switch (message->what) {
352 		case kMsgSaverSelected:
353 		{
354 			int selection = fListView->CurrentSelection();
355 			if (selection < 0)
356 				break;
357 
358 			ScreenSaverItem* item = (ScreenSaverItem *)fListView->ItemAt(selection);
359 			if (item == NULL)
360 				break;
361 
362 			if (!strcmp(item->Text(), "Blackness"))
363 				fPrefs.SetModuleName("");
364 			else
365 				fPrefs.SetModuleName(item->Text());
366 
367 			_CloseSaver();
368 			_OpenSaver();
369 			break;
370 		}
371 
372 		case kMsgTestSaver:
373 			SaveState();
374 			fPrefs.SaveSettings();
375 
376 			be_roster->Launch(SCREEN_BLANKER_SIG, &fPrefs.GetSettings());
377 			break;
378 
379 		case kMsgAddSaver:
380 			fFilePanel->Show();
381 			break;
382 
383 		default:
384 			BView::MessageReceived(message);
385 	}
386 }
387 
388 
389 void
390 ModulesView::SaveState()
391 {
392 	BScreenSaver* saver = _ScreenSaver();
393 	if (saver == NULL)
394 		return;
395 
396 	BMessage state;
397 	if (saver->SaveState(&state) == B_OK)
398 		fPrefs.SetState(fCurrentName.String(), &state);
399 }
400 
401 
402 void
403 ModulesView::PopulateScreenSaverList()
404 {
405  	fListView->DeselectAll();
406 	while (ScreenSaverItem* item = (ScreenSaverItem *)fListView->RemoveItem((int32)0)) {
407 		delete item;
408 	}
409 
410 	// Blackness is a built-in screen saver
411 	fListView->AddItem(new ScreenSaverItem("Blackness", ""));
412 
413 	// Iterate over add-on directories, and add their files to the list view
414 
415 	directory_which which[] = {B_BEOS_ADDONS_DIRECTORY, B_USER_ADDONS_DIRECTORY};
416 	ScreenSaverItem* selectItem = NULL;
417 
418 	for (uint32 i = 0; i < sizeof(which) / sizeof(which[0]); i++) {
419 		BPath basePath;
420 		find_directory(which[i], &basePath);
421 		basePath.Append("Screen Savers", true);
422 
423 		BDirectory dir(basePath.Path());
424 		BEntry entry;
425 		while (dir.GetNextEntry(&entry, true) == B_OK) {
426 			char name[B_FILE_NAME_LENGTH];
427 			if (entry.GetName(name) != B_OK)
428 				continue;
429 
430 			BPath path = basePath;
431 			path.Append(name);
432 
433 			ScreenSaverItem* item = new ScreenSaverItem(name, path.Path());
434 			fListView->AddItem(item);
435 
436 			if (!strcmp(fPrefs.ModuleName(), item->Text())
437 				|| (!strcmp(fPrefs.ModuleName(), "")
438 					&& !strcmp(item->Text(), "Blackness")))
439 				selectItem = item;
440 		}
441 	}
442 
443 	fListView->SortItems(_CompareScreenSaverItems);
444 
445 	fListView->Select(fListView->IndexOf(selectItem));
446 	fListView->ScrollToSelection();
447 }
448 
449 
450 //! sorting function for ScreenSaverItems
451 int
452 ModulesView::_CompareScreenSaverItems(const void* left, const void* right)
453 {
454 	ScreenSaverItem* leftItem  = *(ScreenSaverItem **)left;
455 	ScreenSaverItem* rightItem = *(ScreenSaverItem **)right;
456 
457 	return strcmp(leftItem->Text(), rightItem->Text());
458 }
459 
460 
461 BScreenSaver*
462 ModulesView::_ScreenSaver()
463 {
464 	if (fSaverRunner != NULL)
465 		return fSaverRunner->ScreenSaver();
466 
467 	return NULL;
468 }
469 
470 
471 void
472 ModulesView::_CloseSaver()
473 {
474 	// remove old screen saver preview & config
475 
476 	BScreenSaver* saver = _ScreenSaver();
477 	BView* view = fPreviewView->RemovePreview();
478 	if (fSettingsView != NULL)
479 		fSettingsBox->RemoveChild(fSettingsView);
480 
481 	if (saver != NULL)
482 		saver->StopConfig();
483 
484 	SaveState();
485 
486 	delete view;
487 	delete fSettingsView;
488 	delete fSaverRunner;
489 
490 	fSettingsView = NULL;
491 	fSaverRunner = NULL;
492 }
493 
494 
495 void
496 ModulesView::_OpenSaver()
497 {
498 	// create new screen saver preview & config
499 
500    	BView* view = fPreviewView->AddPreview();
501 	fCurrentName = fPrefs.ModuleName();
502 	fSaverRunner = new ScreenSaverRunner(Window(), view, true, fPrefs);
503 	BScreenSaver* saver = _ScreenSaver();
504 
505 	BRect rect = fSettingsBox->Bounds().InsetByCopy(4, 4);
506 #ifdef __HAIKU__
507 	rect.top += fSettingsBox->TopBorderOffset();
508 #else
509 	rect.top += 14;
510 #endif
511 	fSettingsView = new BView(rect, "SettingsView", B_FOLLOW_ALL, B_WILL_DRAW);
512 	fSettingsView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
513 	fSettingsBox->AddChild(fSettingsView);
514 
515 	if (saver != NULL) {
516 		fSaverRunner->Run();
517 		saver->StartConfig(fSettingsView);
518 	}
519 
520 	if (fSettingsView->ChildAt(0) == NULL) {
521 		// There are no settings at all, we add the module name here to
522 		// let it look a bit better at least.
523 		rect = BRect(15, 15, 20, 20);
524 		BStringView* stringView = new BStringView(rect, "module", fPrefs.ModuleName()[0]
525 			? fPrefs.ModuleName() : "Blackness");
526 		stringView->SetFont(be_bold_font);
527 		stringView->ResizeToPreferred();
528 		fSettingsView->AddChild(stringView);
529 
530 		rect.OffsetBy(0, stringView->Bounds().Height() + 4);
531 		stringView = new BStringView(rect, "info", saver || !fPrefs.ModuleName()[0]
532 			? "No options available" : "Could not load screen saver");
533 		stringView->ResizeToPreferred();
534 		fSettingsView->AddChild(stringView);
535 	}
536 
537 	ScreenSaverWindow* window = dynamic_cast<ScreenSaverWindow*>(Window());
538 	if (window == NULL)
539 		return;
540 
541 	// find the minimal size of the settings view
542 
543 	float right = 0, bottom = 0;
544 	int32 i = 0;
545 	while ((view = fSettingsView->ChildAt(i++)) != NULL) {
546 		// very simple heuristic...
547 		float viewRight = view->Frame().right;
548 		if ((view->ResizingMode() & _rule_(0, 0xf, 0, 0xf)) == B_FOLLOW_LEFT_RIGHT) {
549 			float width, height;
550 			view->GetPreferredSize(&width, &height);
551 			viewRight = view->Frame().left + width / 2;
552 		} else if ((view->ResizingMode() & _rule_(0, 0xf, 0, 0xf)) == B_FOLLOW_RIGHT)
553 			viewRight = 8 + view->Frame().Width();
554 
555 		float viewBottom = view->Frame().bottom;
556 		if ((view->ResizingMode() & _rule_(0xf, 0, 0xf, 0)) == B_FOLLOW_TOP_BOTTOM) {
557 			float width, height;
558 			view->GetPreferredSize(&width, &height);
559 			viewBottom = view->Frame().top + height;
560 		} else if ((view->ResizingMode() & _rule_(0xf, 0, 0xf, 0)) == B_FOLLOW_BOTTOM)
561 			viewBottom = 8 + view->Frame().Height();
562 
563 		if (viewRight > right)
564 			right = viewRight;
565 		if (viewBottom > bottom)
566 			bottom = viewBottom;
567 	}
568 
569 	if (right < kMinSettingsWidth)
570 		right = kMinSettingsWidth;
571 	if (bottom < kMinSettingsHeight)
572 		bottom = kMinSettingsHeight;
573 
574 	BPoint leftTop = fSettingsView->LeftTop();
575 	fSettingsView->ConvertToScreen(&leftTop);
576 	window->ConvertFromScreen(&leftTop);
577 	window->SetMinimalSizeLimit(leftTop.x + right + 16,
578 		leftTop.y + bottom + 16);
579 }
580 
581 
582 //	#pragma mark -
583 
584 
585 ScreenSaverWindow::ScreenSaverWindow()
586 	: BWindow(BRect(50, 50, 496, 375), "Screen Saver",
587 		B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS /*| B_NOT_ZOOMABLE | B_NOT_RESIZABLE*/),
588 	fFadeNowString(NULL),
589 	fFadeNowString2(NULL),
590 	fDontFadeString(NULL),
591 	fDontFadeString2(NULL),
592 	fFadeNow(NULL),
593 	fFadeNever(NULL)
594 {
595 	fPrefs.LoadSettings();
596 
597 	BRect rect = Bounds();
598 
599 	// Create a background view
600 	BView *background = new BView(rect, "background", B_FOLLOW_ALL, 0);
601 	background->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
602 	AddChild(background);
603 
604 	// Add the tab view to the background
605 	rect.top += 4;
606 	fTabView = new BTabView(rect, "tab_view");
607 
608 	// Create the controls inside the tabs
609 	rect = fTabView->ContainerView()->Bounds();
610 	_SetupFadeTab(rect);
611 	fModulesView = new ModulesView(rect, "Modules", fPrefs);
612 
613 	fTabView->AddTab(fFadeView);
614 	fTabView->AddTab(fModulesView);
615 	background->AddChild(fTabView);
616 
617 	// Create the password editing window
618 	fPasswordWindow = new PasswordWindow(fPrefs);
619 	fPasswordWindow->Run();
620 
621 	// TODO: better limits!
622 	fMinWidth = 430;
623 	fMinHeight = 325;
624 	SetMinimalSizeLimit(fMinWidth, fMinHeight);
625 	MoveTo(fPrefs.WindowFrame().left, fPrefs.WindowFrame().top);
626 	ResizeTo(fPrefs.WindowFrame().Width(), fPrefs.WindowFrame().Height());
627 
628 	fEnableCheckBox->SetValue(fPrefs.TimeFlags() & ENABLE_SAVER ? B_CONTROL_ON : B_CONTROL_OFF);
629 	fRunSlider->SetTime(fPrefs.BlankTime());
630 	fTurnOffSlider->SetTime(fPrefs.OffTime() + fPrefs.BlankTime());
631 	fFadeNow->SetCorner(fPrefs.GetBlankCorner());
632 	fFadeNever->SetCorner(fPrefs.GetNeverBlankCorner());
633 	fPasswordCheckBox->SetValue(fPrefs.LockEnable());
634 	fPasswordSlider->SetTime(fPrefs.PasswordTime());
635 
636 	fTabView->Select(fPrefs.WindowTab());
637 
638 	_UpdateTurnOffScreen();
639 	_UpdateStatus();
640 }
641 
642 
643 ScreenSaverWindow::~ScreenSaverWindow()
644 {
645 }
646 
647 
648 //! Create the controls for the fade tab
649 void
650 ScreenSaverWindow::_SetupFadeTab(BRect rect)
651 {
652 	fFadeView = new FadeView(rect, "Fade", fPrefs);
653 
654 /*
655 	font_height fontHeight;
656 	be_plain_font->GetHeight(&fontHeight);
657 	float lineHeight = ceilf(fontHeight.ascent + fontHeight.descent);
658 */
659 	fEnableCheckBox = new BCheckBox(BRect(0, 0, 1, 1), "EnableCheckBox",
660 		"Enable Screen Saver", new BMessage(kMsgEnableScreenSaverBox));
661 	fEnableCheckBox->ResizeToPreferred();
662 
663 	rect.InsetBy(8, 8);
664 	BBox* box = new BBox(rect, "EnableScreenSaverBox", B_FOLLOW_ALL);
665 	box->SetLabel(fEnableCheckBox);
666 	fFadeView->AddChild(box);
667 
668 	// Run Module
669 	rect.top = fEnableCheckBox->Bounds().bottom + 8.0f;
670 	BStringView* stringView = new BStringView(rect, NULL, "Run module");
671 	stringView->ResizeToPreferred();
672 	box->AddChild(stringView);
673 
674 	float topEdge = rect.top;
675 	fRunSlider = new TimeSlider(BRect(135, topEdge, 420, topEdge + 20),
676 		"RunSlider", kMsgRunSliderChanged);
677 	float width, height;
678 	fRunSlider->GetPreferredSize(&width, &height);
679 	fRunSlider->ResizeTo(fRunSlider->Bounds().Width(), height);
680 	box->AddChild(fRunSlider);
681 
682 	// Turn Off
683 	topEdge += fRunSlider->Bounds().Height() + 4.0f;
684 	fTurnOffCheckBox = new BCheckBox(BRect(20, topEdge-2, 127, topEdge + 20),
685 		"TurnOffScreenCheckBox", "Turn off screen", new BMessage(kMsgTurnOffCheckBox));
686 	fTurnOffCheckBox->ResizeToPreferred();
687 	box->AddChild(fTurnOffCheckBox);
688 
689 	fTurnOffSlider = new TimeSlider(BRect(135, topEdge, 420, topEdge + 20),
690 		"TurnOffSlider", kMsgTurnOffSliderChanged);
691 	fTurnOffSlider->ResizeTo(fTurnOffSlider->Bounds().Width(), height);
692 	box->AddChild(fTurnOffSlider);
693 
694 	// Password
695 	topEdge += fTurnOffSlider->Bounds().Height() + 4.0f;
696 	fPasswordCheckBox = new BCheckBox(BRect(20, topEdge - 2, 127, topEdge + 20),
697 		"PasswordCheckbox", "Password lock", new BMessage(kMsgPasswordCheckBox));
698 	fPasswordCheckBox->ResizeToPreferred();
699 	box->AddChild(fPasswordCheckBox);
700 
701 	fPasswordSlider = new TimeSlider(BRect(135, topEdge, 420, topEdge + 20),
702 		"PasswordSlider", kMsgPasswordSliderChanged);
703 	fPasswordSlider->ResizeTo(fPasswordSlider->Bounds().Width(), height);
704 	box->AddChild(fPasswordSlider);
705 
706 	topEdge += fPasswordSlider->Bounds().Height() + 4.0f;
707 	fPasswordButton = new BButton(BRect(390, topEdge, 410, topEdge + 24), "PasswordButton",
708 		"Password" B_UTF8_ELLIPSIS, new BMessage(kMsgChangePassword));
709 	fPasswordButton->ResizeToPreferred();
710 	fPasswordButton->MoveBy(-fPasswordButton->Bounds().Width(), 0);
711 	box->AddChild(fPasswordButton);
712 
713 	// Bottom
714 
715 	box->AddChild(fFadeNow = new MouseAreaView(BRect(20,205,80,260),"fadeNow"));
716 	box->AddChild(fFadeNever = new MouseAreaView(BRect(220,205,280,260),"fadeNever"));
717 
718 	box->AddChild(fFadeNowString = new BStringView(BRect(90,215,193,230),"FadeNowString","Fade now when"));
719 	fFadeNowString->SetText("Fade now when");
720 	fFadeNowString->SetAlignment(B_ALIGN_LEFT);
721 
722 	box->AddChild(fFadeNowString2 = new BStringView(BRect(90,233,193,248),"FadeNowString2","mouse is here"));
723 	fFadeNowString2->SetText("mouse is here");
724 	fFadeNowString2->SetAlignment(B_ALIGN_LEFT);
725 
726 	box->AddChild(fDontFadeString = new BStringView(BRect(290,215,387,230),"DontFadeString","Don't fade when"));
727 	fDontFadeString->SetText("Don't fade when");
728 	fDontFadeString->SetAlignment(B_ALIGN_LEFT);
729 
730 	box->AddChild(fDontFadeString2 = new BStringView(BRect(290,233,387,248),"DontFadeString2","mouse is here"));
731 	fDontFadeString2->SetText("mouse is here");
732 	fDontFadeString2->SetAlignment(B_ALIGN_LEFT);
733 }
734 
735 
736 void
737 ScreenSaverWindow::_UpdateTurnOffScreen()
738 {
739 	bool enabled = (fPrefs.TimeFlags() & ENABLE_DPMS_MASK) != 0;
740 
741 	BScreen screen(this);
742 	uint32 dpmsCapabilities = screen.DPMSCapabilites();
743 
744 	fTurnOffScreenFlags = 0;
745 	if (dpmsCapabilities & B_DPMS_OFF)
746 		fTurnOffScreenFlags |= ENABLE_DPMS_OFF;
747 	if (dpmsCapabilities & B_DPMS_STAND_BY)
748 		fTurnOffScreenFlags |= ENABLE_DPMS_STAND_BY;
749 	if (dpmsCapabilities & B_DPMS_SUSPEND)
750 		fTurnOffScreenFlags |= ENABLE_DPMS_SUSPEND;
751 
752 	fTurnOffCheckBox->SetValue(enabled && fTurnOffScreenFlags != 0
753 		? B_CONTROL_ON : B_CONTROL_OFF);
754 }
755 
756 
757 void
758 ScreenSaverWindow::_UpdateStatus()
759 {
760 	DisableUpdates();
761 
762 	bool enabled = fEnableCheckBox->Value() == B_CONTROL_ON;
763 	fPasswordCheckBox->SetEnabled(enabled);
764 	fTurnOffCheckBox->SetEnabled(enabled && fTurnOffScreenFlags != 0);
765 	fRunSlider->SetEnabled(enabled);
766 	fTurnOffSlider->SetEnabled(enabled && fTurnOffCheckBox->Value());
767 	fPasswordSlider->SetEnabled(enabled && fPasswordCheckBox->Value());
768 	fPasswordButton->SetEnabled(enabled && fPasswordCheckBox->Value());
769 
770 	EnableUpdates();
771 
772 	// Update the saved preferences
773 	fPrefs.SetWindowFrame(Frame());
774 	fPrefs.SetWindowTab(fTabView->Selection());
775 	fPrefs.SetTimeFlags((enabled ? ENABLE_SAVER : 0)
776 		| (fTurnOffCheckBox->Value() ? fTurnOffScreenFlags : 0));
777 	fPrefs.SetBlankTime(fRunSlider->Time());
778 	bigtime_t offTime = fTurnOffSlider->Time() - fPrefs.BlankTime();
779 	fPrefs.SetOffTime(offTime);
780 	fPrefs.SetSuspendTime(offTime);
781 	fPrefs.SetStandbyTime(offTime);
782 	fPrefs.SetBlankCorner(fFadeNow->Corner());
783 	fPrefs.SetNeverBlankCorner(fFadeNever->Corner());
784 	fPrefs.SetLockEnable(fPasswordCheckBox->Value());
785 	fPrefs.SetPasswordTime(fPasswordSlider->Time());
786 
787 	// TODO - Tell the password window to update its stuff
788 }
789 
790 
791 void
792 ScreenSaverWindow::SetMinimalSizeLimit(float width, float height)
793 {
794 	if (width < fMinWidth)
795 		width = fMinWidth;
796 	if (height < fMinHeight)
797 		height = fMinHeight;
798 
799 	SetSizeLimits(width, 32767, height, 32767);
800 }
801 
802 
803 void
804 ScreenSaverWindow::MessageReceived(BMessage *msg)
805 {
806 	switch (msg->what) {
807 		// "Fade" tab
808 
809 		case kMsgRunSliderChanged:
810 			if (fRunSlider->Value() > fTurnOffSlider->Value())
811 				fTurnOffSlider->SetValue(fRunSlider->Value());
812 
813 			if (fRunSlider->Value() > fPasswordSlider->Value())
814 				fPasswordSlider->SetValue(fRunSlider->Value());
815 			break;
816 
817 		case kMsgTurnOffCheckBox:
818 			fTurnOffSlider->SetEnabled(fTurnOffCheckBox->Value() == B_CONTROL_ON);
819 			break;
820 
821 		case kMsgTurnOffSliderChanged:
822 			if (fRunSlider->Value() > fTurnOffSlider->Value())
823 				fRunSlider->SetValue(fTurnOffSlider->Value());
824 			break;
825 
826 		case kMsgPasswordSliderChanged:
827 			if (fPasswordSlider->Value() < fRunSlider->Value())
828 				fRunSlider->SetValue(fPasswordSlider->Value());
829 			break;
830 
831 		case kMsgPasswordCheckBox:
832 		case kMsgEnableScreenSaverBox:
833 			_UpdateStatus();
834 			break;
835 
836 		case kMsgChangePassword:
837 			fPasswordWindow->Show();
838 			break;
839 
840 		// "Modules" tab
841 
842 		case kMsgUpdateList:
843 			fModulesView->PopulateScreenSaverList();
844 			break;
845   	}
846 	BWindow::MessageReceived(msg);
847 }
848 
849 
850 void
851 ScreenSaverWindow::ScreenChanged(BRect frame, color_space colorSpace)
852 {
853 	_UpdateTurnOffScreen();
854 }
855 
856 
857 bool
858 ScreenSaverWindow::QuitRequested()
859 {
860 	_UpdateStatus();
861 	fModulesView->SaveState();
862 	fPrefs.SaveSettings();
863 
864 	be_app->PostMessage(B_QUIT_REQUESTED);
865 	return true;
866 }
867 
868