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