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_TRANSLATION_CONTEXT 44 #define B_TRANSLATION_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("/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_USER_NONPACKAGED_ADDONS_DIRECTORY, 446 B_USER_ADDONS_DIRECTORY, 447 B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, 448 B_COMMON_ADDONS_DIRECTORY, 449 B_SYSTEM_ADDONS_DIRECTORY, 450 }; 451 ScreenSaverItem* selectItem = NULL; 452 453 for (uint32 i = 0; i < sizeof(which) / sizeof(which[0]); i++) { 454 BPath basePath; 455 find_directory(which[i], &basePath); 456 basePath.Append("Screen Savers", true); 457 458 BDirectory dir(basePath.Path()); 459 BEntry entry; 460 while (dir.GetNextEntry(&entry, true) == B_OK) { 461 char name[B_FILE_NAME_LENGTH]; 462 if (entry.GetName(name) != B_OK) 463 continue; 464 465 BPath path = basePath; 466 path.Append(name); 467 468 ScreenSaverItem* item = new ScreenSaverItem(name, path.Path()); 469 fListView->AddItem(item); 470 471 if (!strcmp(fSettings.ModuleName(), item->Text()) 472 || (!strcmp(fSettings.ModuleName(), "") 473 && !strcmp(item->Text(), B_TRANSLATE("Blackness")))) 474 selectItem = item; 475 } 476 } 477 478 fListView->SortItems(_CompareScreenSaverItems); 479 480 fListView->Select(fListView->IndexOf(selectItem)); 481 fListView->ScrollToSelection(); 482 } 483 484 485 //! Sorting function for ScreenSaverItems 486 int 487 ModulesView::_CompareScreenSaverItems(const void* left, const void* right) 488 { 489 ScreenSaverItem* leftItem = *(ScreenSaverItem **)left; 490 ScreenSaverItem* rightItem = *(ScreenSaverItem **)right; 491 492 return strcasecmp(leftItem->Text(), rightItem->Text()); 493 } 494 495 496 BScreenSaver* 497 ModulesView::_ScreenSaver() 498 { 499 if (fSaverRunner != NULL) 500 return fSaverRunner->ScreenSaver(); 501 502 return NULL; 503 } 504 505 506 void 507 ModulesView::_CloseSaver() 508 { 509 // remove old screen saver preview & config 510 511 BScreenSaver* saver = _ScreenSaver(); 512 BView* view = fPreviewView->RemovePreview(); 513 if (fSettingsView != NULL) 514 fSettingsBox->RemoveChild(fSettingsView); 515 516 if (fSaverRunner != NULL) 517 fSaverRunner->Quit(); 518 if (saver != NULL) 519 saver->StopConfig(); 520 521 delete view; 522 delete fSettingsView; 523 delete fSaverRunner; 524 // the saver runner also unloads the add-on, so it must 525 // be deleted last 526 527 fSettingsView = NULL; 528 fSaverRunner = NULL; 529 } 530 531 532 void 533 ModulesView::_OpenSaver() 534 { 535 // create new screen saver preview & config 536 537 BView* view = fPreviewView->AddPreview(); 538 fCurrentName = fSettings.ModuleName(); 539 fSaverRunner = new ScreenSaverRunner(Window(), view, true, fSettings); 540 BScreenSaver* saver = _ScreenSaver(); 541 542 #ifdef __HAIKU__ 543 BRect rect = fSettingsBox->InnerFrame().InsetByCopy(4, 4); 544 #else 545 BRect rect = fSettingsBox->Bounds().InsetByCopy(4, 4); 546 rect.top += 14; 547 #endif 548 fSettingsView = new BView(rect, "SettingsView", B_FOLLOW_ALL, B_WILL_DRAW); 549 fSettingsView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 550 fSettingsBox->AddChild(fSettingsView); 551 552 if (saver != NULL) { 553 fSaverRunner->Run(); 554 saver->StartConfig(fSettingsView); 555 } 556 557 if (fSettingsView->ChildAt(0) == NULL) { 558 // There are no settings at all, we add the module name here to 559 // let it look a bit better at least. 560 BPrivate::BuildScreenSaverDefaultSettingsView(fSettingsView, 561 fSettings.ModuleName()[0] ? fSettings.ModuleName() : 562 B_TRANSLATE("Blackness"), saver || !fSettings.ModuleName()[0] 563 ? B_TRANSLATE("No options available") : 564 B_TRANSLATE("Could not load screen saver")); 565 } 566 567 ScreenSaverWindow* window = dynamic_cast<ScreenSaverWindow*>(Window()); 568 if (window == NULL) 569 return; 570 571 // find the minimal size of the settings view 572 573 float right = 0, bottom = 0; 574 int32 i = 0; 575 while ((view = fSettingsView->ChildAt(i++)) != NULL) { 576 // very simple heuristic... 577 float viewRight = view->Frame().right; 578 if ((view->ResizingMode() & _rule_(0, 0xf, 0, 0xf)) 579 == B_FOLLOW_LEFT_RIGHT) { 580 float width, height; 581 view->GetPreferredSize(&width, &height); 582 viewRight = view->Frame().left + width / 2; 583 } else if ((view->ResizingMode() & _rule_(0, 0xf, 0, 0xf)) 584 == B_FOLLOW_RIGHT) 585 viewRight = 8 + view->Frame().Width(); 586 587 float viewBottom = view->Frame().bottom; 588 if ((view->ResizingMode() & _rule_(0xf, 0, 0xf, 0)) 589 == B_FOLLOW_TOP_BOTTOM) { 590 float width, height; 591 view->GetPreferredSize(&width, &height); 592 viewBottom = view->Frame().top + height; 593 } else if ((view->ResizingMode() & _rule_(0xf, 0, 0xf, 0)) 594 == B_FOLLOW_BOTTOM) 595 viewBottom = 8 + view->Frame().Height(); 596 597 if (viewRight > right) 598 right = viewRight; 599 if (viewBottom > bottom) 600 bottom = viewBottom; 601 } 602 603 if (right < kMinSettingsWidth) 604 right = kMinSettingsWidth; 605 if (bottom < kMinSettingsHeight) 606 bottom = kMinSettingsHeight; 607 608 BPoint leftTop = fSettingsView->LeftTop(); 609 fSettingsView->ConvertToScreen(&leftTop); 610 window->ConvertFromScreen(&leftTop); 611 window->SetMinimalSizeLimit(leftTop.x + right + 16, 612 leftTop.y + bottom + 16); 613 } 614 615 616 // #pragma mark - 617 618 619 ScreenSaverWindow::ScreenSaverWindow() 620 : 621 BWindow(BRect(50, 50, 496, 375), B_TRANSLATE_SYSTEM_NAME("ScreenSaver"), 622 B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS) 623 { 624 fSettings.Load(); 625 626 BRect rect = Bounds(); 627 fMinWidth = 430; 628 fMinHeight = 325; 629 630 // Create a background view 631 BView *background = new BView(rect, "background", B_FOLLOW_ALL, 0); 632 background->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 633 AddChild(background); 634 635 // Add the tab view to the background 636 rect.top += 4; 637 fTabView = new BTabView(rect, "tab_view"); 638 639 // Create the controls inside the tabs 640 rect = fTabView->ContainerView()->Bounds(); 641 _SetupFadeTab(rect); 642 fModulesView = new ModulesView(rect, B_TRANSLATE("Screensavers"), fSettings); 643 644 fTabView->AddTab(fFadeView); 645 fTabView->AddTab(fModulesView); 646 background->AddChild(fTabView); 647 648 // Create the password editing window 649 fPasswordWindow = new PasswordWindow(fSettings); 650 fPasswordWindow->Run(); 651 652 SetMinimalSizeLimit(fMinWidth, fMinHeight); 653 MoveTo(fSettings.WindowFrame().left, fSettings.WindowFrame().top); 654 ResizeTo(fSettings.WindowFrame().Width(), fSettings.WindowFrame().Height()); 655 656 fEnableCheckBox->SetValue( 657 fSettings.TimeFlags() & ENABLE_SAVER ? B_CONTROL_ON : B_CONTROL_OFF); 658 fRunSlider->SetTime(fSettings.BlankTime()); 659 fTurnOffSlider->SetTime(fSettings.OffTime() + fSettings.BlankTime()); 660 fFadeNow->SetCorner(fSettings.BlankCorner()); 661 fFadeNever->SetCorner(fSettings.NeverBlankCorner()); 662 fPasswordCheckBox->SetValue(fSettings.LockEnable()); 663 fPasswordSlider->SetTime(fSettings.PasswordTime()); 664 665 fTabView->Select(fSettings.WindowTab()); 666 667 _UpdateTurnOffScreen(); 668 _UpdateStatus(); 669 } 670 671 672 ScreenSaverWindow::~ScreenSaverWindow() 673 { 674 Hide(); 675 _UpdateStatus(); 676 677 delete fTabView->RemoveTab(1); 678 // We delete this here in order to make sure the module view saves its 679 // state while the window is still intact. 680 681 fSettings.Save(); 682 } 683 684 685 //! Create the controls for the "General" tab 686 void 687 ScreenSaverWindow::_SetupFadeTab(BRect rect) 688 { 689 fFadeView = new FadeView(rect, B_TRANSLATE("General"), fSettings); 690 691 float StringWidth1 = be_plain_font->StringWidth(B_TRANSLATE 692 ("Start screensaver")); 693 float StringWidth2 = be_plain_font->StringWidth(B_TRANSLATE 694 ("Turn off screen")); 695 float StringWidth3 = be_plain_font->StringWidth(B_TRANSLATE 696 ("Password lock")); 697 698 float labelWidth = StringWidth1; 699 if (labelWidth < StringWidth2) 700 labelWidth = StringWidth2; 701 if (labelWidth < StringWidth3) 702 labelWidth = StringWidth3; 703 704 labelWidth += 20.0f; 705 706 font_height fontHeight; 707 be_plain_font->GetHeight(&fontHeight); 708 float textHeight = ceilf(fontHeight.ascent + fontHeight.descent); 709 710 // taken from BRadioButton: 711 float radioButtonOffset = 2 * floorf(textHeight / 2 - 2) 712 + floorf(textHeight / 2); 713 714 fEnableCheckBox = new BCheckBox(BRect(0, 0, 1, 1), "EnableCheckBox", 715 B_TRANSLATE("Enable screensaver"), 716 new BMessage(kMsgEnableScreenSaverBox)); 717 fEnableCheckBox->ResizeToPreferred(); 718 719 rect.InsetBy(8, 8); 720 BBox* box = new BBox(rect, "EnableScreenSaverBox", B_FOLLOW_ALL); 721 box->SetLabel(fEnableCheckBox); 722 fFadeView->AddChild(box); 723 724 // Start Screensaver 725 rect.left += radioButtonOffset + 6; 726 rect.top = fEnableCheckBox->Bounds().bottom + 8.0f; 727 rect.right = box->Bounds().right - 8; 728 BStringView* stringView = new BStringView(rect, NULL, 729 B_TRANSLATE("Start screensaver")); 730 stringView->ResizeToPreferred(); 731 box->AddChild(stringView); 732 733 rect.left += labelWidth - 4; 734 fRunSlider = new TimeSlider(rect, "RunSlider", kMsgRunSliderChanged, 735 kMsgRunSliderUpdate); 736 float width, height; 737 fRunSlider->GetPreferredSize(&width, &height); 738 fRunSlider->ResizeTo(fRunSlider->Bounds().Width(), height); 739 box->AddChild(fRunSlider); 740 741 // Turn Off 742 rect.left = 10; 743 rect.OffsetBy(0, fRunSlider->Bounds().Height() + 4.0f); 744 fTurnOffCheckBox = new BCheckBox(rect, "TurnOffScreenCheckBox", 745 B_TRANSLATE("Turn off screen"), new BMessage(kMsgTurnOffCheckBox)); 746 fTurnOffCheckBox->ResizeToPreferred(); 747 box->AddChild(fTurnOffCheckBox); 748 749 rect.top += 3; 750 rect.left += radioButtonOffset + labelWidth; 751 fTurnOffSlider = new TimeSlider(rect, "TurnOffSlider", 752 kMsgTurnOffSliderChanged, kMsgTurnOffSliderUpdate); 753 fTurnOffSlider->ResizeTo(fTurnOffSlider->Bounds().Width(), height); 754 box->AddChild(fTurnOffSlider); 755 756 rgb_color textColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 757 B_DISABLED_LABEL_TINT); 758 BRect textRect(0, 0, fTurnOffSlider->Bounds().Width(), height); 759 textRect.InsetBy(0, 3); 760 fTurnOffNotSupported = new BTextView(rect, "not_supported", 761 textRect, be_plain_font, &textColor, B_FOLLOW_ALL, B_WILL_DRAW); 762 fTurnOffNotSupported->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 763 fTurnOffNotSupported->MakeEditable(false); 764 fTurnOffNotSupported->MakeSelectable(false); 765 fTurnOffNotSupported->SetText( 766 B_TRANSLATE("Display Power Management Signaling not available")); 767 768 fTurnOffNotSupported->ResizeTo(fTurnOffSlider->Bounds().Width(), height); 769 box->AddChild(fTurnOffNotSupported); 770 771 // Password 772 rect.left = 10; 773 rect.OffsetBy(0, fTurnOffSlider->Bounds().Height() + 4.0f); 774 fPasswordCheckBox = new BCheckBox(rect, "PasswordCheckbox", 775 B_TRANSLATE("Password lock"), new BMessage(kMsgPasswordCheckBox)); 776 fPasswordCheckBox->ResizeToPreferred(); 777 box->AddChild(fPasswordCheckBox); 778 779 rect.top += 3; 780 rect.left += radioButtonOffset + labelWidth; 781 fPasswordSlider = new TimeSlider(rect, "PasswordSlider", 782 kMsgPasswordSliderChanged, kMsgPasswordSliderUpdate); 783 fPasswordSlider->ResizeTo(fPasswordSlider->Bounds().Width(), height); 784 box->AddChild(fPasswordSlider); 785 786 rect.OffsetBy(0, fTurnOffSlider->Bounds().Height() + 4.0f); 787 rect.left = rect.right; 788 fPasswordButton = new BButton(rect, "PasswordButton", 789 B_TRANSLATE("Password" B_UTF8_ELLIPSIS), 790 new BMessage(kMsgChangePassword), B_FOLLOW_TOP | B_FOLLOW_RIGHT); 791 fPasswordButton->ResizeToPreferred(); 792 fPasswordButton->MoveBy(-fPasswordButton->Bounds().Width(), 0); 793 box->AddChild(fPasswordButton); 794 795 // Bottom 796 797 float monitorHeight = 10 + textHeight * 3; 798 float monitorWidth = monitorHeight * 4 / 3; 799 rect.left = 11; 800 rect.top = box->Bounds().Height() - 15 - monitorHeight; 801 rect.right = rect.left + monitorWidth; 802 rect.bottom = rect.top + monitorHeight; 803 box->AddChild(fFadeNow = new ScreenCornerSelector(rect, "FadeNow", 804 new BMessage(kMsgFadeCornerChanged), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM)); 805 806 rect.OffsetBy(monitorWidth + 10, 0); 807 stringView = new BStringView(rect, NULL, B_TRANSLATE("Fade now when"), 808 B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); 809 stringView->ResizeToPreferred(); 810 float maxWidth = stringView->Bounds().Width(); 811 box->AddChild(stringView); 812 813 rect.OffsetBy(0, stringView->Bounds().Height()); 814 stringView = new BStringView(rect, NULL, B_TRANSLATE("mouse is here"), 815 B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); 816 stringView->ResizeToPreferred(); 817 if (maxWidth < stringView->Bounds().Width()) 818 maxWidth = stringView->Bounds().Width(); 819 box->AddChild(stringView); 820 821 rect.left += maxWidth + 20; 822 rect.top = box->Bounds().Height() - 15 - monitorHeight; 823 rect.right = rect.left + monitorWidth; 824 rect.bottom = rect.top + monitorHeight; 825 box->AddChild(fFadeNever = new ScreenCornerSelector(rect, "FadeNever", 826 new BMessage(kMsgNeverFadeCornerChanged), 827 B_FOLLOW_LEFT | B_FOLLOW_BOTTOM)); 828 829 rect.OffsetBy(monitorWidth + 10, 0); 830 stringView = new BStringView(rect, NULL,B_TRANSLATE("Don't fade when"), 831 B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); 832 stringView->ResizeToPreferred(); 833 if (maxWidth < stringView->Bounds().Width()) 834 maxWidth = stringView->Bounds().Width(); 835 box->AddChild(stringView); 836 837 rect.OffsetBy(0, stringView->Bounds().Height()); 838 stringView = new BStringView(rect, NULL, B_TRANSLATE("mouse is here"), 839 B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); 840 stringView->ResizeToPreferred(); 841 if (maxWidth < stringView->Bounds().Width()) 842 maxWidth = stringView->Bounds().Width(); 843 box->AddChild(stringView); 844 845 float size = rect.left + maxWidth + 40; 846 if (fMinWidth < size) 847 fMinWidth = size; 848 size = fPasswordButton->Frame().bottom + box->Frame().top 849 + monitorHeight + 40 + textHeight * 2; 850 if (fMinHeight < size) 851 fMinHeight = size; 852 } 853 854 855 void 856 ScreenSaverWindow::_UpdateTurnOffScreen() 857 { 858 bool enabled = (fSettings.TimeFlags() & ENABLE_DPMS_MASK) != 0; 859 860 BScreen screen(this); 861 uint32 dpmsCapabilities = screen.DPMSCapabilites(); 862 863 fTurnOffScreenFlags = 0; 864 if (dpmsCapabilities & B_DPMS_OFF) 865 fTurnOffScreenFlags |= ENABLE_DPMS_OFF; 866 if (dpmsCapabilities & B_DPMS_STAND_BY) 867 fTurnOffScreenFlags |= ENABLE_DPMS_STAND_BY; 868 if (dpmsCapabilities & B_DPMS_SUSPEND) 869 fTurnOffScreenFlags |= ENABLE_DPMS_SUSPEND; 870 871 fTurnOffCheckBox->SetValue(enabled && fTurnOffScreenFlags != 0 872 ? B_CONTROL_ON : B_CONTROL_OFF); 873 874 enabled = fEnableCheckBox->Value() == B_CONTROL_ON; 875 fTurnOffCheckBox->SetEnabled(enabled && fTurnOffScreenFlags != 0); 876 if (fTurnOffScreenFlags != 0) { 877 fTurnOffNotSupported->Hide(); 878 fTurnOffSlider->Show(); 879 } else { 880 fTurnOffSlider->Hide(); 881 fTurnOffNotSupported->Show(); 882 } 883 } 884 885 886 void 887 ScreenSaverWindow::_UpdateStatus() 888 { 889 DisableUpdates(); 890 891 bool enabled = fEnableCheckBox->Value() == B_CONTROL_ON; 892 fPasswordCheckBox->SetEnabled(enabled); 893 fTurnOffCheckBox->SetEnabled(enabled && fTurnOffScreenFlags != 0); 894 fRunSlider->SetEnabled(enabled); 895 fTurnOffSlider->SetEnabled(enabled && fTurnOffCheckBox->Value()); 896 fPasswordSlider->SetEnabled(enabled && fPasswordCheckBox->Value()); 897 fPasswordButton->SetEnabled(enabled && fPasswordCheckBox->Value()); 898 899 EnableUpdates(); 900 901 // Update the saved preferences 902 fSettings.SetWindowFrame(Frame()); 903 fSettings.SetWindowTab(fTabView->Selection()); 904 fSettings.SetTimeFlags((enabled ? ENABLE_SAVER : 0) 905 | (fTurnOffCheckBox->Value() ? fTurnOffScreenFlags : 0)); 906 fSettings.SetBlankTime(fRunSlider->Time()); 907 bigtime_t offTime = fTurnOffSlider->Time() - fSettings.BlankTime(); 908 fSettings.SetOffTime(offTime); 909 fSettings.SetSuspendTime(offTime); 910 fSettings.SetStandByTime(offTime); 911 fSettings.SetBlankCorner(fFadeNow->Corner()); 912 fSettings.SetNeverBlankCorner(fFadeNever->Corner()); 913 fSettings.SetLockEnable(fPasswordCheckBox->Value()); 914 fSettings.SetPasswordTime(fPasswordSlider->Time()); 915 916 // TODO - Tell the password window to update its stuff 917 } 918 919 920 void 921 ScreenSaverWindow::SetMinimalSizeLimit(float width, float height) 922 { 923 if (width < fMinWidth) 924 width = fMinWidth; 925 if (height < fMinHeight) 926 height = fMinHeight; 927 928 SetSizeLimits(width, 32767, height, 32767); 929 } 930 931 932 void 933 ScreenSaverWindow::MessageReceived(BMessage *msg) 934 { 935 // "Settings" tab, slider updates 936 937 switch (msg->what) { 938 case kMsgRunSliderChanged: 939 case kMsgRunSliderUpdate: 940 if (fRunSlider->Value() > fTurnOffSlider->Value()) 941 fTurnOffSlider->SetValue(fRunSlider->Value()); 942 943 if (fRunSlider->Value() > fPasswordSlider->Value()) 944 fPasswordSlider->SetValue(fRunSlider->Value()); 945 break; 946 947 case kMsgTurnOffSliderChanged: 948 case kMsgTurnOffSliderUpdate: 949 if (fRunSlider->Value() > fTurnOffSlider->Value()) 950 fRunSlider->SetValue(fTurnOffSlider->Value()); 951 break; 952 953 case kMsgPasswordSliderChanged: 954 case kMsgPasswordSliderUpdate: 955 if (fPasswordSlider->Value() < fRunSlider->Value()) 956 fRunSlider->SetValue(fPasswordSlider->Value()); 957 break; 958 } 959 960 switch (msg->what) { 961 // "General" tab 962 963 case kMsgTurnOffCheckBox: 964 fTurnOffSlider->SetEnabled( 965 fTurnOffCheckBox->Value() == B_CONTROL_ON); 966 break; 967 968 case kMsgRunSliderChanged: 969 case kMsgTurnOffSliderChanged: 970 case kMsgPasswordSliderChanged: 971 case kMsgPasswordCheckBox: 972 case kMsgEnableScreenSaverBox: 973 case kMsgFadeCornerChanged: 974 case kMsgNeverFadeCornerChanged: 975 _UpdateStatus(); 976 fSettings.Save(); 977 break; 978 979 case kMsgChangePassword: 980 fPasswordWindow->Show(); 981 break; 982 983 // "Screensavers" tab 984 985 case kMsgUpdateList: 986 fModulesView->PopulateScreenSaverList(); 987 break; 988 989 default: 990 BWindow::MessageReceived(msg); 991 break; 992 } 993 } 994 995 996 void 997 ScreenSaverWindow::ScreenChanged(BRect frame, color_space colorSpace) 998 { 999 _UpdateTurnOffScreen(); 1000 } 1001 1002 1003 bool 1004 ScreenSaverWindow::QuitRequested() 1005 { 1006 be_app->PostMessage(B_QUIT_REQUESTED); 1007 return true; 1008 } 1009 1010