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