1 /* 2 * Copyright 2001-2005, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Rafael Romo 7 * Stefano Ceccherini (burton666@libero.it) 8 * Andrew Bachmann 9 * Thomas Kurschel 10 * Axel Dörfler, axeld@pinc-software.de 11 */ 12 13 14 #include <Alert.h> 15 #include <Application.h> 16 #include <Box.h> 17 #include <Button.h> 18 #include <InterfaceDefs.h> 19 #include <MenuItem.h> 20 #include <MenuField.h> 21 #include <Messenger.h> 22 #include <PopUpMenu.h> 23 #include <Screen.h> 24 #include <String.h> 25 #include <Window.h> 26 27 #include <cstdio> 28 #include <cstdlib> 29 #include <cstring> 30 31 #include "AlertWindow.h" 32 #include "Constants.h" 33 #include "RefreshWindow.h" 34 #include "MonitorView.h" 35 #include "ScreenSettings.h" 36 #include "ScreenWindow.h" 37 #include "Utility.h" 38 39 /* Note, this headers defines a *private* interface to the Radeon accelerant. 40 * It's a solution that works with the current BeOS interface that Haiku 41 * adopted. 42 * However, it's not a nice and clean solution. Don't use this header in any 43 * application if you can avoid it. No other driver is using this, or should 44 * be using this. 45 * It will be replaced as soon as we introduce an updated accelerant interface 46 * which may even happen before R1 hits the streets. 47 */ 48 49 #include "multimon.h" // the usual: DANGER WILL, ROBINSON! 50 51 52 #define USE_FIXED_REFRESH 53 // define to use fixed standard refresh rates 54 // undefine to get standard refresh rates from driver 55 56 57 // list of officially supported colour spaces 58 static const struct { 59 color_space space; 60 int32 bits_per_pixel; 61 const char* label; 62 } kColorSpaces[] = { 63 { B_CMAP8, 8, "8 Bits/Pixel, 256 Colors" }, 64 { B_RGB15, 15, "15 Bits/Pixel, 32768 Colors" }, 65 { B_RGB16, 16, "16 Bits/Pixel, 65536 Colors" }, 66 { B_RGB32, 32, "32 Bits/Pixel, 16 Million Colors" } 67 }; 68 static const int32 kColorSpaceCount = sizeof(kColorSpaces) / sizeof(kColorSpaces[0]); 69 70 // list of standard refresh rates 71 static const int32 kRefreshRates[] = {56, 60, 70, 72, 75}; 72 static const int32 kRefreshRateCount = sizeof(kRefreshRates) / sizeof(kRefreshRates[0]); 73 74 75 // list of combine modes 76 static const struct { 77 combine_mode mode; 78 const char *name; 79 } kCombineModes[] = { 80 { kCombineDisable, "disable" }, 81 { kCombineHorizontally, "horizontally" }, 82 { kCombineVertically, "vertically" } 83 }; 84 static const int32 kCombineModeCount = sizeof(kCombineModes) / sizeof(kCombineModes[0]); 85 86 87 static BString 88 tv_standard_to_string(uint32 mode) 89 { 90 switch (mode) { 91 case 0: return "disabled"; 92 case 1: return "NTSC"; 93 case 2: return "NTSC Japan"; 94 case 3: return "PAL BDGHI"; 95 case 4: return "PAL M"; 96 case 5: return "PAL N"; 97 case 6: return "SECAM"; 98 case 101: return "NTSC 443"; 99 case 102: return "PAL 60"; 100 case 103: return "PAL NC"; 101 default: 102 { 103 BString name; 104 name << "??? (" << mode << ")"; 105 106 return name; 107 } 108 } 109 } 110 111 112 static void 113 resolution_to_string(screen_mode& mode, BString &string) 114 { 115 string << mode.width << " x " << mode.height; 116 } 117 118 119 static void 120 refresh_rate_to_string(float refresh, BString &string, 121 bool appendUnit = true, bool alwaysWithFraction = false) 122 { 123 snprintf(string.LockBuffer(32), 32, "%.*g", refresh >= 100.0 ? 4 : 3, refresh); 124 string.UnlockBuffer(); 125 126 if (appendUnit) 127 string << " Hz"; 128 } 129 130 131 // #pragma mark - 132 133 134 ScreenWindow::ScreenWindow(ScreenSettings *Settings) 135 : BWindow(Settings->WindowFrame(), "Screen", B_TITLED_WINDOW, 136 B_NOT_RESIZABLE | B_NOT_ZOOMABLE, B_ALL_WORKSPACES), 137 fScreenMode(this), 138 fChangingAllWorkspaces(false) 139 { 140 BScreen screen(this); 141 BRect frame(Bounds()); 142 143 fScreenMode.Get(fOriginal); 144 fActive = fSelected = fOriginal; 145 146 BView *view = new BView(frame, "ScreenView", B_FOLLOW_ALL, B_WILL_DRAW); 147 view->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 148 AddChild(view); 149 150 fSettings = Settings; 151 152 // box on the left with workspace count and monitor view 153 154 BRect screenBoxRect(11.0, 18.0, 153.0, 155.0); 155 BBox *screenBox = new BBox(screenBoxRect, "left box"); 156 157 fMonitorView = new MonitorView(BRect(20.0, 16.0, 122.0, 93.0), "monitor", 158 screen.Frame().Width() + 1, screen.Frame().Height() + 1); 159 screenBox->AddChild(fMonitorView); 160 161 BPopUpMenu *popUpMenu = new BPopUpMenu("", true, true); 162 BMenuField *menuField = new BMenuField(BRect(7.0, 107.0, 135.0, 127.0), 163 "WorkspaceCountMenu", "Workspace count:", popUpMenu, true); 164 screenBox->AddChild(menuField); 165 166 for (int32 count = 1; count <= 32; count++) { 167 BString workspaceCount; 168 workspaceCount << count; 169 170 BMessage *message = new BMessage(POP_WORKSPACE_CHANGED_MSG); 171 message->AddInt32("workspace count", count); 172 173 popUpMenu->AddItem(new BMenuItem(workspaceCount.String(), 174 message)); 175 } 176 177 BMenuItem *item = popUpMenu->ItemAt(count_workspaces() - 1); 178 if (item != NULL) 179 item->SetMarked(true); 180 181 menuField->SetDivider(91.0); 182 view->AddChild(screenBox); 183 184 // box on the right with screen resolution, etc. 185 186 popUpMenu = new BPopUpMenu("Current Workspace", true, true); 187 fAllWorkspacesItem = new BMenuItem("All Workspaces", new BMessage(WORKSPACE_CHECK_MSG)); 188 popUpMenu->AddItem(fAllWorkspacesItem); 189 item = new BMenuItem("Current Workspace", new BMessage(WORKSPACE_CHECK_MSG)); 190 item->SetMarked(true); 191 popUpMenu->AddItem(item); 192 193 BRect rect(0.0, 0.0, 132.0, 18.0); 194 menuField = new BMenuField(rect, "WorkspaceMenu", NULL, popUpMenu, true); 195 196 rect.Set(164.0, 7.0, 345.0, 155.0); 197 BBox* controlsBox = new BBox(rect); 198 controlsBox->SetLabel(menuField); 199 200 rect.Set(88.0, 114.0, 200.0, 150.0); 201 fApplyButton = new BButton(rect, "ApplyButton", "Apply", 202 new BMessage(BUTTON_APPLY_MSG)); 203 fApplyButton->ResizeToPreferred(); 204 fApplyButton->SetEnabled(false); 205 206 controlsBox->AddChild(fApplyButton); 207 208 fResolutionMenu = new BPopUpMenu("resolution", true, true); 209 210 uint16 previousWidth = 0, previousHeight = 0; 211 for (int32 i = 0; i < fScreenMode.CountModes(); i++) { 212 screen_mode mode = fScreenMode.ModeAt(i); 213 214 if (mode.width == previousWidth && mode.height == previousHeight) 215 continue; 216 217 previousWidth = mode.width; 218 previousHeight = mode.height; 219 220 BMessage *message = new BMessage(POP_RESOLUTION_MSG); 221 message->AddInt32("width", mode.width); 222 message->AddInt32("height", mode.height); 223 224 BString name; 225 name << mode.width << " x " << mode.height; 226 227 fResolutionMenu->AddItem(new BMenuItem(name.String(), message)); 228 } 229 230 rect.Set(33.0, 30.0, 171.0, 48.0); 231 fResolutionField = new BMenuField(rect, "ResolutionMenu", "Resolution:", 232 fResolutionMenu, true); 233 fResolutionField->SetDivider(55.0); 234 controlsBox->AddChild(fResolutionField); 235 236 fColorsMenu = new BPopUpMenu("colors", true, true); 237 238 for (int32 i = 0; i < kColorSpaceCount; i++) { 239 BMessage *message = new BMessage(POP_COLORS_MSG); 240 message->AddInt32("bits_per_pixel", kColorSpaces[i].bits_per_pixel); 241 message->AddInt32("space", kColorSpaces[i].space); 242 243 fColorsMenu->AddItem(new BMenuItem(kColorSpaces[i].label, message)); 244 } 245 246 rect.Set(50.0, 58.0, 171.0, 76.0); 247 fColorsField = new BMenuField(rect, "ColorsMenu", "Colors:", fColorsMenu, true); 248 fColorsField->SetDivider(38.0); 249 controlsBox->AddChild(fColorsField); 250 251 fRefreshMenu = new BPopUpMenu("refresh rate", true, true); 252 253 #ifdef USE_FIXED_REFRESH 254 for (int32 i = 0; i < kRefreshRateCount; ++i) { 255 BString name; 256 name << kRefreshRates[i] << " Hz"; 257 258 BMessage *message = new BMessage(POP_REFRESH_MSG); 259 message->AddFloat("refresh", kRefreshRates[i]); 260 261 fRefreshMenu->AddItem(new BMenuItem(name.String(), message)); 262 } 263 #endif 264 265 BMessage *message = new BMessage(POP_OTHER_REFRESH_MSG); 266 267 fOtherRefresh = new BMenuItem("Other" B_UTF8_ELLIPSIS, message); 268 fRefreshMenu->AddItem(fOtherRefresh); 269 270 rect.Set(19.0, 86.0, 171.0, 104.0); 271 fRefreshField = new BMenuField(rect, "RefreshMenu", "Refresh Rate:", fRefreshMenu, true); 272 fRefreshField->SetDivider(69.0); 273 controlsBox->AddChild(fRefreshField); 274 275 view->AddChild(controlsBox); 276 277 // enlarged area for multi-monitor settings 278 { 279 bool dummy; 280 uint32 dummy32; 281 bool multiMonSupport; 282 bool useLaptopPanelSupport; 283 bool tvStandardSupport; 284 285 multiMonSupport = TestMultiMonSupport(&screen) == B_OK; 286 useLaptopPanelSupport = GetUseLaptopPanel(&screen, &dummy) == B_OK; 287 tvStandardSupport = GetTVStandard(&screen, &dummy32) == B_OK; 288 289 // even if there is no support, we still create all controls 290 // to make sure we don't access NULL pointers later on 291 if (multiMonSupport) { 292 fApplyButton->MoveTo(275, 114); 293 controlsBox->ResizeTo(366, 148); 294 ResizeTo(556, 202); 295 } 296 297 fCombineMenu = new BPopUpMenu("CombineDisplays", true, true); 298 299 for (int32 i = 0; i < kCombineModeCount; i++) { 300 message = new BMessage(POP_COMBINE_DISPLAYS_MSG); 301 message->AddInt32("mode", kCombineModes[i].mode); 302 303 fCombineMenu->AddItem(new BMenuItem(kCombineModes[i].name, message)); 304 } 305 306 rect.Set(185, 30, 356, 48); 307 BMenuField* menuField = new BMenuField(rect, "CombineMenu", 308 "Combine Displays:", fCombineMenu, true); 309 menuField->SetDivider(90); 310 controlsBox->AddChild(menuField); 311 312 if (!multiMonSupport) 313 menuField->Hide(); 314 315 fSwapDisplaysMenu = new BPopUpMenu("SwapDisplays", true, true); 316 317 // !order is important - we rely that boolean value == idx 318 message = new BMessage(POP_SWAP_DISPLAYS_MSG); 319 message->AddBool("swap", false); 320 fSwapDisplaysMenu->AddItem(new BMenuItem("no", message)); 321 322 message = new BMessage(POP_SWAP_DISPLAYS_MSG); 323 message->AddBool("swap", true); 324 fSwapDisplaysMenu->AddItem(new BMenuItem("yes", message)); 325 326 rect.Set(199, 58, 356, 76); 327 menuField = new BMenuField(rect, "SwapMenu", "Swap Displays:", 328 fSwapDisplaysMenu, true); 329 menuField->SetDivider(76); 330 331 controlsBox->AddChild(menuField); 332 if (!multiMonSupport) 333 menuField->Hide(); 334 335 fUseLaptopPanelMenu = new BPopUpMenu("UseLaptopPanel", true, true); 336 337 // !order is important - we rely that boolean value == idx 338 message = new BMessage(POP_USE_LAPTOP_PANEL_MSG); 339 message->AddBool("use", false); 340 fUseLaptopPanelMenu->AddItem(new BMenuItem("if needed", message)); 341 342 message = new BMessage(POP_USE_LAPTOP_PANEL_MSG); 343 message->AddBool("use", true); 344 fUseLaptopPanelMenu->AddItem(new BMenuItem("always", message)); 345 346 rect.Set(184, 86, 356, 104); 347 menuField = new BMenuField(rect, "UseLaptopPanel", "Use Laptop Panel:", 348 fUseLaptopPanelMenu, true); 349 menuField->SetDivider(91); 350 351 controlsBox->AddChild(menuField); 352 if (!useLaptopPanelSupport) 353 menuField->Hide(); 354 355 fTVStandardMenu = new BPopUpMenu("TVStandard", true, true); 356 357 // arbitrary limit 358 uint32 i; 359 for (i = 0; i < 100; ++i) { 360 uint32 mode; 361 362 if (GetNthSupportedTVStandard(&screen, i, &mode) != B_OK) 363 break; 364 365 BString name = tv_standard_to_string(mode); 366 367 message = new BMessage(POP_TV_STANDARD_MSG); 368 message->AddInt32("tv_standard", mode); 369 370 fTVStandardMenu->AddItem(new BMenuItem(name.String(), message)); 371 } 372 373 rect.Set(15, 114, 171, 132); 374 menuField = new BMenuField(rect, "tv standard", "Video Format:", 375 fTVStandardMenu, true); 376 menuField->SetDivider(73); 377 378 if (!tvStandardSupport || i == 0) 379 menuField->Hide(); 380 381 controlsBox->AddChild(menuField); 382 } 383 384 rect.Set(10.0, 167, 100.0, 200.0); 385 fDefaultsButton = new BButton(rect, "DefaultsButton", "Defaults", 386 new BMessage(BUTTON_DEFAULTS_MSG)); 387 fDefaultsButton->ResizeToPreferred(); 388 view->AddChild(fDefaultsButton); 389 390 rect.Set(95.0, 167, 160.0, 200.0); 391 fRevertButton = new BButton(rect, "RevertButton", "Revert", 392 new BMessage(BUTTON_REVERT_MSG)); 393 fRevertButton->ResizeToPreferred(); 394 fRevertButton->SetEnabled(false); 395 view->AddChild(fRevertButton); 396 397 UpdateControls(); 398 } 399 400 401 ScreenWindow::~ScreenWindow() 402 { 403 delete fSettings; 404 } 405 406 407 bool 408 ScreenWindow::QuitRequested() 409 { 410 fSettings->SetWindowFrame(Frame()); 411 be_app->PostMessage(B_QUIT_REQUESTED); 412 413 return BWindow::QuitRequested(); 414 } 415 416 417 /** update resolution list according to combine mode 418 * (some resolution may not be combinable due to memory restrictions) 419 */ 420 421 void 422 ScreenWindow::CheckResolutionMenu() 423 { 424 for (int32 i = 0; i < fResolutionMenu->CountItems(); i++) 425 fResolutionMenu->ItemAt(i)->SetEnabled(false); 426 427 for (int32 i = 0; i < fScreenMode.CountModes(); i++) { 428 screen_mode mode = fScreenMode.ModeAt(i); 429 if (mode.combine != fSelected.combine) 430 continue; 431 432 BString name; 433 name << mode.width << " x " << mode.height; 434 435 BMenuItem *item = fResolutionMenu->FindItem(name.String()); 436 if (item != NULL) 437 item->SetEnabled(true); 438 } 439 } 440 441 442 /** update color and refresh options according to current mode 443 * (a color space is made active if there is any mode with 444 * given resolution and this colour space; same applies for 445 * refresh rate, though "Other…" is always possible) 446 */ 447 448 void 449 ScreenWindow::CheckColorMenu() 450 { 451 for (int32 i = 0; i < kColorSpaceCount; i++) { 452 bool supported = false; 453 454 for (int32 j = 0; j < fScreenMode.CountModes(); j++) { 455 screen_mode mode = fScreenMode.ModeAt(j); 456 457 if (fSelected.width == mode.width 458 && fSelected.height == mode.height 459 && kColorSpaces[i].space == mode.space 460 && fSelected.combine == mode.combine) { 461 supported = true; 462 break; 463 } 464 } 465 466 BMenuItem* item = fColorsMenu->ItemAt(i); 467 if (item) 468 item->SetEnabled(supported); 469 } 470 } 471 472 473 /** Enable/disable refresh options according to current mode. 474 * Only needed when USE_FIXED_REFRESH is not defined. 475 */ 476 477 void 478 ScreenWindow::CheckRefreshMenu() 479 { 480 #ifndef USE_FIXED_REFRESH 481 // ToDo: does currently not compile! 482 for (int32 i = fRefreshMenu->CountItems() - 2; i >= 0; --i) { 483 delete fRefreshMenu->RemoveItem(i); 484 } 485 486 for (int32 i = 0; i < fModeListCount; ++i) { 487 if (virtualWidth == fModeList[i].virtual_width 488 && virtualHeight == fModeList[i].virtual_height 489 && combine == get_combine_mode(&fModeList[i])) { 490 BString name; 491 BMenuItem *item; 492 493 int32 refresh10 = get_refresh10(fModeList[i]); 494 refresh10_to_string(name, refresh10); 495 496 item = fRefreshMenu->FindItem(name.String()); 497 if (item == NULL) { 498 BMessage *msg = new BMessage(POP_REFRESH_MSG); 499 msg->AddFloat("refresh", refresh); 500 501 fRefreshMenu->AddItem(new BMenuItem(name.String(), msg), 502 fRefreshMenu->CountItems() - 1); 503 } 504 } 505 } 506 #endif 507 508 // TBD: some drivers lack many refresh rates; still, they 509 // can be used by generating the mode manually 510 /* 511 for( i = 0; i < sizeof( refresh_list ) / sizeof( refresh_list[0] ); ++i ) { 512 BMenuItem *item; 513 bool supported = false; 514 515 for( j = 0; j < fModeListCount; ++j ) { 516 if( width == fModeList[j].virtual_width && 517 height == fModeList[j].virtual_height && 518 refresh_list[i].refresh * 10 == getModeRefresh10( &fModeList[j] )) 519 { 520 supported = true; 521 break; 522 } 523 } 524 525 item = fRefreshMenu->ItemAt( i ); 526 if( item ) 527 item->SetEnabled( supported ); 528 } 529 */ 530 } 531 532 533 /** activate appropriate menu item according to selected refresh rate */ 534 535 void 536 ScreenWindow::UpdateRefreshControl() 537 { 538 BString string; 539 refresh_rate_to_string(fSelected.refresh, string); 540 541 BMenuItem* item = fRefreshMenu->FindItem(string.String()); 542 if (item) { 543 if (!item->IsMarked()) 544 item->SetMarked(true); 545 // "Other…" items only contains a refresh rate when active 546 fOtherRefresh->SetLabel("Other…"); 547 return; 548 } 549 550 // this is a non-standard refresh rate 551 552 fOtherRefresh->Message()->ReplaceFloat("refresh", fSelected.refresh); 553 fOtherRefresh->SetMarked(true); 554 555 fRefreshMenu->Superitem()->SetLabel(string.String()); 556 557 string.Append("/Other" B_UTF8_ELLIPSIS); 558 fOtherRefresh->SetLabel(string.String()); 559 } 560 561 562 void 563 ScreenWindow::UpdateMonitorView() 564 { 565 BMessage updateMessage(UPDATE_DESKTOP_MSG); 566 updateMessage.AddInt32("width", fSelected.width); 567 updateMessage.AddInt32("height", fSelected.height); 568 569 PostMessage(&updateMessage, fMonitorView); 570 } 571 572 573 void 574 ScreenWindow::UpdateControls() 575 { 576 BMenuItem* item = fSwapDisplaysMenu->ItemAt((int32)fSelected.swap_displays); 577 if (item && !item->IsMarked()) 578 item->SetMarked(true); 579 580 item = fUseLaptopPanelMenu->ItemAt((int32)fSelected.use_laptop_panel); 581 if (item && !item->IsMarked()) 582 item->SetMarked(true); 583 584 for (int32 i = 0; i < fTVStandardMenu->CountItems(); i++) { 585 item = fTVStandardMenu->ItemAt(i); 586 587 uint32 tvStandard; 588 item->Message()->FindInt32("tv_standard", (int32 *)&tvStandard); 589 if (tvStandard == fSelected.tv_standard) { 590 if (!item->IsMarked()) 591 item->SetMarked(true); 592 break; 593 } 594 } 595 596 CheckResolutionMenu(); 597 CheckColorMenu(); 598 CheckRefreshMenu(); 599 600 BString string; 601 resolution_to_string(fSelected, string); 602 item = fResolutionMenu->FindItem(string.String()); 603 604 if (item != NULL) { 605 if (!item->IsMarked()) 606 item->SetMarked(true); 607 } else { 608 // this is bad luck - if mode has been set via screen references, 609 // this case cannot occur; there are three possible solutions: 610 // 1. add a new resolution to list 611 // - we had to remove it as soon as a "valid" one is selected 612 // - we don't know which frequencies/bit depths are supported 613 // - as long as we haven't the GMT formula to create 614 // parameters for any resolution given, we cannot 615 // really set current mode - it's just not in the list 616 // 2. choose nearest resolution 617 // - probably a good idea, but implies coding and testing 618 // 3. choose lowest resolution 619 // - do you really think we are so lazy? yes, we are 620 item = fResolutionMenu->ItemAt(0); 621 if (item) 622 item->SetMarked(true); 623 624 // okay - at least we set menu label to active resolution 625 fResolutionMenu->Superitem()->SetLabel(string.String()); 626 } 627 628 // mark active combine mode 629 for (int32 i = 0; i < kCombineModeCount; i++) { 630 if (kCombineModes[i].mode == fSelected.combine) { 631 item = fCombineMenu->ItemAt(i); 632 if (item && !item->IsMarked()) 633 item->SetMarked(true); 634 break; 635 } 636 } 637 638 item = fColorsMenu->ItemAt(0); 639 640 for (int32 i = kColorSpaceCount; i-- > 0;) { 641 if (kColorSpaces[i].space == fSelected.space) { 642 item = fColorsMenu->ItemAt(i); 643 break; 644 } 645 } 646 647 if (item && !item->IsMarked()) 648 item->SetMarked(true); 649 650 string.Truncate(0); 651 string << fSelected.BitsPerPixel() << " Bits/Pixel"; 652 if (string != fColorsMenu->Superitem()->Label()) 653 fColorsMenu->Superitem()->SetLabel(string.String()); 654 655 UpdateMonitorView(); 656 UpdateRefreshControl(); 657 658 CheckApplyEnabled(); 659 } 660 661 662 /** reflect active mode in chosen settings */ 663 664 void 665 ScreenWindow::UpdateActiveMode() 666 { 667 // usually, this function gets called after a mode 668 // has been set manually; still, as the graphics driver 669 // is free to fiddle with mode passed, we better ask 670 // what kind of mode we actually got 671 fScreenMode.Get(fActive); 672 fSelected = fActive; 673 674 UpdateControls(); 675 } 676 677 678 void 679 ScreenWindow::ScreenChanged(BRect frame, color_space mode) 680 { 681 // move window on screen, if necessary 682 if (frame.right <= Frame().right 683 && frame.bottom <= Frame().bottom) { 684 MoveTo((frame.Width() - Frame().Width()) / 2, 685 (frame.Height() - Frame().Height()) / 2); 686 } 687 } 688 689 690 void 691 ScreenWindow::WorkspaceActivated(int32 workspace, bool state) 692 { 693 if (fChangingAllWorkspaces) { 694 // we're currently changing all workspaces, so there is no need 695 // to update the interface 696 return; 697 } 698 699 fScreenMode.Get(fOriginal); 700 fScreenMode.UpdateOriginalMode(); 701 702 // only override current settings if they have not been changed yet 703 if (fSelected == fActive) 704 UpdateActiveMode(); 705 706 PostMessage(new BMessage(UPDATE_DESKTOP_COLOR_MSG), fMonitorView); 707 } 708 709 710 void 711 ScreenWindow::MessageReceived(BMessage* message) 712 { 713 switch (message->what) { 714 case WORKSPACE_CHECK_MSG: 715 CheckApplyEnabled(); 716 break; 717 718 case POP_WORKSPACE_CHANGED_MSG: 719 { 720 int32 index; 721 if (message->FindInt32("index", &index) == B_OK) 722 set_workspace_count(index + 1); 723 break; 724 } 725 726 case POP_RESOLUTION_MSG: 727 { 728 message->FindInt32("width", &fSelected.width); 729 message->FindInt32("height", &fSelected.height); 730 731 CheckColorMenu(); 732 CheckRefreshMenu(); 733 734 UpdateMonitorView(); 735 UpdateRefreshControl(); 736 737 CheckApplyEnabled(); 738 break; 739 } 740 741 case POP_COLORS_MSG: 742 { 743 message->FindInt32("space", (int32 *)&fSelected.space); 744 745 BString string; 746 string << fSelected.BitsPerPixel() << " Bits/Pixel"; 747 fColorsMenu->Superitem()->SetLabel(string.String()); 748 749 CheckApplyEnabled(); 750 break; 751 } 752 753 case POP_REFRESH_MSG: 754 message->FindFloat("refresh", &fSelected.refresh); 755 fOtherRefresh->SetLabel("Other" B_UTF8_ELLIPSIS); 756 // revert "Other…" label - it might have had a refresh rate prefix 757 758 CheckApplyEnabled(); 759 break; 760 761 case POP_OTHER_REFRESH_MSG: 762 { 763 // make sure menu shows something usefull 764 UpdateRefreshControl(); 765 766 BRect frame(Frame()); 767 RefreshWindow *fRefreshWindow = new RefreshWindow(BRect(frame.left + 201.0, 768 frame.top + 34.0, frame.left + 509.0, frame.top + 169.0), 769 int32(fSelected.refresh * 10)); 770 fRefreshWindow->Show(); 771 break; 772 } 773 774 case SET_CUSTOM_REFRESH_MSG: 775 { 776 // user pressed "done" in "Other…" refresh dialog; 777 // select the refresh rate chosen 778 message->FindFloat("refresh", &fSelected.refresh); 779 780 UpdateRefreshControl(); 781 CheckApplyEnabled(); 782 break; 783 } 784 785 case POP_COMBINE_DISPLAYS_MSG: 786 { 787 // new combine mode has bee chosen 788 int32 mode; 789 if (message->FindInt32("mode", &mode) == B_OK) 790 fSelected.combine = (combine_mode)mode; 791 792 CheckResolutionMenu(); 793 CheckApplyEnabled(); 794 break; 795 } 796 797 case POP_SWAP_DISPLAYS_MSG: 798 message->FindBool("swap", &fSelected.swap_displays); 799 CheckApplyEnabled(); 800 break; 801 802 case POP_USE_LAPTOP_PANEL_MSG: 803 message->FindBool("use", &fSelected.use_laptop_panel); 804 CheckApplyEnabled(); 805 break; 806 807 case POP_TV_STANDARD_MSG: 808 message->FindInt32("tv_standard", (int32 *)&fSelected.tv_standard); 809 CheckApplyEnabled(); 810 break; 811 812 case BUTTON_DEFAULTS_MSG: 813 { 814 fSelected.width = 640; 815 fSelected.height = 480; 816 fSelected.space = B_CMAP8; 817 fSelected.refresh = 60.0; 818 fSelected.combine = kCombineDisable; 819 fSelected.swap_displays = false; 820 fSelected.use_laptop_panel = false; 821 fSelected.tv_standard = 0; 822 823 UpdateControls(); 824 break; 825 } 826 827 case BUTTON_REVERT_MSG: 828 case SET_INITIAL_MODE_MSG: 829 fScreenMode.Revert(); 830 UpdateActiveMode(); 831 break; 832 833 case BUTTON_APPLY_MSG: 834 Apply(); 835 break; 836 837 case MAKE_INITIAL_MSG: { 838 // user pressed "keep" in confirmation box; 839 // select this mode in dialog and mark it as 840 // previous mode; if "all workspaces" is selected, 841 // distribute mode to all workspaces 842 843 // use the mode that has eventually been set and 844 // thus we know to be working; it can differ from 845 // the mode selected by user due to hardware limitation 846 display_mode newMode; 847 BScreen screen(this); 848 screen.GetMode(&newMode); 849 850 if (fAllWorkspacesItem->IsMarked()) { 851 int32 originatingWorkspace; 852 853 // the original panel activates each workspace in turn; 854 // this is disguisting and there is a SetMode 855 // variant that accepts a workspace id, so let's take 856 // this one 857 originatingWorkspace = current_workspace(); 858 859 // well, this "cannot be reverted" message is not 860 // entirely true - at least, you can revert it 861 // for current workspace; to not overwrite original 862 // mode during workspace switch, we use this flag 863 fChangingAllWorkspaces = true; 864 865 for (int32 i = 0; i < count_workspaces(); i++) { 866 if (i != originatingWorkspace) 867 screen.SetMode(i, &newMode, true); 868 } 869 870 fChangingAllWorkspaces = false; 871 } 872 873 UpdateActiveMode(); 874 break; 875 } 876 877 default: 878 BWindow::MessageReceived(message); 879 break; 880 } 881 } 882 883 884 bool 885 ScreenWindow::CanApply() const 886 { 887 if (fAllWorkspacesItem->IsMarked()) 888 return true; 889 890 return fSelected != fActive; 891 } 892 893 894 bool 895 ScreenWindow::CanRevert() const 896 { 897 if (fActive != fOriginal) 898 return true; 899 900 return CanApply(); 901 } 902 903 904 void 905 ScreenWindow::CheckApplyEnabled() 906 { 907 fApplyButton->SetEnabled(CanApply()); 908 fRevertButton->SetEnabled(CanRevert()); 909 } 910 911 912 void 913 ScreenWindow::Apply() 914 { 915 if (fAllWorkspacesItem->IsMarked()) { 916 BAlert *workspacesAlert = new BAlert("WorkspacesAlert", 917 "Change all workspaces? This action cannot be reverted.", "Okay", "Cancel", 918 NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 919 920 if (workspacesAlert->Go() == 1) 921 return; 922 } 923 924 if (fScreenMode.Set(fSelected) == B_OK) 925 fActive = fSelected; 926 927 // ToDo: only show alert when this is an unknown mode 928 BWindow *window = new AlertWindow(this); 929 window->Show(); 930 } 931