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