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