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