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