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