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