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