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