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