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