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