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