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