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