xref: /haiku/src/preferences/screensaver/ScreenSaverWindow.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
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 			_CloseSaver();
355 			_OpenSaver();
356 			break;
357 		}
358 
359 		case kMsgTestSaver:
360 			SaveState();
361 			fSettings.Save();
362 
363 			be_roster->Launch(SCREEN_BLANKER_SIG, &fSettings.Message());
364 			break;
365 
366 		case kMsgAddSaver:
367 			fFilePanel->Show();
368 			break;
369 
370 		default:
371 			BView::MessageReceived(message);
372 	}
373 }
374 
375 
376 void
377 ModulesView::SaveState()
378 {
379 	BScreenSaver* saver = _ScreenSaver();
380 	if (saver == NULL)
381 		return;
382 
383 	BMessage state;
384 	if (saver->SaveState(&state) == B_OK)
385 		fSettings.SetModuleState(fCurrentName.String(), &state);
386 }
387 
388 
389 void
390 ModulesView::PopulateScreenSaverList()
391 {
392  	fListView->DeselectAll();
393 	while (ScreenSaverItem* item = (ScreenSaverItem *)fListView->RemoveItem((int32)0)) {
394 		delete item;
395 	}
396 
397 	// Blackness is a built-in screen saver
398 	fListView->AddItem(new ScreenSaverItem("Blackness", ""));
399 
400 	// Iterate over add-on directories, and add their files to the list view
401 
402 	directory_which which[] = {B_BEOS_ADDONS_DIRECTORY, B_USER_ADDONS_DIRECTORY};
403 	ScreenSaverItem* selectItem = NULL;
404 
405 	for (uint32 i = 0; i < sizeof(which) / sizeof(which[0]); i++) {
406 		BPath basePath;
407 		find_directory(which[i], &basePath);
408 		basePath.Append("Screen Savers", true);
409 
410 		BDirectory dir(basePath.Path());
411 		BEntry entry;
412 		while (dir.GetNextEntry(&entry, true) == B_OK) {
413 			char name[B_FILE_NAME_LENGTH];
414 			if (entry.GetName(name) != B_OK)
415 				continue;
416 
417 			BPath path = basePath;
418 			path.Append(name);
419 
420 			ScreenSaverItem* item = new ScreenSaverItem(name, path.Path());
421 			fListView->AddItem(item);
422 
423 			if (!strcmp(fSettings.ModuleName(), item->Text())
424 				|| (!strcmp(fSettings.ModuleName(), "")
425 					&& !strcmp(item->Text(), "Blackness")))
426 				selectItem = item;
427 		}
428 	}
429 
430 	fListView->SortItems(_CompareScreenSaverItems);
431 
432 	fListView->Select(fListView->IndexOf(selectItem));
433 	fListView->ScrollToSelection();
434 }
435 
436 
437 //! sorting function for ScreenSaverItems
438 int
439 ModulesView::_CompareScreenSaverItems(const void* left, const void* right)
440 {
441 	ScreenSaverItem* leftItem  = *(ScreenSaverItem **)left;
442 	ScreenSaverItem* rightItem = *(ScreenSaverItem **)right;
443 
444 	return strcasecmp(leftItem->Text(), rightItem->Text());
445 }
446 
447 
448 BScreenSaver*
449 ModulesView::_ScreenSaver()
450 {
451 	if (fSaverRunner != NULL)
452 		return fSaverRunner->ScreenSaver();
453 
454 	return NULL;
455 }
456 
457 
458 void
459 ModulesView::_CloseSaver()
460 {
461 	// remove old screen saver preview & config
462 
463 	BScreenSaver* saver = _ScreenSaver();
464 	BView* view = fPreviewView->RemovePreview();
465 	if (fSettingsView != NULL)
466 		fSettingsBox->RemoveChild(fSettingsView);
467 
468 	if (fSaverRunner != NULL)
469 		fSaverRunner->Quit();
470 	if (saver != NULL)
471 		saver->StopConfig();
472 
473 	SaveState();
474 
475 	delete view;
476 	delete fSettingsView;
477 	delete fSaverRunner;
478 		// the saver runner also unloads the add-on, so it must
479 		// be deleted last
480 
481 	fSettingsView = NULL;
482 	fSaverRunner = NULL;
483 }
484 
485 
486 void
487 ModulesView::_OpenSaver()
488 {
489 	// create new screen saver preview & config
490 
491    	BView* view = fPreviewView->AddPreview();
492 	fCurrentName = fSettings.ModuleName();
493 	fSaverRunner = new ScreenSaverRunner(Window(), view, true, fSettings);
494 	BScreenSaver* saver = _ScreenSaver();
495 
496 #ifdef __HAIKU__
497 	BRect rect = fSettingsBox->InnerFrame().InsetByCopy(4, 4);
498 #else
499 	BRect rect = fSettingsBox->Bounds().InsetByCopy(4, 4);
500 	rect.top += 14;
501 #endif
502 	fSettingsView = new BView(rect, "SettingsView", B_FOLLOW_ALL, B_WILL_DRAW);
503 	fSettingsView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
504 	fSettingsBox->AddChild(fSettingsView);
505 
506 	if (saver != NULL) {
507 		fSaverRunner->Run();
508 		saver->StartConfig(fSettingsView);
509 	}
510 
511 	if (fSettingsView->ChildAt(0) == NULL) {
512 		// There are no settings at all, we add the module name here to
513 		// let it look a bit better at least.
514 		rect = BRect(15, 15, 20, 20);
515 		BStringView* stringView = new BStringView(rect, "module", fSettings.ModuleName()[0]
516 			? fSettings.ModuleName() : "Blackness");
517 		stringView->SetFont(be_bold_font);
518 		stringView->ResizeToPreferred();
519 		fSettingsView->AddChild(stringView);
520 
521 		rect.OffsetBy(0, stringView->Bounds().Height() + 4);
522 		stringView = new BStringView(rect, "info", saver || !fSettings.ModuleName()[0]
523 			? "No options available" : "Could not load screen saver");
524 		stringView->ResizeToPreferred();
525 		fSettingsView->AddChild(stringView);
526 	}
527 
528 	ScreenSaverWindow* window = dynamic_cast<ScreenSaverWindow*>(Window());
529 	if (window == NULL)
530 		return;
531 
532 	// find the minimal size of the settings view
533 
534 	float right = 0, bottom = 0;
535 	int32 i = 0;
536 	while ((view = fSettingsView->ChildAt(i++)) != NULL) {
537 		// very simple heuristic...
538 		float viewRight = view->Frame().right;
539 		if ((view->ResizingMode() & _rule_(0, 0xf, 0, 0xf)) == B_FOLLOW_LEFT_RIGHT) {
540 			float width, height;
541 			view->GetPreferredSize(&width, &height);
542 			viewRight = view->Frame().left + width / 2;
543 		} else if ((view->ResizingMode() & _rule_(0, 0xf, 0, 0xf)) == B_FOLLOW_RIGHT)
544 			viewRight = 8 + view->Frame().Width();
545 
546 		float viewBottom = view->Frame().bottom;
547 		if ((view->ResizingMode() & _rule_(0xf, 0, 0xf, 0)) == B_FOLLOW_TOP_BOTTOM) {
548 			float width, height;
549 			view->GetPreferredSize(&width, &height);
550 			viewBottom = view->Frame().top + height;
551 		} else if ((view->ResizingMode() & _rule_(0xf, 0, 0xf, 0)) == B_FOLLOW_BOTTOM)
552 			viewBottom = 8 + view->Frame().Height();
553 
554 		if (viewRight > right)
555 			right = viewRight;
556 		if (viewBottom > bottom)
557 			bottom = viewBottom;
558 	}
559 
560 	if (right < kMinSettingsWidth)
561 		right = kMinSettingsWidth;
562 	if (bottom < kMinSettingsHeight)
563 		bottom = kMinSettingsHeight;
564 
565 	BPoint leftTop = fSettingsView->LeftTop();
566 	fSettingsView->ConvertToScreen(&leftTop);
567 	window->ConvertFromScreen(&leftTop);
568 	window->SetMinimalSizeLimit(leftTop.x + right + 16,
569 		leftTop.y + bottom + 16);
570 }
571 
572 
573 //	#pragma mark -
574 
575 
576 ScreenSaverWindow::ScreenSaverWindow()
577 	: BWindow(BRect(50, 50, 496, 375), "Screen Saver",
578 		B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS /*| B_NOT_ZOOMABLE | B_NOT_RESIZABLE*/)
579 {
580 	fSettings.Load();
581 
582 	BRect rect = Bounds();
583 	fMinWidth = 430;
584 	fMinHeight = 325;
585 
586 	// Create a background view
587 	BView *background = new BView(rect, "background", B_FOLLOW_ALL, 0);
588 	background->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
589 	AddChild(background);
590 
591 	// Add the tab view to the background
592 	rect.top += 4;
593 	fTabView = new BTabView(rect, "tab_view");
594 
595 	// Create the controls inside the tabs
596 	rect = fTabView->ContainerView()->Bounds();
597 	_SetupFadeTab(rect);
598 	fModulesView = new ModulesView(rect, "Modules", fSettings);
599 
600 	fTabView->AddTab(fFadeView);
601 	fTabView->AddTab(fModulesView);
602 	background->AddChild(fTabView);
603 
604 	// Create the password editing window
605 	fPasswordWindow = new PasswordWindow(fSettings);
606 	fPasswordWindow->Run();
607 
608 	SetMinimalSizeLimit(fMinWidth, fMinHeight);
609 	MoveTo(fSettings.WindowFrame().left, fSettings.WindowFrame().top);
610 	ResizeTo(fSettings.WindowFrame().Width(), fSettings.WindowFrame().Height());
611 
612 	fEnableCheckBox->SetValue(fSettings.TimeFlags() & ENABLE_SAVER ? B_CONTROL_ON : B_CONTROL_OFF);
613 	fRunSlider->SetTime(fSettings.BlankTime());
614 	fTurnOffSlider->SetTime(fSettings.OffTime() + fSettings.BlankTime());
615 	fFadeNow->SetCorner(fSettings.BlankCorner());
616 	fFadeNever->SetCorner(fSettings.NeverBlankCorner());
617 	fPasswordCheckBox->SetValue(fSettings.LockEnable());
618 	fPasswordSlider->SetTime(fSettings.PasswordTime());
619 
620 	fTabView->Select(fSettings.WindowTab());
621 
622 	_UpdateTurnOffScreen();
623 	_UpdateStatus();
624 }
625 
626 
627 ScreenSaverWindow::~ScreenSaverWindow()
628 {
629 }
630 
631 
632 //! Create the controls for the fade tab
633 void
634 ScreenSaverWindow::_SetupFadeTab(BRect rect)
635 {
636 	fFadeView = new FadeView(rect, "Fade", fSettings);
637 
638 	float labelWidth = be_plain_font->StringWidth("Turn off screen") + 20.0f;
639 
640 	font_height fontHeight;
641 	be_plain_font->GetHeight(&fontHeight);
642 	float textHeight = ceilf(fontHeight.ascent + fontHeight.descent);
643 
644 	// taken from BRadioButton:
645 	float radioButtonOffset = 2 * floorf(textHeight / 2 - 2) + floorf(textHeight / 2);
646 
647 	fEnableCheckBox = new BCheckBox(BRect(0, 0, 1, 1), "EnableCheckBox",
648 		"Enable Screen Saver", new BMessage(kMsgEnableScreenSaverBox));
649 	fEnableCheckBox->ResizeToPreferred();
650 
651 	rect.InsetBy(8, 8);
652 	BBox* box = new BBox(rect, "EnableScreenSaverBox", B_FOLLOW_ALL);
653 	box->SetLabel(fEnableCheckBox);
654 	fFadeView->AddChild(box);
655 
656 	// Run Module
657 	rect.left += radioButtonOffset;
658 	rect.top = fEnableCheckBox->Bounds().bottom + 8.0f;
659 	rect.right = box->Bounds().right - 8;
660 	BStringView* stringView = new BStringView(rect, NULL, "Run module");
661 	stringView->ResizeToPreferred();
662 	box->AddChild(stringView);
663 
664 	rect.left += labelWidth;
665 	fRunSlider = new TimeSlider(rect, "RunSlider", kMsgRunSliderChanged,
666 		kMsgRunSliderUpdate);
667 	float width, height;
668 	fRunSlider->GetPreferredSize(&width, &height);
669 	fRunSlider->ResizeTo(fRunSlider->Bounds().Width(), height);
670 	box->AddChild(fRunSlider);
671 
672 	// Turn Off
673 	rect.left = 8;
674 	rect.OffsetBy(0, fRunSlider->Bounds().Height() + 4.0f);
675 	fTurnOffCheckBox = new BCheckBox(rect, "TurnOffScreenCheckBox",
676 		"Turn off screen", new BMessage(kMsgTurnOffCheckBox));
677 	fTurnOffCheckBox->ResizeToPreferred();
678 	box->AddChild(fTurnOffCheckBox);
679 
680 	rect.left += radioButtonOffset + labelWidth;
681 	fTurnOffSlider = new TimeSlider(rect, "TurnOffSlider",
682 		kMsgTurnOffSliderChanged, kMsgTurnOffSliderUpdate);
683 	fTurnOffSlider->ResizeTo(fTurnOffSlider->Bounds().Width(), height);
684 	box->AddChild(fTurnOffSlider);
685 
686 	// Password
687 	rect.left = 8;
688 	rect.OffsetBy(0, fTurnOffSlider->Bounds().Height() + 4.0f);
689 	fPasswordCheckBox = new BCheckBox(rect, "PasswordCheckbox",
690 		"Password lock", new BMessage(kMsgPasswordCheckBox));
691 	fPasswordCheckBox->ResizeToPreferred();
692 	box->AddChild(fPasswordCheckBox);
693 
694 	rect.left += radioButtonOffset + labelWidth;
695 	fPasswordSlider = new TimeSlider(rect, "PasswordSlider",
696 		kMsgPasswordSliderChanged, kMsgPasswordSliderUpdate);
697 	fPasswordSlider->ResizeTo(fPasswordSlider->Bounds().Width(), height);
698 	box->AddChild(fPasswordSlider);
699 
700 	rect.OffsetBy(0, fTurnOffSlider->Bounds().Height() + 4.0f);
701 	rect.left = rect.right;
702 	fPasswordButton = new BButton(rect, "PasswordButton", "Password" B_UTF8_ELLIPSIS,
703 		new BMessage(kMsgChangePassword), B_FOLLOW_TOP | B_FOLLOW_RIGHT);
704 	fPasswordButton->ResizeToPreferred();
705 	fPasswordButton->MoveBy(-fPasswordButton->Bounds().Width(), 0);
706 	box->AddChild(fPasswordButton);
707 
708 	// Bottom
709 
710 	float monitorHeight = 10 + textHeight * 3;
711 	float monitorWidth = monitorHeight * 4 / 3;
712 	rect.left = 15;
713 	rect.top = box->Bounds().Height() - 15 - monitorHeight;
714 	rect.right = rect.left + monitorWidth;
715 	rect.bottom = rect.top + monitorHeight;
716 	box->AddChild(fFadeNow = new ScreenCornerSelector(rect, "FadeNow",
717 		new BMessage(kMsgFadeCornerChanged), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM));
718 
719 	rect.OffsetBy(monitorWidth + 10, 0);
720 	stringView = new BStringView(rect, NULL, "Fade now when",
721 		B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
722 	stringView->ResizeToPreferred();
723 	float maxWidth = stringView->Bounds().Width();
724 	box->AddChild(stringView);
725 
726 	rect.OffsetBy(0, stringView->Bounds().Height());
727 	stringView = new BStringView(rect, NULL, "mouse is here",
728 		B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
729 	stringView->ResizeToPreferred();
730 	if (maxWidth < stringView->Bounds().Width())
731 		maxWidth = stringView->Bounds().Width();
732 	box->AddChild(stringView);
733 
734 	rect.left += maxWidth + 20;
735 	rect.top = box->Bounds().Height() - 15 - monitorHeight;
736 	rect.right = rect.left + monitorWidth;
737 	rect.bottom = rect.top + monitorHeight;
738 	box->AddChild(fFadeNever = new ScreenCornerSelector(rect, "FadeNever",
739 		new BMessage(kMsgNeverFadeCornerChanged), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM));
740 
741 	rect.OffsetBy(monitorWidth + 10, 0);
742 	stringView = new BStringView(rect, NULL,"Don't fade when",
743 		B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
744 	stringView->ResizeToPreferred();
745 	if (maxWidth < stringView->Bounds().Width())
746 		maxWidth = stringView->Bounds().Width();
747 	box->AddChild(stringView);
748 
749 	rect.OffsetBy(0, stringView->Bounds().Height());
750 	stringView = new BStringView(rect, NULL, "mouse is here",
751 		B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
752 	stringView->ResizeToPreferred();
753 	if (maxWidth < stringView->Bounds().Width())
754 		maxWidth = stringView->Bounds().Width();
755 	box->AddChild(stringView);
756 
757 	float size = rect.left + maxWidth + 40;
758 	if (fMinWidth < size)
759 		fMinWidth = size;
760 	size = fPasswordButton->Frame().bottom + box->Frame().top
761 		+ monitorHeight + 40 + textHeight * 2;
762 	if (fMinHeight < size)
763 		fMinHeight = size;
764 }
765 
766 
767 void
768 ScreenSaverWindow::_UpdateTurnOffScreen()
769 {
770 	bool enabled = (fSettings.TimeFlags() & ENABLE_DPMS_MASK) != 0;
771 
772 	BScreen screen(this);
773 	uint32 dpmsCapabilities = screen.DPMSCapabilites();
774 
775 	fTurnOffScreenFlags = 0;
776 	if (dpmsCapabilities & B_DPMS_OFF)
777 		fTurnOffScreenFlags |= ENABLE_DPMS_OFF;
778 	if (dpmsCapabilities & B_DPMS_STAND_BY)
779 		fTurnOffScreenFlags |= ENABLE_DPMS_STAND_BY;
780 	if (dpmsCapabilities & B_DPMS_SUSPEND)
781 		fTurnOffScreenFlags |= ENABLE_DPMS_SUSPEND;
782 
783 	fTurnOffCheckBox->SetValue(enabled && fTurnOffScreenFlags != 0
784 		? B_CONTROL_ON : B_CONTROL_OFF);
785 }
786 
787 
788 void
789 ScreenSaverWindow::_UpdateStatus()
790 {
791 	DisableUpdates();
792 
793 	bool enabled = fEnableCheckBox->Value() == B_CONTROL_ON;
794 	fPasswordCheckBox->SetEnabled(enabled);
795 	fTurnOffCheckBox->SetEnabled(enabled && fTurnOffScreenFlags != 0);
796 	fRunSlider->SetEnabled(enabled);
797 	fTurnOffSlider->SetEnabled(enabled && fTurnOffCheckBox->Value());
798 	fPasswordSlider->SetEnabled(enabled && fPasswordCheckBox->Value());
799 	fPasswordButton->SetEnabled(enabled && fPasswordCheckBox->Value());
800 
801 	EnableUpdates();
802 
803 	// Update the saved preferences
804 	fSettings.SetWindowFrame(Frame());
805 	fSettings.SetWindowTab(fTabView->Selection());
806 	fSettings.SetTimeFlags((enabled ? ENABLE_SAVER : 0)
807 		| (fTurnOffCheckBox->Value() ? fTurnOffScreenFlags : 0));
808 	fSettings.SetBlankTime(fRunSlider->Time());
809 	bigtime_t offTime = fTurnOffSlider->Time() - fSettings.BlankTime();
810 	fSettings.SetOffTime(offTime);
811 	fSettings.SetSuspendTime(offTime);
812 	fSettings.SetStandByTime(offTime);
813 	fSettings.SetBlankCorner(fFadeNow->Corner());
814 	fSettings.SetNeverBlankCorner(fFadeNever->Corner());
815 	fSettings.SetLockEnable(fPasswordCheckBox->Value());
816 	fSettings.SetPasswordTime(fPasswordSlider->Time());
817 
818 	// TODO - Tell the password window to update its stuff
819 }
820 
821 
822 void
823 ScreenSaverWindow::SetMinimalSizeLimit(float width, float height)
824 {
825 	if (width < fMinWidth)
826 		width = fMinWidth;
827 	if (height < fMinHeight)
828 		height = fMinHeight;
829 
830 	SetSizeLimits(width, 32767, height, 32767);
831 }
832 
833 
834 void
835 ScreenSaverWindow::MessageReceived(BMessage *msg)
836 {
837 	// "Fade" tab, slider updates
838 
839 	switch (msg->what) {
840 		case kMsgRunSliderChanged:
841 		case kMsgRunSliderUpdate:
842 			if (fRunSlider->Value() > fTurnOffSlider->Value())
843 				fTurnOffSlider->SetValue(fRunSlider->Value());
844 
845 			if (fRunSlider->Value() > fPasswordSlider->Value())
846 				fPasswordSlider->SetValue(fRunSlider->Value());
847 			break;
848 
849 		case kMsgTurnOffSliderChanged:
850 		case kMsgTurnOffSliderUpdate:
851 			if (fRunSlider->Value() > fTurnOffSlider->Value())
852 				fRunSlider->SetValue(fTurnOffSlider->Value());
853 			break;
854 
855 		case kMsgPasswordSliderChanged:
856 		case kMsgPasswordSliderUpdate:
857 			if (fPasswordSlider->Value() < fRunSlider->Value())
858 				fRunSlider->SetValue(fPasswordSlider->Value());
859 			break;
860 	}
861 
862 	switch (msg->what) {
863 		// "Fade" tab
864 
865 		case kMsgTurnOffCheckBox:
866 			fTurnOffSlider->SetEnabled(fTurnOffCheckBox->Value() == B_CONTROL_ON);
867 			break;
868 
869 		case kMsgRunSliderChanged:
870 		case kMsgTurnOffSliderChanged:
871 		case kMsgPasswordSliderChanged:
872 		case kMsgPasswordCheckBox:
873 		case kMsgEnableScreenSaverBox:
874 		case kMsgFadeCornerChanged:
875 		case kMsgNeverFadeCornerChanged:
876 			_UpdateStatus();
877 			fSettings.Save();
878 			break;
879 
880 		case kMsgChangePassword:
881 			fPasswordWindow->Show();
882 			break;
883 
884 		// "Modules" tab
885 
886 		case kMsgUpdateList:
887 			fModulesView->PopulateScreenSaverList();
888 			break;
889 
890 		default:
891 			BWindow::MessageReceived(msg);
892 			break;
893   	}
894 }
895 
896 
897 void
898 ScreenSaverWindow::ScreenChanged(BRect frame, color_space colorSpace)
899 {
900 	_UpdateTurnOffScreen();
901 }
902 
903 
904 bool
905 ScreenSaverWindow::QuitRequested()
906 {
907 	_UpdateStatus();
908 	fModulesView->SaveState();
909 	fSettings.Save();
910 
911 	be_app->PostMessage(B_QUIT_REQUESTED);
912 	return true;
913 }
914 
915