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 #include <strings.h> 17 18 #include <Alignment.h> 19 #include <Application.h> 20 #include <Box.h> 21 #include <Button.h> 22 #include <Catalog.h> 23 #include <CheckBox.h> 24 #include <ControlLook.h> 25 #include <Directory.h> 26 #include <DurationFormat.h> 27 #include <Entry.h> 28 #include <File.h> 29 #include <FindDirectory.h> 30 #include <Font.h> 31 #include <Layout.h> 32 #include <LayoutBuilder.h> 33 #include <ListItem.h> 34 #include <ListView.h> 35 #include <Path.h> 36 #include <Rect.h> 37 #include <Roster.h> 38 #include <Screen.h> 39 #include <ScreenSaver.h> 40 #include <ScreenSaverRunner.h> 41 #include <ScrollView.h> 42 #include <Size.h> 43 #include <Slider.h> 44 #include <StringView.h> 45 #include <TabView.h> 46 #include <TextView.h> 47 48 #include <algorithm> 49 // for std::max and std::min 50 51 #include <BuildScreenSaverDefaultSettingsView.h> 52 53 #include "PreviewView.h" 54 #include "ScreenCornerSelector.h" 55 #include "ScreenSaverItem.h" 56 57 58 #undef B_TRANSLATION_CONTEXT 59 #define B_TRANSLATION_CONTEXT "ScreenSaver" 60 61 62 const uint32 kPreviewMonitorGap = 16; 63 const uint32 kMinSettingsWidth = 230; 64 const uint32 kMinSettingsHeight = 120; 65 66 const int32 kMsgSaverSelected = 'SSEL'; 67 const int32 kMsgTestSaver = 'TEST'; 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(0, useconds, &string); 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 if (be_roster->Launch(SCREEN_BLANKER_SIG, &fSettings.Message(), 643 &fScreenSaverTestTeam) == B_OK) { 644 break; 645 } 646 647 // Try really hard to launch it. It's very likely that this fails 648 // when we run from the CD, and there is only an incomplete mime 649 // database for example... 650 BPath path; 651 if (find_directory(B_SYSTEM_BIN_DIRECTORY, &path) != B_OK 652 || path.Append("screen_blanker") != B_OK) { 653 path.SetTo("/bin/screen_blanker"); 654 } 655 656 BEntry entry(path.Path()); 657 entry_ref ref; 658 if (entry.GetRef(&ref) == B_OK) { 659 be_roster->Launch(&ref, &fSettings.Message(), 660 &fScreenSaverTestTeam); 661 } 662 break; 663 } 664 665 case B_SOME_APP_QUIT: 666 { 667 team_id team; 668 if (message->FindInt32("be:team", &team) == B_OK 669 && team == fScreenSaverTestTeam) { 670 be_roster->StopWatching(this); 671 _OpenSaver(); 672 } 673 break; 674 } 675 676 default: 677 BView::MessageReceived(message); 678 } 679 } 680 681 682 void 683 ModulesView::SaveState() 684 { 685 BScreenSaver* saver = ScreenSaver(); 686 if (saver == NULL) 687 return; 688 689 BMessage state; 690 if (saver->SaveState(&state) == B_OK) 691 fSettings.SetModuleState(fCurrentName.String(), &state); 692 } 693 694 695 void 696 ModulesView::EmptyScreenSaverList() 697 { 698 fScreenSaversListView->DeselectAll(); 699 while (BListItem* item = fScreenSaversListView->RemoveItem((int32)0)) 700 delete item; 701 } 702 703 704 void 705 ModulesView::PopulateScreenSaverList() 706 { 707 // Blackness is a built-in screen saver 708 ScreenSaverItem* defaultItem 709 = new ScreenSaverItem(B_TRANSLATE("Blackness"), ""); 710 fScreenSaversListView->AddItem(defaultItem); 711 712 // Iterate over add-on directories, and add their files to the list view 713 714 directory_which which[] = { 715 B_USER_NONPACKAGED_ADDONS_DIRECTORY, 716 B_USER_ADDONS_DIRECTORY, 717 B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY, 718 B_SYSTEM_ADDONS_DIRECTORY, 719 }; 720 ScreenSaverItem* selectedItem = NULL; 721 722 for (uint32 i = 0; i < sizeof(which) / sizeof(which[0]); i++) { 723 BPath basePath; 724 if (find_directory(which[i], &basePath) != B_OK) 725 continue; 726 else if (basePath.Append("Screen Savers", true) != B_OK) 727 continue; 728 729 BDirectory dir(basePath.Path()); 730 BEntry entry; 731 while (dir.GetNextEntry(&entry, true) == B_OK) { 732 char name[B_FILE_NAME_LENGTH]; 733 if (entry.GetName(name) != B_OK) 734 continue; 735 736 BPath path(basePath); 737 if (path.Append(name) != B_OK) 738 continue; 739 740 ScreenSaverItem* item = new ScreenSaverItem(name, path.Path()); 741 fScreenSaversListView->AddItem(item); 742 743 if (selectedItem != NULL) 744 continue; 745 746 if (strcmp(fSettings.ModuleName(), item->Text()) == 0) 747 selectedItem = item; 748 } 749 } 750 751 fScreenSaversListView->SortItems(_CompareScreenSaverItems); 752 if (selectedItem == NULL) 753 selectedItem = defaultItem; 754 755 fScreenSaversListView->Select(fScreenSaversListView->IndexOf(selectedItem)); 756 fScreenSaversListView->ScrollToSelection(); 757 } 758 759 760 //! Sorting function for ScreenSaverItems 761 int 762 ModulesView::_CompareScreenSaverItems(const void* left, const void* right) 763 { 764 ScreenSaverItem* leftItem = *(ScreenSaverItem **)left; 765 ScreenSaverItem* rightItem = *(ScreenSaverItem **)right; 766 767 return strcasecmp(leftItem->Text(), rightItem->Text()); 768 } 769 770 771 BScreenSaver* 772 ModulesView::ScreenSaver() 773 { 774 if (fSaverRunner != NULL) 775 return fSaverRunner->ScreenSaver(); 776 777 return NULL; 778 } 779 780 781 void 782 ModulesView::_CloseSaver() 783 { 784 // remove old screen saver preview & config 785 786 BScreenSaver* saver = ScreenSaver(); 787 BView* view = fPreviewView->RemovePreview(); 788 if (fSettingsView != NULL) 789 fSettingsBox->RemoveChild(fSettingsView); 790 791 if (fSaverRunner != NULL) 792 fSaverRunner->Quit(); 793 794 if (saver != NULL) 795 saver->StopConfig(); 796 797 delete view; 798 delete fSettingsView; 799 delete fSaverRunner; 800 // the saver runner also unloads the add-on, so it must 801 // be deleted last 802 803 fSettingsView = NULL; 804 fSaverRunner = NULL; 805 } 806 807 808 void 809 ModulesView::_OpenSaver() 810 { 811 // create new screen saver preview & config 812 813 BView* view = fPreviewView->AddPreview(); 814 fCurrentName = fSettings.ModuleName(); 815 fSaverRunner = new ScreenSaverRunner(view->Window(), view, fSettings); 816 817 #ifdef __HAIKU__ 818 BRect rect = fSettingsBox->InnerFrame().InsetByCopy(4, 4); 819 #else 820 BRect rect = fSettingsBox->Bounds().InsetByCopy(4, 4); 821 rect.top += 14; 822 #endif 823 fSettingsView = new BView(rect, "SettingsView", B_FOLLOW_ALL, B_WILL_DRAW); 824 825 fSettingsView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 826 fSettingsBox->AddChild(fSettingsView); 827 828 BScreenSaver* saver = ScreenSaver(); 829 if (saver != NULL && fSettingsView != NULL) { 830 saver->StartConfig(fSettingsView); 831 if (saver->StartSaver(view, true) == B_OK) { 832 fPreviewView->HideNoPreview(); 833 fSaverRunner->Run(); 834 } else 835 fPreviewView->ShowNoPreview(); 836 } else 837 fPreviewView->ShowNoPreview(); 838 839 if (fSettingsView->ChildAt(0) == NULL) { 840 // There are no settings at all, we add the module name here to 841 // let it look a bit better at least. 842 BPrivate::BuildScreenSaverDefaultSettingsView(fSettingsView, 843 fSettings.ModuleName()[0] ? fSettings.ModuleName() 844 : B_TRANSLATE("Blackness"), 845 saver != NULL || !fSettings.ModuleName()[0] 846 ? B_TRANSLATE("No options available") 847 : B_TRANSLATE("Could not load screen saver")); 848 } 849 } 850 851 852 // #pragma mark - TabView 853 854 855 TabView::TabView() 856 : 857 BTabView("tab_view", B_WIDTH_FROM_LABEL) 858 { 859 } 860 861 862 void 863 TabView::MouseDown(BPoint where) 864 { 865 BTab* fadeTab = TabAt(0); 866 BRect fadeTabFrame(TabFrame(0)); 867 BTab* modulesTab = TabAt(1); 868 BRect modulesTabFrame(TabFrame(1)); 869 ModulesView* modulesView = dynamic_cast<ModulesView*>(modulesTab->View()); 870 871 if (fadeTab != NULL && Selection() != 0 && fadeTabFrame.Contains(where) 872 && modulesView != NULL) { 873 // clicked on the fade tab 874 modulesView->SaveState(); 875 modulesView->_CloseSaver(); 876 } else if (modulesTab != NULL && Selection() != 1 877 && modulesTabFrame.Contains(where) && modulesView != NULL) { 878 // clicked on the modules tab 879 BMessage message(kMsgSaverSelected); 880 modulesView->MessageReceived(&message); 881 } 882 883 BTabView::MouseDown(where); 884 } 885 886 887 // #pragma mark - ScreenSaverWindow 888 889 890 ScreenSaverWindow::ScreenSaverWindow() 891 : 892 BWindow(BRect(50, 50, 496, 375), 893 B_TRANSLATE_SYSTEM_NAME("ScreenSaver"), B_TITLED_WINDOW, 894 B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS) 895 { 896 fSettings.Load(); 897 898 fMinWidth = ceilf(std::max(446.0f, 899 be_control_look->DefaultItemSpacing() * 44.6f)); 900 901 font_height fontHeight; 902 be_plain_font->GetHeight(&fontHeight); 903 float textHeight = ceilf(fontHeight.ascent + fontHeight.descent); 904 905 fMinHeight = ceilf(std::max(325.0f, textHeight * 28)); 906 907 // Create the password editing window 908 fPasswordWindow = new PasswordWindow(fSettings); 909 fPasswordWindow->Run(); 910 911 // Create the tab view 912 fTabView = new TabView(); 913 fTabView->SetBorder(B_NO_BORDER); 914 915 // Create the controls inside the tabs 916 fFadeView = new FadeView(B_TRANSLATE("General"), fSettings); 917 fModulesView = new ModulesView(B_TRANSLATE("Screensavers"), fSettings); 918 919 fTabView->AddTab(fFadeView); 920 fTabView->AddTab(fModulesView); 921 922 // Create the topmost background view 923 BView* topView = new BView("topView", B_WILL_DRAW); 924 topView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 925 topView->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH, 926 B_ALIGN_USE_FULL_HEIGHT)); 927 topView->SetExplicitMinSize(BSize(fMinWidth, fMinHeight)); 928 BLayoutBuilder::Group<>(topView, B_VERTICAL) 929 .SetInsets(0, B_USE_SMALL_SPACING, 0, 0) 930 .Add(fTabView) 931 .End(); 932 933 SetLayout(new BGroupLayout(B_VERTICAL)); 934 GetLayout()->AddView(topView); 935 936 fTabView->Select(fSettings.WindowTab()); 937 938 if (fSettings.WindowFrame().left > 0 && fSettings.WindowFrame().top > 0) 939 MoveTo(fSettings.WindowFrame().left, fSettings.WindowFrame().top); 940 941 if (fSettings.WindowFrame().Width() > 0 942 && fSettings.WindowFrame().Height() > 0) { 943 ResizeTo(fSettings.WindowFrame().Width(), 944 fSettings.WindowFrame().Height()); 945 } 946 } 947 948 949 ScreenSaverWindow::~ScreenSaverWindow() 950 { 951 Hide(); 952 fFadeView->UpdateStatus(); 953 fSettings.SetWindowTab(fTabView->Selection()); 954 955 delete fTabView->RemoveTab(1); 956 // We delete this here in order to make sure the module view saves its 957 // state while the window is still intact. 958 959 fSettings.Save(); 960 } 961 962 963 void 964 ScreenSaverWindow::MessageReceived(BMessage* message) 965 { 966 switch (message->what) { 967 case kMsgChangePassword: 968 fPasswordWindow->CenterIn(Frame()); 969 fPasswordWindow->Show(); 970 break; 971 972 case kMsgUpdateList: 973 fModulesView->EmptyScreenSaverList(); 974 fModulesView->PopulateScreenSaverList(); 975 break; 976 977 default: 978 BWindow::MessageReceived(message); 979 } 980 } 981 982 983 void 984 ScreenSaverWindow::ScreenChanged(BRect frame, color_space colorSpace) 985 { 986 fFadeView->UpdateTurnOffScreen(); 987 } 988 989 990 bool 991 ScreenSaverWindow::QuitRequested() 992 { 993 be_app->PostMessage(B_QUIT_REQUESTED); 994 return true; 995 } 996