xref: /haiku/src/preferences/screensaver/ScreenSaverWindow.cpp (revision 7c434cc5a0eaecd399a0c490b6d7b3d4a4635529)
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 #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, 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 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;
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, ScreenSaverSettings& settings)
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, ScreenSaverSettings& settings)
260 	: BView(rect, name, B_FOLLOW_ALL, B_WILL_DRAW),
261 	fSettings(settings),
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 				fSettings.SetModuleName("");
364 			else
365 				fSettings.SetModuleName(item->Text());
366 
367 			_CloseSaver();
368 			_OpenSaver();
369 			break;
370 		}
371 
372 		case kMsgTestSaver:
373 			SaveState();
374 			fSettings.SaveSettings();
375 
376 			be_roster->Launch(SCREEN_BLANKER_SIG, &fSettings.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 		fSettings.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(fSettings.ModuleName(), item->Text())
437 				|| (!strcmp(fSettings.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 = fSettings.ModuleName();
502 	fSaverRunner = new ScreenSaverRunner(Window(), view, true, fSettings);
503 	BScreenSaver* saver = _ScreenSaver();
504 
505 #ifdef __HAIKU__
506 	BRect rect = fSettingsBox->InnerFrame().InsetByCopy(4, 4);
507 #else
508 	BRect rect = fSettingsBox->Bounds().InsetByCopy(4, 4);
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", fSettings.ModuleName()[0]
525 			? fSettings.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 || !fSettings.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 {
589 	fSettings.LoadSettings();
590 
591 	BRect rect = Bounds();
592 
593 	// Create a background view
594 	BView *background = new BView(rect, "background", B_FOLLOW_ALL, 0);
595 	background->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
596 	AddChild(background);
597 
598 	// Add the tab view to the background
599 	rect.top += 4;
600 	fTabView = new BTabView(rect, "tab_view");
601 
602 	// Create the controls inside the tabs
603 	rect = fTabView->ContainerView()->Bounds();
604 	_SetupFadeTab(rect);
605 	fModulesView = new ModulesView(rect, "Modules", fSettings);
606 
607 	fTabView->AddTab(fFadeView);
608 	fTabView->AddTab(fModulesView);
609 	background->AddChild(fTabView);
610 
611 	// Create the password editing window
612 	fPasswordWindow = new PasswordWindow(fSettings);
613 	fPasswordWindow->Run();
614 
615 	// TODO: better limits!
616 	fMinWidth = 430;
617 	fMinHeight = 325;
618 	SetMinimalSizeLimit(fMinWidth, fMinHeight);
619 	MoveTo(fSettings.WindowFrame().left, fSettings.WindowFrame().top);
620 	ResizeTo(fSettings.WindowFrame().Width(), fSettings.WindowFrame().Height());
621 
622 	fEnableCheckBox->SetValue(fSettings.TimeFlags() & ENABLE_SAVER ? B_CONTROL_ON : B_CONTROL_OFF);
623 	fRunSlider->SetTime(fSettings.BlankTime());
624 	fTurnOffSlider->SetTime(fSettings.OffTime() + fSettings.BlankTime());
625 	fFadeNow->SetCorner(fSettings.GetBlankCorner());
626 	fFadeNever->SetCorner(fSettings.GetNeverBlankCorner());
627 	fPasswordCheckBox->SetValue(fSettings.LockEnable());
628 	fPasswordSlider->SetTime(fSettings.PasswordTime());
629 
630 	fTabView->Select(fSettings.WindowTab());
631 
632 	_UpdateTurnOffScreen();
633 	_UpdateStatus();
634 }
635 
636 
637 ScreenSaverWindow::~ScreenSaverWindow()
638 {
639 }
640 
641 
642 //! Create the controls for the fade tab
643 void
644 ScreenSaverWindow::_SetupFadeTab(BRect rect)
645 {
646 	fFadeView = new FadeView(rect, "Fade", fSettings);
647 
648 	float labelWidth = be_plain_font->StringWidth("Turn off screen") + 20.0f;
649 
650 	font_height fontHeight;
651 	be_plain_font->GetHeight(&fontHeight);
652 	float textHeight = ceilf(fontHeight.ascent + fontHeight.descent);
653 
654 	// taken from BRadioButton:
655 	float radioButtonOffset = 2 * floorf(textHeight / 2 - 2) + floorf(textHeight / 2);
656 
657 	fEnableCheckBox = new BCheckBox(BRect(0, 0, 1, 1), "EnableCheckBox",
658 		"Enable Screen Saver", new BMessage(kMsgEnableScreenSaverBox));
659 	fEnableCheckBox->ResizeToPreferred();
660 
661 	rect.InsetBy(8, 8);
662 	BBox* box = new BBox(rect, "EnableScreenSaverBox", B_FOLLOW_ALL);
663 	box->SetLabel(fEnableCheckBox);
664 	fFadeView->AddChild(box);
665 
666 	// Run Module
667 	rect.left += radioButtonOffset;
668 	rect.top = fEnableCheckBox->Bounds().bottom + 8.0f;
669 	rect.right = box->Bounds().right - 8;
670 	BStringView* stringView = new BStringView(rect, NULL, "Run module");
671 	stringView->ResizeToPreferred();
672 	box->AddChild(stringView);
673 
674 	rect.left += labelWidth;
675 	fRunSlider = new TimeSlider(rect, "RunSlider", kMsgRunSliderChanged);
676 	float width, height;
677 	fRunSlider->GetPreferredSize(&width, &height);
678 	fRunSlider->ResizeTo(fRunSlider->Bounds().Width(), height);
679 	box->AddChild(fRunSlider);
680 
681 	// Turn Off
682 	rect.left = 8;
683 	rect.OffsetBy(0, fRunSlider->Bounds().Height() + 4.0f);
684 	fTurnOffCheckBox = new BCheckBox(rect, "TurnOffScreenCheckBox",
685 		"Turn off screen", new BMessage(kMsgTurnOffCheckBox));
686 	fTurnOffCheckBox->ResizeToPreferred();
687 	box->AddChild(fTurnOffCheckBox);
688 
689 	rect.left += radioButtonOffset + labelWidth;
690 	fTurnOffSlider = new TimeSlider(rect, "TurnOffSlider", kMsgTurnOffSliderChanged);
691 	fTurnOffSlider->ResizeTo(fTurnOffSlider->Bounds().Width(), height);
692 	box->AddChild(fTurnOffSlider);
693 
694 	// Password
695 	rect.left = 8;
696 	rect.OffsetBy(0, fTurnOffSlider->Bounds().Height() + 4.0f);
697 	fPasswordCheckBox = new BCheckBox(rect, "PasswordCheckbox",
698 		"Password lock", new BMessage(kMsgPasswordCheckBox));
699 	fPasswordCheckBox->ResizeToPreferred();
700 	box->AddChild(fPasswordCheckBox);
701 
702 	rect.left += radioButtonOffset + labelWidth;
703 	fPasswordSlider = new TimeSlider(rect, "PasswordSlider", kMsgPasswordSliderChanged);
704 	fPasswordSlider->ResizeTo(fPasswordSlider->Bounds().Width(), height);
705 	box->AddChild(fPasswordSlider);
706 
707 	rect.OffsetBy(0, fTurnOffSlider->Bounds().Height() + 4.0f);
708 	rect.left = rect.right;
709 	fPasswordButton = new BButton(rect, "PasswordButton", "Password" B_UTF8_ELLIPSIS,
710 		new BMessage(kMsgChangePassword), B_FOLLOW_TOP | B_FOLLOW_RIGHT);
711 	fPasswordButton->ResizeToPreferred();
712 	fPasswordButton->MoveBy(-fPasswordButton->Bounds().Width(), 0);
713 	box->AddChild(fPasswordButton);
714 
715 	// Bottom
716 
717 	box->AddChild(fFadeNow = new ScreenCornerSelector(BRect(20,205,80,260),"fadeNow",
718 		B_FOLLOW_LEFT | B_FOLLOW_BOTTOM));
719 	box->AddChild(fFadeNever = new ScreenCornerSelector(BRect(220,205,280,260),"fadeNever",
720 		B_FOLLOW_LEFT | B_FOLLOW_BOTTOM));
721 
722 	rect = BRect(90,215,193,230);
723 	stringView = new BStringView(rect, NULL, "Fade now when",
724 		B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
725 	stringView->ResizeToPreferred();
726 	box->AddChild(stringView);
727 
728 	rect.OffsetBy(0, stringView->Bounds().Height());
729 	stringView = new BStringView(rect, NULL, "mouse is here",
730 		B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
731 	stringView->ResizeToPreferred();
732 	box->AddChild(stringView);
733 
734 	rect = BRect(290,215,387,230);
735 	stringView = new BStringView(rect, NULL,"Don't fade when",
736 		B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
737 	stringView->ResizeToPreferred();
738 	box->AddChild(stringView);
739 
740 	rect.OffsetBy(0, stringView->Bounds().Height());
741 	stringView = new BStringView(rect, NULL, "mouse is here",
742 		B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
743 	stringView->ResizeToPreferred();
744 	box->AddChild(stringView);
745 }
746 
747 
748 void
749 ScreenSaverWindow::_UpdateTurnOffScreen()
750 {
751 	bool enabled = (fSettings.TimeFlags() & ENABLE_DPMS_MASK) != 0;
752 
753 	BScreen screen(this);
754 	uint32 dpmsCapabilities = screen.DPMSCapabilites();
755 
756 	fTurnOffScreenFlags = 0;
757 	if (dpmsCapabilities & B_DPMS_OFF)
758 		fTurnOffScreenFlags |= ENABLE_DPMS_OFF;
759 	if (dpmsCapabilities & B_DPMS_STAND_BY)
760 		fTurnOffScreenFlags |= ENABLE_DPMS_STAND_BY;
761 	if (dpmsCapabilities & B_DPMS_SUSPEND)
762 		fTurnOffScreenFlags |= ENABLE_DPMS_SUSPEND;
763 
764 	fTurnOffCheckBox->SetValue(enabled && fTurnOffScreenFlags != 0
765 		? B_CONTROL_ON : B_CONTROL_OFF);
766 }
767 
768 
769 void
770 ScreenSaverWindow::_UpdateStatus()
771 {
772 	DisableUpdates();
773 
774 	bool enabled = fEnableCheckBox->Value() == B_CONTROL_ON;
775 	fPasswordCheckBox->SetEnabled(enabled);
776 	fTurnOffCheckBox->SetEnabled(enabled && fTurnOffScreenFlags != 0);
777 	fRunSlider->SetEnabled(enabled);
778 	fTurnOffSlider->SetEnabled(enabled && fTurnOffCheckBox->Value());
779 	fPasswordSlider->SetEnabled(enabled && fPasswordCheckBox->Value());
780 	fPasswordButton->SetEnabled(enabled && fPasswordCheckBox->Value());
781 
782 	EnableUpdates();
783 
784 	// Update the saved preferences
785 	fSettings.SetWindowFrame(Frame());
786 	fSettings.SetWindowTab(fTabView->Selection());
787 	fSettings.SetTimeFlags((enabled ? ENABLE_SAVER : 0)
788 		| (fTurnOffCheckBox->Value() ? fTurnOffScreenFlags : 0));
789 	fSettings.SetBlankTime(fRunSlider->Time());
790 	bigtime_t offTime = fTurnOffSlider->Time() - fSettings.BlankTime();
791 	fSettings.SetOffTime(offTime);
792 	fSettings.SetSuspendTime(offTime);
793 	fSettings.SetStandByTime(offTime);
794 	fSettings.SetBlankCorner(fFadeNow->Corner());
795 	fSettings.SetNeverBlankCorner(fFadeNever->Corner());
796 	fSettings.SetLockEnable(fPasswordCheckBox->Value());
797 	fSettings.SetPasswordTime(fPasswordSlider->Time());
798 
799 	// TODO - Tell the password window to update its stuff
800 }
801 
802 
803 void
804 ScreenSaverWindow::SetMinimalSizeLimit(float width, float height)
805 {
806 	if (width < fMinWidth)
807 		width = fMinWidth;
808 	if (height < fMinHeight)
809 		height = fMinHeight;
810 
811 	SetSizeLimits(width, 32767, height, 32767);
812 }
813 
814 
815 void
816 ScreenSaverWindow::MessageReceived(BMessage *msg)
817 {
818 	switch (msg->what) {
819 		// "Fade" tab
820 
821 		case kMsgRunSliderChanged:
822 			if (fRunSlider->Value() > fTurnOffSlider->Value())
823 				fTurnOffSlider->SetValue(fRunSlider->Value());
824 
825 			if (fRunSlider->Value() > fPasswordSlider->Value())
826 				fPasswordSlider->SetValue(fRunSlider->Value());
827 			break;
828 
829 		case kMsgTurnOffCheckBox:
830 			fTurnOffSlider->SetEnabled(fTurnOffCheckBox->Value() == B_CONTROL_ON);
831 			break;
832 
833 		case kMsgTurnOffSliderChanged:
834 			if (fRunSlider->Value() > fTurnOffSlider->Value())
835 				fRunSlider->SetValue(fTurnOffSlider->Value());
836 			break;
837 
838 		case kMsgPasswordSliderChanged:
839 			if (fPasswordSlider->Value() < fRunSlider->Value())
840 				fRunSlider->SetValue(fPasswordSlider->Value());
841 			break;
842 
843 		case kMsgPasswordCheckBox:
844 		case kMsgEnableScreenSaverBox:
845 			_UpdateStatus();
846 			break;
847 
848 		case kMsgChangePassword:
849 			fPasswordWindow->Show();
850 			break;
851 
852 		// "Modules" tab
853 
854 		case kMsgUpdateList:
855 			fModulesView->PopulateScreenSaverList();
856 			break;
857   	}
858 	BWindow::MessageReceived(msg);
859 }
860 
861 
862 void
863 ScreenSaverWindow::ScreenChanged(BRect frame, color_space colorSpace)
864 {
865 	_UpdateTurnOffScreen();
866 }
867 
868 
869 bool
870 ScreenSaverWindow::QuitRequested()
871 {
872 	_UpdateStatus();
873 	fModulesView->SaveState();
874 	fSettings.SaveSettings();
875 
876 	be_app->PostMessage(B_QUIT_REQUESTED);
877 	return true;
878 }
879 
880