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