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