RemoteDrawingEngine: Reduce RP_READ_BITMAP result timeout.
[haiku.git] / src / preferences / screensaver / ScreenSaverWindow.cpp
blob38e02a4c482f6f49afa6aa0051318f93c984a49b
1 /*
2 * Copyright 2003-2016 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Axel Dörfler, axeld@pinc-software.de
7 * Jérôme Duval, jerome.duval@free.fr
8 * Puck Meerburg, puck@puckipedia.nl
9 * Michael Phipps
10 * John Scipione, jscipione@gmail.com
14 #include "ScreenSaverWindow.h"
16 #include <stdio.h>
17 #include <strings.h>
19 #include <Alignment.h>
20 #include <Application.h>
21 #include <Box.h>
22 #include <Button.h>
23 #include <Catalog.h>
24 #include <CheckBox.h>
25 #include <ControlLook.h>
26 #include <DefaultSettingsView.h>
27 #include <Directory.h>
28 #include <DurationFormat.h>
29 #include <Entry.h>
30 #include <File.h>
31 #include <FindDirectory.h>
32 #include <Font.h>
33 #include <GroupLayout.h>
34 #include <LayoutBuilder.h>
35 #include <ListItem.h>
36 #include <ListView.h>
37 #include <Path.h>
38 #include <Rect.h>
39 #include <Roster.h>
40 #include <Screen.h>
41 #include <ScreenSaver.h>
42 #include <ScreenSaverRunner.h>
43 #include <ScrollView.h>
44 #include <Size.h>
45 #include <Slider.h>
46 #include <StringView.h>
47 #include <TabView.h>
48 #include <TextView.h>
50 #include <algorithm>
51 // for std::max and std::min
53 #include "PreviewView.h"
54 #include "ScreenCornerSelector.h"
55 #include "ScreenSaverItem.h"
56 #include "ScreenSaverShared.h"
58 #undef B_TRANSLATION_CONTEXT
59 #define B_TRANSLATION_CONTEXT "ScreenSaver"
62 const uint32 kPreviewMonitorGap = 16;
63 const uint32 kMinSettingsWidth = 230;
64 const uint32 kMinSettingsHeight = 120;
66 const int32 kMsgSaverSelected = 'SSEL';
67 const int32 kMsgPasswordCheckBox = 'PWCB';
68 const int32 kMsgRunSliderChanged = 'RSch';
69 const int32 kMsgRunSliderUpdate = 'RSup';
70 const int32 kMsgPasswordSliderChanged = 'PWch';
71 const int32 kMsgPasswordSliderUpdate = 'PWup';
72 const int32 kMsgChangePassword = 'PWBT';
73 const int32 kMsgEnableScreenSaverBox = 'ESCH';
75 const int32 kMsgTurnOffCheckBox = 'TUOF';
76 const int32 kMsgTurnOffSliderChanged = 'TUch';
77 const int32 kMsgTurnOffSliderUpdate = 'TUup';
79 const int32 kMsgFadeCornerChanged = 'fdcc';
80 const int32 kMsgNeverFadeCornerChanged = 'nfcc';
82 const float kWindowWidth = 446.0f;
83 const float kWindowHeight = 325.0f;
84 const float kDefaultItemSpacingAt12pt = 12.0f * 0.85;
87 class TimeSlider : public BSlider {
88 public:
89 TimeSlider(const char* name,
90 uint32 changedMessage,
91 uint32 updateMessage);
92 virtual ~TimeSlider();
94 virtual void SetValue(int32 value);
96 void SetTime(bigtime_t useconds);
97 bigtime_t Time() const;
99 private:
100 void _TimeToString(bigtime_t useconds,
101 BString& string);
105 class TabView : public BTabView {
106 public:
107 TabView();
109 virtual void MouseDown(BPoint where);
113 class FadeView : public BView {
114 public:
115 FadeView(const char* name,
116 ScreenSaverSettings& settings);
118 virtual void AttachedToWindow();
119 virtual void MessageReceived(BMessage* message);
121 void UpdateTurnOffScreen();
122 void UpdateStatus();
124 private:
125 void _UpdateColors();
126 ScreenSaverSettings& fSettings;
127 uint32 fTurnOffScreenFlags;
129 BCheckBox* fEnableCheckBox;
130 TimeSlider* fRunSlider;
132 BTextView* fTurnOffNotSupported;
133 BCheckBox* fTurnOffCheckBox;
134 TimeSlider* fTurnOffSlider;
136 BTextView* fFadeNeverText;
137 BTextView* fFadeNowText;
139 BCheckBox* fPasswordCheckBox;
140 TimeSlider* fPasswordSlider;
141 BButton* fPasswordButton;
143 ScreenCornerSelector* fFadeNow;
144 ScreenCornerSelector* fFadeNever;
148 class ModulesView : public BView {
149 public:
150 ModulesView(const char* name,
151 ScreenSaverSettings& settings);
152 virtual ~ModulesView();
154 virtual void DetachedFromWindow();
155 virtual void AttachedToWindow();
156 virtual void AllAttached();
157 virtual void MessageReceived(BMessage* message);
159 void EmptyScreenSaverList();
160 void PopulateScreenSaverList();
162 void SaveState();
164 BScreenSaver* ScreenSaver();
166 private:
167 friend class TabView;
169 static int _CompareScreenSaverItems(const void* left,
170 const void* right);
172 void _CloseSaver();
173 void _OpenSaver();
175 private:
176 ScreenSaverSettings& fSettings;
178 BListView* fScreenSaversListView;
179 BButton* fTestButton;
181 ScreenSaverRunner* fSaverRunner;
182 BString fCurrentName;
184 BBox* fSettingsBox;
185 BView* fSettingsView;
187 PreviewView* fPreviewView;
189 team_id fScreenSaverTestTeam;
193 // #pragma mark - TimeSlider
196 static const int32 kTimeInUnits[] = {
197 30, 60, 90,
198 120, 150, 180,
199 240, 300, 360,
200 420, 480, 540,
201 600, 900, 1200,
202 1500, 1800, 2400,
203 3000, 3600, 5400,
204 7200, 9000, 10800,
205 14400, 18000
208 static const int32 kTimeUnitCount
209 = sizeof(kTimeInUnits) / sizeof(kTimeInUnits[0]);
212 TimeSlider::TimeSlider(const char* name, uint32 changedMessage,
213 uint32 updateMessage)
215 BSlider(name, B_TRANSLATE("30 seconds"), new BMessage(changedMessage),
216 0, kTimeUnitCount - 1, B_HORIZONTAL, B_TRIANGLE_THUMB)
218 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
219 SetModificationMessage(new BMessage(updateMessage));
220 SetBarThickness(10);
224 TimeSlider::~TimeSlider()
229 void
230 TimeSlider::SetValue(int32 value)
232 int32 oldValue = Value();
233 BSlider::SetValue(value);
235 if (oldValue != Value()) {
236 BString label;
237 _TimeToString(kTimeInUnits[Value()] * 1000000LL, label);
238 SetLabel(label.String());
243 void
244 TimeSlider::SetTime(bigtime_t useconds)
246 for (int t = 0; t < kTimeUnitCount; t++) {
247 if (kTimeInUnits[t] * 1000000LL == useconds) {
248 SetValue(t);
249 break;
255 bigtime_t
256 TimeSlider::Time() const
258 return 1000000LL * kTimeInUnits[Value()];
262 void
263 TimeSlider::_TimeToString(bigtime_t useconds, BString& string)
265 BDurationFormat formatter;
266 formatter.Format(string, 0, useconds);
270 // #pragma mark - FadeView
273 FadeView::FadeView(const char* name, ScreenSaverSettings& settings)
275 BView(name, B_WILL_DRAW),
276 fSettings(settings)
278 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
280 font_height fontHeight;
281 be_plain_font->GetHeight(&fontHeight);
282 float textHeight = ceilf(fontHeight.ascent + fontHeight.descent);
284 fEnableCheckBox = new BCheckBox("EnableCheckBox",
285 B_TRANSLATE("Enable screensaver"),
286 new BMessage(kMsgEnableScreenSaverBox));
288 BBox* box = new BBox("EnableScreenSaverBox");
289 box->SetLabel(fEnableCheckBox);
291 // Start Screensaver
292 BStringView* startScreenSaver = new BStringView("startScreenSaver",
293 B_TRANSLATE("Start screensaver"));
294 startScreenSaver->SetAlignment(B_ALIGN_RIGHT);
296 fRunSlider = new TimeSlider("RunSlider", kMsgRunSliderChanged,
297 kMsgRunSliderUpdate);
299 // Turn Off
300 rgb_color textColor = disable_color(ui_color(B_PANEL_TEXT_COLOR),
301 ViewColor());
303 fTurnOffNotSupported = new BTextView("not_supported", be_plain_font,
304 &textColor, B_WILL_DRAW);
305 fTurnOffNotSupported->SetExplicitMinSize(BSize(B_SIZE_UNSET,
306 3 + textHeight * 3));
307 fTurnOffNotSupported->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
308 fTurnOffNotSupported->MakeEditable(false);
309 fTurnOffNotSupported->MakeSelectable(false);
310 fTurnOffNotSupported->SetText(
311 B_TRANSLATE("Display Power Management Signaling not available"));
313 fTurnOffCheckBox = new BCheckBox("TurnOffScreenCheckBox",
314 B_TRANSLATE("Turn off screen"), new BMessage(kMsgTurnOffCheckBox));
315 fTurnOffCheckBox->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
316 B_ALIGN_VERTICAL_CENTER));
318 fTurnOffSlider = new TimeSlider("TurnOffSlider", kMsgTurnOffSliderChanged,
319 kMsgTurnOffSliderUpdate);
321 // Password
322 fPasswordCheckBox = new BCheckBox("PasswordCheckbox",
323 B_TRANSLATE("Password lock"), new BMessage(kMsgPasswordCheckBox));
324 fPasswordCheckBox->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
325 B_ALIGN_VERTICAL_CENTER));
327 fPasswordSlider = new TimeSlider("PasswordSlider",
328 kMsgPasswordSliderChanged, kMsgPasswordSliderUpdate);
330 fPasswordButton = new BButton("PasswordButton",
331 B_TRANSLATE("Password" B_UTF8_ELLIPSIS),
332 new BMessage(kMsgChangePassword));
334 // Bottom
335 float monitorHeight = 10 + textHeight * 3;
336 float aspectRatio = 4.0f / 3.0f;
337 float monitorWidth = monitorHeight * aspectRatio;
338 BRect monitorRect = BRect(0, 0, monitorWidth, monitorHeight);
340 fFadeNow = new ScreenCornerSelector(monitorRect, "FadeNow",
341 new BMessage(kMsgFadeCornerChanged), B_FOLLOW_NONE);
342 fFadeNowText = new BTextView("FadeNowText", B_WILL_DRAW);
343 fFadeNowText->SetExplicitMinSize(BSize(B_SIZE_UNSET,
344 4 + textHeight * 4));
345 fFadeNowText->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
346 fFadeNowText->MakeEditable(false);
347 fFadeNowText->MakeSelectable(false);
348 fFadeNowText->SetText(B_TRANSLATE("Fade now when mouse is here"));
350 fFadeNever = new ScreenCornerSelector(monitorRect, "FadeNever",
351 new BMessage(kMsgNeverFadeCornerChanged), B_FOLLOW_NONE);
352 fFadeNeverText = new BTextView("FadeNeverText", B_WILL_DRAW);
353 fFadeNeverText->SetExplicitMinSize(BSize(B_SIZE_UNSET,
354 4 + textHeight * 4));
355 fFadeNeverText->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
356 fFadeNeverText->MakeEditable(false);
357 fFadeNeverText->MakeSelectable(false);
358 fFadeNeverText->SetText(B_TRANSLATE("Don't fade when mouse is here"));
360 box->AddChild(BLayoutBuilder::Group<>(B_VERTICAL, 0)
361 .SetInsets(B_USE_DEFAULT_SPACING, 0, B_USE_DEFAULT_SPACING,
362 B_USE_DEFAULT_SPACING)
363 .AddGrid(B_USE_DEFAULT_SPACING, B_USE_SMALL_SPACING)
364 .Add(startScreenSaver, 0, 0)
365 .Add(fRunSlider, 1, 0)
366 .Add(fTurnOffCheckBox, 0, 1)
367 .Add(BLayoutBuilder::Group<>(B_VERTICAL)
368 .Add(fTurnOffNotSupported)
369 .Add(fTurnOffSlider)
370 .View(), 1, 1)
371 .Add(fPasswordCheckBox, 0, 2)
372 .Add(fPasswordSlider, 1, 2)
373 .End()
374 .AddGroup(B_HORIZONTAL)
375 .AddGlue()
376 .Add(fPasswordButton)
377 .End()
378 .AddGlue()
379 .AddGroup(B_HORIZONTAL)
380 .Add(fFadeNow)
381 .AddGroup(B_VERTICAL, 0)
382 .Add(fFadeNowText)
383 .AddGlue()
384 .End()
385 .Add(fFadeNever)
386 .AddGroup(B_VERTICAL, 0)
387 .Add(fFadeNeverText)
388 .AddGlue()
389 .End()
390 .End()
391 .AddGlue()
392 .View());
394 BLayoutBuilder::Group<>(this, B_HORIZONTAL)
395 .SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
396 B_USE_WINDOW_SPACING, 0)
397 .Add(box)
398 .End();
403 void
404 FadeView::AttachedToWindow()
406 fEnableCheckBox->SetTarget(this);
407 fRunSlider->SetTarget(this);
408 fTurnOffCheckBox->SetTarget(this);
409 fTurnOffSlider->SetTarget(this);
410 fFadeNow->SetTarget(this);
411 fFadeNever->SetTarget(this);
412 fPasswordCheckBox->SetTarget(this);
413 fPasswordSlider->SetTarget(this);
415 fEnableCheckBox->SetValue(
416 fSettings.TimeFlags() & ENABLE_SAVER ? B_CONTROL_ON : B_CONTROL_OFF);
417 fRunSlider->SetTime(fSettings.BlankTime());
418 fTurnOffSlider->SetTime(fSettings.OffTime() + fSettings.BlankTime());
419 fFadeNow->SetCorner(fSettings.BlankCorner());
420 fFadeNever->SetCorner(fSettings.NeverBlankCorner());
421 fPasswordCheckBox->SetValue(fSettings.LockEnable());
422 fPasswordSlider->SetTime(fSettings.PasswordTime());
424 _UpdateColors();
425 UpdateTurnOffScreen();
426 UpdateStatus();
430 void
431 FadeView::MessageReceived(BMessage *message)
433 switch (message->what) {
434 case B_COLORS_UPDATED:
435 _UpdateColors();
436 break;
437 case kMsgRunSliderChanged:
438 case kMsgRunSliderUpdate:
439 if (fRunSlider->Value() > fTurnOffSlider->Value())
440 fTurnOffSlider->SetValue(fRunSlider->Value());
442 if (fRunSlider->Value() > fPasswordSlider->Value())
443 fPasswordSlider->SetValue(fRunSlider->Value());
444 break;
446 case kMsgTurnOffSliderChanged:
447 case kMsgTurnOffSliderUpdate:
448 if (fRunSlider->Value() > fTurnOffSlider->Value())
449 fRunSlider->SetValue(fTurnOffSlider->Value());
450 break;
452 case kMsgPasswordSliderChanged:
453 case kMsgPasswordSliderUpdate:
454 if (fPasswordSlider->Value() < fRunSlider->Value())
455 fRunSlider->SetValue(fPasswordSlider->Value());
456 break;
458 case kMsgTurnOffCheckBox:
459 fTurnOffSlider->SetEnabled(
460 fTurnOffCheckBox->Value() == B_CONTROL_ON);
461 break;
464 switch (message->what) {
465 case kMsgRunSliderChanged:
466 case kMsgTurnOffSliderChanged:
467 case kMsgPasswordSliderChanged:
468 case kMsgPasswordCheckBox:
469 case kMsgEnableScreenSaverBox:
470 case kMsgFadeCornerChanged:
471 case kMsgNeverFadeCornerChanged:
472 UpdateStatus();
473 fSettings.Save();
474 break;
476 default:
477 BView::MessageReceived(message);
482 void
483 FadeView::UpdateTurnOffScreen()
485 bool enabled = (fSettings.TimeFlags() & ENABLE_DPMS_MASK) != 0;
487 BScreen screen(Window());
488 uint32 dpmsCapabilities = screen.DPMSCapabilites();
490 fTurnOffScreenFlags = 0;
491 if (dpmsCapabilities & B_DPMS_OFF)
492 fTurnOffScreenFlags |= ENABLE_DPMS_OFF;
493 if (dpmsCapabilities & B_DPMS_STAND_BY)
494 fTurnOffScreenFlags |= ENABLE_DPMS_STAND_BY;
495 if (dpmsCapabilities & B_DPMS_SUSPEND)
496 fTurnOffScreenFlags |= ENABLE_DPMS_SUSPEND;
498 fTurnOffCheckBox->SetValue(enabled && fTurnOffScreenFlags != 0
499 ? B_CONTROL_ON : B_CONTROL_OFF);
501 enabled = fEnableCheckBox->Value() == B_CONTROL_ON;
502 fTurnOffCheckBox->SetEnabled(enabled && fTurnOffScreenFlags != 0);
503 if (fTurnOffScreenFlags != 0) {
504 fTurnOffNotSupported->Hide();
505 fTurnOffSlider->Show();
506 } else {
507 fTurnOffSlider->Hide();
508 fTurnOffNotSupported->Show();
513 void
514 FadeView::UpdateStatus()
516 Window()->DisableUpdates();
518 bool enabled = fEnableCheckBox->Value() == B_CONTROL_ON;
519 fPasswordCheckBox->SetEnabled(enabled);
520 fTurnOffCheckBox->SetEnabled(enabled && fTurnOffScreenFlags != 0);
521 fRunSlider->SetEnabled(enabled);
522 fTurnOffSlider->SetEnabled(enabled && fTurnOffCheckBox->Value());
523 fPasswordSlider->SetEnabled(enabled && fPasswordCheckBox->Value());
524 fPasswordButton->SetEnabled(enabled && fPasswordCheckBox->Value());
526 Window()->EnableUpdates();
528 // Update the saved preferences
529 fSettings.SetWindowFrame(Frame());
530 fSettings.SetTimeFlags((enabled ? ENABLE_SAVER : 0)
531 | (fTurnOffCheckBox->Value() ? fTurnOffScreenFlags : 0));
532 fSettings.SetBlankTime(fRunSlider->Time());
533 bigtime_t offTime = fTurnOffSlider->Time() - fSettings.BlankTime();
534 fSettings.SetOffTime(offTime);
535 fSettings.SetSuspendTime(offTime);
536 fSettings.SetStandByTime(offTime);
537 fSettings.SetBlankCorner(fFadeNow->Corner());
538 fSettings.SetNeverBlankCorner(fFadeNever->Corner());
539 fSettings.SetLockEnable(fPasswordCheckBox->Value());
540 fSettings.SetPasswordTime(fPasswordSlider->Time());
542 // TODO - Tell the password window to update its stuff
546 void
547 FadeView::_UpdateColors()
549 rgb_color color = ui_color(B_PANEL_TEXT_COLOR);
550 fFadeNeverText->SetFontAndColor(be_plain_font, 0, &color);
551 fFadeNowText->SetFontAndColor(be_plain_font, 0, &color);
555 // #pragma mark - ModulesView
558 ModulesView::ModulesView(const char* name, ScreenSaverSettings& settings)
560 BView(name, B_WILL_DRAW),
561 fSettings(settings),
562 fScreenSaversListView(new BListView("SaversListView")),
563 fTestButton(new BButton("TestButton", B_TRANSLATE("Test"),
564 new BMessage(kMsgTestSaver))),
565 fSaverRunner(NULL),
566 fSettingsBox(new BBox("SettingsBox")),
567 fSettingsView(NULL),
568 fPreviewView(new PreviewView("preview")),
569 fScreenSaverTestTeam(-1)
571 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
573 fScreenSaversListView->SetSelectionMessage(
574 new BMessage(kMsgSaverSelected));
575 BScrollView* saversListScrollView = new BScrollView("scroll_list",
576 fScreenSaversListView, 0, false, true);
578 fSettingsBox->SetLabel(B_TRANSLATE("Screensaver settings"));
579 fSettingsBox->SetExplicitMinSize(BSize(
580 floorf(be_control_look->DefaultItemSpacing()
581 * ((kWindowWidth - 157.0f) / kDefaultItemSpacingAt12pt)),
582 B_SIZE_UNSET));
584 BLayoutBuilder::Group<>(this, B_HORIZONTAL)
585 .SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
586 B_USE_WINDOW_SPACING, 0)
587 .AddGroup(B_VERTICAL)
588 .Add(fPreviewView)
589 .Add(saversListScrollView)
590 .AddGroup(B_HORIZONTAL)
591 .Add(fTestButton)
592 .AddGlue()
593 .End()
594 .End()
595 .Add(fSettingsBox)
596 .End();
600 ModulesView::~ModulesView()
602 delete fTestButton;
603 delete fSettingsBox;
604 delete fPreviewView;
608 void
609 ModulesView::DetachedFromWindow()
611 SaveState();
612 EmptyScreenSaverList();
614 _CloseSaver();
618 void
619 ModulesView::AttachedToWindow()
621 fScreenSaversListView->SetTarget(this);
622 fTestButton->SetTarget(this);
626 void
627 ModulesView::AllAttached()
629 PopulateScreenSaverList();
630 fScreenSaversListView->Invoke();
634 void
635 ModulesView::MessageReceived(BMessage* message)
637 switch (message->what) {
638 case kMsgSaverSelected:
640 int32 selection = fScreenSaversListView->CurrentSelection();
641 if (selection < 0)
642 break;
644 ScreenSaverItem* item
645 = (ScreenSaverItem*)fScreenSaversListView->ItemAt(selection);
646 if (item == NULL)
647 break;
649 if (strcmp(item->Text(), B_TRANSLATE("Blackness")) == 0)
650 fSettings.SetModuleName("");
651 else
652 fSettings.SetModuleName(item->Text());
654 SaveState();
655 _CloseSaver();
656 _OpenSaver();
657 fSettings.Save();
658 break;
661 case kMsgTestSaver:
663 SaveState();
664 fSettings.Save();
666 _CloseSaver();
668 be_roster->StartWatching(BMessenger(this, Looper()),
669 B_REQUEST_QUIT);
670 BMessage message(kMsgTestSaver);
671 if (be_roster->Launch(SCREEN_BLANKER_SIG, &message,
672 &fScreenSaverTestTeam) == B_OK) {
673 break;
676 // Try really hard to launch it. It's very likely that this fails
677 // when we run from the CD, and there is only an incomplete mime
678 // database for example...
679 BPath path;
680 if (find_directory(B_SYSTEM_BIN_DIRECTORY, &path) != B_OK
681 || path.Append("screen_blanker") != B_OK) {
682 path.SetTo("/bin/screen_blanker");
685 BEntry entry(path.Path());
686 entry_ref ref;
687 if (entry.GetRef(&ref) == B_OK) {
688 be_roster->Launch(&ref, &message,
689 &fScreenSaverTestTeam);
691 break;
694 case B_SOME_APP_QUIT:
696 team_id team;
697 if (message->FindInt32("be:team", &team) == B_OK
698 && team == fScreenSaverTestTeam) {
699 be_roster->StopWatching(this);
700 _OpenSaver();
702 break;
705 default:
706 BView::MessageReceived(message);
711 void
712 ModulesView::SaveState()
714 BScreenSaver* saver = ScreenSaver();
715 if (saver == NULL)
716 return;
718 BMessage state;
719 if (saver->SaveState(&state) == B_OK)
720 fSettings.SetModuleState(fCurrentName.String(), &state);
724 void
725 ModulesView::EmptyScreenSaverList()
727 fScreenSaversListView->DeselectAll();
728 while (BListItem* item = fScreenSaversListView->RemoveItem((int32)0))
729 delete item;
733 void
734 ModulesView::PopulateScreenSaverList()
736 // Blackness is a built-in screen saver
737 ScreenSaverItem* defaultItem
738 = new ScreenSaverItem(B_TRANSLATE("Blackness"), "");
739 fScreenSaversListView->AddItem(defaultItem);
741 // Iterate over add-on directories, and add their files to the list view
743 directory_which which[] = {
744 B_USER_NONPACKAGED_ADDONS_DIRECTORY,
745 B_USER_ADDONS_DIRECTORY,
746 B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY,
747 B_SYSTEM_ADDONS_DIRECTORY,
749 ScreenSaverItem* selectedItem = NULL;
751 for (uint32 i = 0; i < sizeof(which) / sizeof(which[0]); i++) {
752 BPath basePath;
753 if (find_directory(which[i], &basePath) != B_OK)
754 continue;
755 else if (basePath.Append("Screen Savers", true) != B_OK)
756 continue;
758 BDirectory dir(basePath.Path());
759 BEntry entry;
760 while (dir.GetNextEntry(&entry, true) == B_OK) {
761 char name[B_FILE_NAME_LENGTH];
762 if (entry.GetName(name) != B_OK)
763 continue;
765 BPath path(basePath);
766 if (path.Append(name) != B_OK)
767 continue;
769 ScreenSaverItem* item = new ScreenSaverItem(name, path.Path());
770 fScreenSaversListView->AddItem(item);
772 if (selectedItem != NULL)
773 continue;
775 if (strcmp(fSettings.ModuleName(), item->Text()) == 0)
776 selectedItem = item;
780 fScreenSaversListView->SortItems(_CompareScreenSaverItems);
781 if (selectedItem == NULL)
782 selectedItem = defaultItem;
784 fScreenSaversListView->Select(fScreenSaversListView->IndexOf(selectedItem));
785 fScreenSaversListView->ScrollToSelection();
789 //! Sorting function for ScreenSaverItems
791 ModulesView::_CompareScreenSaverItems(const void* left, const void* right)
793 ScreenSaverItem* leftItem = *(ScreenSaverItem **)left;
794 ScreenSaverItem* rightItem = *(ScreenSaverItem **)right;
796 return strcasecmp(leftItem->Text(), rightItem->Text());
800 BScreenSaver*
801 ModulesView::ScreenSaver()
803 if (fSaverRunner != NULL)
804 return fSaverRunner->ScreenSaver();
806 return NULL;
810 void
811 ModulesView::_CloseSaver()
813 // remove old screen saver preview & config
815 BScreenSaver* saver = ScreenSaver();
816 BView* view = fPreviewView->RemovePreview();
817 if (fSettingsView != NULL)
818 fSettingsBox->RemoveChild(fSettingsView);
820 if (fSaverRunner != NULL)
821 fSaverRunner->Quit();
823 if (saver != NULL)
824 saver->StopConfig();
826 delete view;
827 delete fSettingsView;
828 delete fSaverRunner;
829 // the saver runner also unloads the add-on, so it must
830 // be deleted last
832 fSettingsView = NULL;
833 fSaverRunner = NULL;
837 void
838 ModulesView::_OpenSaver()
840 // create new screen saver preview & config
842 BView* view = fPreviewView->AddPreview();
843 fCurrentName = fSettings.ModuleName();
844 fSaverRunner = new ScreenSaverRunner(view->Window(), view, fSettings);
846 #ifdef __HAIKU__
847 BRect rect = fSettingsBox->InnerFrame().InsetByCopy(4, 4);
848 #else
849 BRect rect = fSettingsBox->Bounds().InsetByCopy(4, 4);
850 rect.top += 14;
851 #endif
852 fSettingsView = new BView(rect, "SettingsView", B_FOLLOW_ALL, B_WILL_DRAW);
854 fSettingsView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
855 fSettingsBox->AddChild(fSettingsView);
857 BScreenSaver* saver = ScreenSaver();
858 if (saver != NULL && fSettingsView != NULL) {
859 saver->StartConfig(fSettingsView);
860 if (saver->StartSaver(view, true) == B_OK) {
861 fPreviewView->HideNoPreview();
862 fSaverRunner->Run();
863 } else
864 fPreviewView->ShowNoPreview();
865 } else {
866 // Failed to load OR this is the "Blackness" screensaver. Show a black
867 // preview (this is what will happen in both cases when screen_blanker
868 // runs).
869 fPreviewView->HideNoPreview();
872 if (fSettingsView->ChildAt(0) == NULL) {
873 // There are no settings at all, we add the module name here to
874 // let it look a bit better at least.
875 BPrivate::BuildDefaultSettingsView(fSettingsView,
876 fSettings.ModuleName()[0] ? fSettings.ModuleName()
877 : B_TRANSLATE("Blackness"),
878 saver != NULL || !fSettings.ModuleName()[0]
879 ? B_TRANSLATE("No options available")
880 : B_TRANSLATE("Could not load screen saver"));
885 // #pragma mark - TabView
888 TabView::TabView()
890 BTabView("tab_view", B_WIDTH_FROM_LABEL)
895 void
896 TabView::MouseDown(BPoint where)
898 BTab* fadeTab = TabAt(0);
899 BRect fadeTabFrame(TabFrame(0));
900 BTab* modulesTab = TabAt(1);
901 BRect modulesTabFrame(TabFrame(1));
902 ModulesView* modulesView = dynamic_cast<ModulesView*>(modulesTab->View());
904 if (fadeTab != NULL && Selection() != 0 && fadeTabFrame.Contains(where)
905 && modulesView != NULL) {
906 // clicked on the fade tab
907 modulesView->SaveState();
908 modulesView->_CloseSaver();
909 } else if (modulesTab != NULL && Selection() != 1
910 && modulesTabFrame.Contains(where) && modulesView != NULL) {
911 // clicked on the modules tab
912 BMessage message(kMsgSaverSelected);
913 modulesView->MessageReceived(&message);
916 BTabView::MouseDown(where);
920 // #pragma mark - ScreenSaverWindow
923 ScreenSaverWindow::ScreenSaverWindow()
925 BWindow(BRect(50.0f, 50.0f, 50.0f + kWindowWidth, 50.0f + kWindowHeight),
926 B_TRANSLATE_SYSTEM_NAME("ScreenSaver"), B_TITLED_WINDOW,
927 B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS)
929 fSettings.Load();
931 fMinWidth = floorf(be_control_look->DefaultItemSpacing()
932 * (kWindowWidth / kDefaultItemSpacingAt12pt));
934 font_height fontHeight;
935 be_plain_font->GetHeight(&fontHeight);
936 float textHeight = ceilf(fontHeight.ascent + fontHeight.descent);
938 fMinHeight = ceilf(std::max(kWindowHeight, textHeight * 28));
940 // Create the password editing window
941 fPasswordWindow = new PasswordWindow(fSettings);
942 fPasswordWindow->Run();
944 // Create the tab view
945 fTabView = new TabView();
946 fTabView->SetBorder(B_NO_BORDER);
948 // Create the controls inside the tabs
949 fFadeView = new FadeView(B_TRANSLATE("General"), fSettings);
950 fModulesView = new ModulesView(B_TRANSLATE("Screensavers"), fSettings);
952 fTabView->AddTab(fFadeView);
953 fTabView->AddTab(fModulesView);
955 // Create the topmost background view
956 BView* topView = new BView("topView", B_WILL_DRAW);
957 topView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
958 topView->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH,
959 B_ALIGN_USE_FULL_HEIGHT));
960 topView->SetExplicitMinSize(BSize(fMinWidth, fMinHeight));
961 BLayoutBuilder::Group<>(topView, B_VERTICAL)
962 .SetInsets(0, B_USE_DEFAULT_SPACING, 0, B_USE_WINDOW_SPACING)
963 .Add(fTabView)
964 .End();
966 SetLayout(new BGroupLayout(B_VERTICAL));
967 GetLayout()->AddView(topView);
969 fTabView->Select(fSettings.WindowTab());
971 if (fSettings.WindowFrame().left > 0 && fSettings.WindowFrame().top > 0)
972 MoveTo(fSettings.WindowFrame().left, fSettings.WindowFrame().top);
974 if (fSettings.WindowFrame().Width() > 0
975 && fSettings.WindowFrame().Height() > 0) {
976 ResizeTo(fSettings.WindowFrame().Width(),
977 fSettings.WindowFrame().Height());
980 CenterOnScreen();
984 ScreenSaverWindow::~ScreenSaverWindow()
986 Hide();
987 fFadeView->UpdateStatus();
988 fSettings.SetWindowTab(fTabView->Selection());
990 delete fTabView->RemoveTab(1);
991 // We delete this here in order to make sure the module view saves its
992 // state while the window is still intact.
994 fSettings.Save();
998 void
999 ScreenSaverWindow::MessageReceived(BMessage* message)
1001 switch (message->what) {
1002 case kMsgChangePassword:
1003 fPasswordWindow->CenterIn(Frame());
1004 fPasswordWindow->Show();
1005 break;
1007 case kMsgUpdateList:
1008 fModulesView->EmptyScreenSaverList();
1009 fModulesView->PopulateScreenSaverList();
1010 break;
1012 default:
1013 BWindow::MessageReceived(message);
1018 void
1019 ScreenSaverWindow::ScreenChanged(BRect frame, color_space colorSpace)
1021 fFadeView->UpdateTurnOffScreen();
1025 bool
1026 ScreenSaverWindow::QuitRequested()
1028 be_app->PostMessage(B_QUIT_REQUESTED);
1029 return true;