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