1 /* 2 * Copyright 2001-2015 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus, superstippi@gmx.de 7 * Andrew Bachmann 8 * Stefano Ceccherini, burton666@libero.it 9 * Alexandre Deckner, alex@zappotek.com 10 * Axel Dörfler, axeld@pinc-software.de 11 * Rene Gollent, rene@gollent.com 12 * Thomas Kurschel 13 * Rafael Romo 14 * John Scipione, jscipione@gmail.com 15 */ 16 17 18 #include "ScreenWindow.h" 19 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <strings.h> 23 24 #include <Alert.h> 25 #include <Application.h> 26 #include <Box.h> 27 #include <Button.h> 28 #include <Catalog.h> 29 #include <ControlLook.h> 30 #include <Directory.h> 31 #include <File.h> 32 #include <FindDirectory.h> 33 #include <InterfaceDefs.h> 34 #include <LayoutBuilder.h> 35 #include <MenuBar.h> 36 #include <MenuItem.h> 37 #include <MenuField.h> 38 #include <Messenger.h> 39 #include <Path.h> 40 #include <PopUpMenu.h> 41 #include <Screen.h> 42 #include <SpaceLayoutItem.h> 43 #include <Spinner.h> 44 #include <String.h> 45 #include <StringView.h> 46 #include <Roster.h> 47 #include <Window.h> 48 49 #include <InterfacePrivate.h> 50 51 #include "AlertWindow.h" 52 #include "Constants.h" 53 #include "RefreshWindow.h" 54 #include "MonitorView.h" 55 #include "ScreenSettings.h" 56 #include "Utility.h" 57 58 /* Note, this headers defines a *private* interface to the Radeon accelerant. 59 * It's a solution that works with the current BeOS interface that Haiku 60 * adopted. 61 * However, it's not a nice and clean solution. Don't use this header in any 62 * application if you can avoid it. No other driver is using this, or should 63 * be using this. 64 * It will be replaced as soon as we introduce an updated accelerant interface 65 * which may even happen before R1 hits the streets. 66 */ 67 #include "multimon.h" // the usual: DANGER WILL, ROBINSON! 68 69 70 #undef B_TRANSLATION_CONTEXT 71 #define B_TRANSLATION_CONTEXT "Screen" 72 73 74 const char* kBackgroundsSignature = "application/x-vnd.Haiku-Backgrounds"; 75 76 // list of officially supported colour spaces 77 static const struct { 78 color_space space; 79 int32 bits_per_pixel; 80 const char* label; 81 } kColorSpaces[] = { 82 { B_CMAP8, 8, B_TRANSLATE("8 bits/pixel, 256 colors") }, 83 { B_RGB15, 15, B_TRANSLATE("15 bits/pixel, 32768 colors") }, 84 { B_RGB16, 16, B_TRANSLATE("16 bits/pixel, 65536 colors") }, 85 { B_RGB24, 24, B_TRANSLATE("24 bits/pixel, 16 Million colors") }, 86 { B_RGB32, 32, B_TRANSLATE("32 bits/pixel, 16 Million colors") } 87 }; 88 static const int32 kColorSpaceCount 89 = sizeof(kColorSpaces) / sizeof(kColorSpaces[0]); 90 91 // list of standard refresh rates 92 static const int32 kRefreshRates[] = { 60, 70, 72, 75, 80, 85, 95, 100 }; 93 static const int32 kRefreshRateCount 94 = sizeof(kRefreshRates) / sizeof(kRefreshRates[0]); 95 96 // list of combine modes 97 static const struct { 98 combine_mode mode; 99 const char *name; 100 } kCombineModes[] = { 101 { kCombineDisable, B_TRANSLATE("disable") }, 102 { kCombineHorizontally, B_TRANSLATE("horizontally") }, 103 { kCombineVertically, B_TRANSLATE("vertically") } 104 }; 105 static const int32 kCombineModeCount 106 = sizeof(kCombineModes) / sizeof(kCombineModes[0]); 107 108 109 static BString 110 tv_standard_to_string(uint32 mode) 111 { 112 switch (mode) { 113 case 0: return "disabled"; 114 case 1: return "NTSC"; 115 case 2: return "NTSC Japan"; 116 case 3: return "PAL BDGHI"; 117 case 4: return "PAL M"; 118 case 5: return "PAL N"; 119 case 6: return "SECAM"; 120 case 101: return "NTSC 443"; 121 case 102: return "PAL 60"; 122 case 103: return "PAL NC"; 123 default: 124 { 125 BString name; 126 name << "??? (" << mode << ")"; 127 128 return name; 129 } 130 } 131 } 132 133 134 static void 135 resolution_to_string(screen_mode& mode, BString &string) 136 { 137 string << mode.width << " x " << mode.height; 138 } 139 140 141 static void 142 refresh_rate_to_string(float refresh, BString &string, 143 bool appendUnit = true, bool alwaysWithFraction = false) 144 { 145 snprintf(string.LockBuffer(32), 32, "%.*g", refresh >= 100.0 ? 4 : 3, 146 refresh); 147 string.UnlockBuffer(); 148 149 if (appendUnit) 150 string << " " << B_TRANSLATE("Hz"); 151 } 152 153 154 static const char* 155 screen_errors(status_t status) 156 { 157 switch (status) { 158 case B_ENTRY_NOT_FOUND: 159 return B_TRANSLATE("Unknown mode"); 160 // TODO: add more? 161 162 default: 163 return strerror(status); 164 } 165 } 166 167 168 // #pragma mark - ScreenWindow 169 170 171 ScreenWindow::ScreenWindow(ScreenSettings* settings) 172 : 173 BWindow(settings->WindowFrame(), B_TRANSLATE_SYSTEM_NAME("Screen"), 174 B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE 175 | B_AUTO_UPDATE_SIZE_LIMITS, B_ALL_WORKSPACES), 176 fIsVesa(false), 177 fBootWorkspaceApplied(false), 178 fOtherRefresh(NULL), 179 fScreenMode(this), 180 fUndoScreenMode(this), 181 fModified(false) 182 { 183 BScreen screen(this); 184 185 accelerant_device_info info; 186 if (screen.GetDeviceInfo(&info) == B_OK 187 && !strcasecmp(info.chipset, "VESA")) 188 fIsVesa = true; 189 190 _UpdateOriginal(); 191 _BuildSupportedColorSpaces(); 192 fActive = fSelected = fOriginal; 193 194 fSettings = settings; 195 196 // we need the "Current Workspace" first to get its height 197 198 BPopUpMenu* popUpMenu = new BPopUpMenu(B_TRANSLATE("Current workspace"), 199 true, true); 200 fAllWorkspacesItem = new BMenuItem(B_TRANSLATE("All workspaces"), 201 new BMessage(WORKSPACE_CHECK_MSG)); 202 popUpMenu->AddItem(fAllWorkspacesItem); 203 BMenuItem *item = new BMenuItem(B_TRANSLATE("Current workspace"), 204 new BMessage(WORKSPACE_CHECK_MSG)); 205 206 popUpMenu->AddItem(item); 207 fAllWorkspacesItem->SetMarked(true); 208 209 BMenuField* workspaceMenuField = new BMenuField("WorkspaceMenu", NULL, 210 popUpMenu); 211 workspaceMenuField->ResizeToPreferred(); 212 213 // box on the left with workspace count and monitor view 214 215 BBox* screenBox = new BBox("screen box"); 216 BGroupLayout* layout = new BGroupLayout(B_VERTICAL, B_USE_SMALL_SPACING); 217 layout->SetInsets(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, 218 B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING); 219 screenBox->SetLayout(layout); 220 221 fMonitorInfo = new BStringView("monitor info", ""); 222 fMonitorInfo->SetAlignment(B_ALIGN_CENTER); 223 screenBox->AddChild(fMonitorInfo); 224 225 fDeviceInfo = new BStringView("monitor info", ""); 226 fDeviceInfo->SetAlignment(B_ALIGN_CENTER); 227 screenBox->AddChild(fDeviceInfo); 228 229 float scaling = std::max(1.0f, be_plain_font->Size() / 12.0f); 230 fMonitorView = new MonitorView(BRect(0.0, 0.0, 80.0 * scaling, 231 80.0 * scaling), "monitor", screen.Frame().IntegerWidth() + 1, 232 screen.Frame().IntegerHeight() + 1); 233 screenBox->AddChild(fMonitorView); 234 235 BStringView* workspaces = new BStringView("workspaces", 236 B_TRANSLATE("Workspaces")); 237 workspaces->SetAlignment(B_ALIGN_CENTER); 238 239 fColumnsControl = new BSpinner("columns", B_TRANSLATE("Columns:"), 240 new BMessage(kMsgWorkspaceColumnsChanged)); 241 fColumnsControl->SetAlignment(B_ALIGN_RIGHT); 242 fColumnsControl->SetRange(1, 32); 243 244 fRowsControl = new BSpinner("rows", B_TRANSLATE("Rows:"), 245 new BMessage(kMsgWorkspaceRowsChanged)); 246 fRowsControl->SetAlignment(B_ALIGN_RIGHT); 247 fRowsControl->SetRange(1, 32); 248 249 uint32 columns; 250 uint32 rows; 251 BPrivate::get_workspaces_layout(&columns, &rows); 252 fColumnsControl->SetValue(columns); 253 fRowsControl->SetValue(rows); 254 255 screenBox->AddChild(BLayoutBuilder::Group<>() 256 .AddGroup(B_VERTICAL, B_USE_SMALL_SPACING) 257 .Add(workspaces) 258 .AddGrid(B_USE_DEFAULT_SPACING, B_USE_SMALL_SPACING) 259 // columns 260 .Add(fColumnsControl->CreateLabelLayoutItem(), 0, 0) 261 .Add(fColumnsControl->CreateTextViewLayoutItem(), 1, 0) 262 // rows 263 .Add(fRowsControl->CreateLabelLayoutItem(), 0, 1) 264 .Add(fRowsControl->CreateTextViewLayoutItem(), 1, 1) 265 .End() 266 .End() 267 .View()); 268 269 fBackgroundsButton = new BButton("BackgroundsButton", 270 B_TRANSLATE("Set background" B_UTF8_ELLIPSIS), 271 new BMessage(BUTTON_LAUNCH_BACKGROUNDS_MSG)); 272 fBackgroundsButton->SetFontSize(be_plain_font->Size() * 0.9); 273 screenBox->AddChild(fBackgroundsButton); 274 275 // box on the right with screen resolution, etc. 276 277 BBox* controlsBox = new BBox("controls box"); 278 controlsBox->SetLabel(workspaceMenuField); 279 BGroupView* outerControlsView = new BGroupView(B_VERTICAL); 280 outerControlsView->GroupLayout()->SetInsets(B_USE_DEFAULT_SPACING, 281 B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING); 282 controlsBox->AddChild(outerControlsView); 283 284 fResolutionMenu = new BPopUpMenu("resolution", true, true); 285 286 uint16 maxWidth = 0; 287 uint16 maxHeight = 0; 288 uint16 previousWidth = 0; 289 uint16 previousHeight = 0; 290 for (int32 i = 0; i < fScreenMode.CountModes(); i++) { 291 screen_mode mode = fScreenMode.ModeAt(i); 292 293 if (mode.width == previousWidth && mode.height == previousHeight) 294 continue; 295 296 previousWidth = mode.width; 297 previousHeight = mode.height; 298 if (maxWidth < mode.width) 299 maxWidth = mode.width; 300 if (maxHeight < mode.height) 301 maxHeight = mode.height; 302 303 BMessage* message = new BMessage(POP_RESOLUTION_MSG); 304 message->AddInt32("width", mode.width); 305 message->AddInt32("height", mode.height); 306 307 BString name; 308 name << mode.width << " x " << mode.height; 309 310 fResolutionMenu->AddItem(new BMenuItem(name.String(), message)); 311 } 312 313 fMonitorView->SetMaxResolution(maxWidth, maxHeight); 314 315 fResolutionField = new BMenuField("ResolutionMenu", 316 B_TRANSLATE("Resolution:"), fResolutionMenu); 317 fResolutionField->SetAlignment(B_ALIGN_RIGHT); 318 319 fColorsMenu = new BPopUpMenu("colors", true, false); 320 321 for (int32 i = 0; i < kColorSpaceCount; i++) { 322 if ((fSupportedColorSpaces & (1 << i)) == 0) 323 continue; 324 325 BMessage* message = new BMessage(POP_COLORS_MSG); 326 message->AddInt32("bits_per_pixel", kColorSpaces[i].bits_per_pixel); 327 message->AddInt32("space", kColorSpaces[i].space); 328 329 BMenuItem* item = new BMenuItem(kColorSpaces[i].label, message); 330 if (kColorSpaces[i].space == screen.ColorSpace()) 331 fUserSelectedColorSpace = item; 332 333 fColorsMenu->AddItem(item); 334 } 335 336 fColorsField = new BMenuField("ColorsMenu", B_TRANSLATE("Colors:"), 337 fColorsMenu); 338 fColorsField->SetAlignment(B_ALIGN_RIGHT); 339 340 fRefreshMenu = new BPopUpMenu("refresh rate", true, true); 341 342 float min, max; 343 if (fScreenMode.GetRefreshLimits(fActive, min, max) != B_OK) { 344 // if we couldn't obtain the refresh limits, reset to the default 345 // range. Constraints from detected monitors will fine-tune this 346 // later. 347 min = kRefreshRates[0]; 348 max = kRefreshRates[kRefreshRateCount - 1]; 349 } 350 351 if (min == max) { 352 // This is a special case for drivers that only support a single 353 // frequency, like the VESA driver 354 BString name; 355 refresh_rate_to_string(min, name); 356 BMessage *message = new BMessage(POP_REFRESH_MSG); 357 message->AddFloat("refresh", min); 358 BMenuItem *item = new BMenuItem(name.String(), message); 359 fRefreshMenu->AddItem(item); 360 item->SetEnabled(false); 361 } else { 362 monitor_info info; 363 if (fScreenMode.GetMonitorInfo(info) == B_OK) { 364 min = max_c(info.min_vertical_frequency, min); 365 max = min_c(info.max_vertical_frequency, max); 366 } 367 368 for (int32 i = 0; i < kRefreshRateCount; ++i) { 369 if (kRefreshRates[i] < min || kRefreshRates[i] > max) 370 continue; 371 372 BString name; 373 name << kRefreshRates[i] << " " << B_TRANSLATE("Hz"); 374 375 BMessage *message = new BMessage(POP_REFRESH_MSG); 376 message->AddFloat("refresh", kRefreshRates[i]); 377 378 fRefreshMenu->AddItem(new BMenuItem(name.String(), message)); 379 } 380 381 fOtherRefresh = new BMenuItem(B_TRANSLATE("Other" B_UTF8_ELLIPSIS), 382 new BMessage(POP_OTHER_REFRESH_MSG)); 383 fRefreshMenu->AddItem(fOtherRefresh); 384 } 385 386 fRefreshField = new BMenuField("RefreshMenu", B_TRANSLATE("Refresh rate:"), 387 fRefreshMenu); 388 fRefreshField->SetAlignment(B_ALIGN_RIGHT); 389 390 if (_IsVesa()) 391 fRefreshField->Hide(); 392 393 // enlarged area for multi-monitor settings 394 { 395 bool dummy; 396 uint32 dummy32; 397 bool multiMonSupport; 398 bool useLaptopPanelSupport; 399 bool tvStandardSupport; 400 401 multiMonSupport = TestMultiMonSupport(&screen) == B_OK; 402 useLaptopPanelSupport = GetUseLaptopPanel(&screen, &dummy) == B_OK; 403 tvStandardSupport = GetTVStandard(&screen, &dummy32) == B_OK; 404 405 // even if there is no support, we still create all controls 406 // to make sure we don't access NULL pointers later on 407 408 fCombineMenu = new BPopUpMenu("CombineDisplays", 409 true, true); 410 411 for (int32 i = 0; i < kCombineModeCount; i++) { 412 BMessage *message = new BMessage(POP_COMBINE_DISPLAYS_MSG); 413 message->AddInt32("mode", kCombineModes[i].mode); 414 415 fCombineMenu->AddItem(new BMenuItem(kCombineModes[i].name, 416 message)); 417 } 418 419 fCombineField = new BMenuField("CombineMenu", 420 B_TRANSLATE("Combine displays:"), fCombineMenu); 421 fCombineField->SetAlignment(B_ALIGN_RIGHT); 422 423 if (!multiMonSupport) 424 fCombineField->Hide(); 425 426 fSwapDisplaysMenu = new BPopUpMenu("SwapDisplays", 427 true, true); 428 429 // !order is important - we rely that boolean value == idx 430 BMessage *message = new BMessage(POP_SWAP_DISPLAYS_MSG); 431 message->AddBool("swap", false); 432 fSwapDisplaysMenu->AddItem(new BMenuItem(B_TRANSLATE("no"), message)); 433 434 message = new BMessage(POP_SWAP_DISPLAYS_MSG); 435 message->AddBool("swap", true); 436 fSwapDisplaysMenu->AddItem(new BMenuItem(B_TRANSLATE("yes"), message)); 437 438 fSwapDisplaysField = new BMenuField("SwapMenu", 439 B_TRANSLATE("Swap displays:"), fSwapDisplaysMenu); 440 fSwapDisplaysField->SetAlignment(B_ALIGN_RIGHT); 441 442 if (!multiMonSupport) 443 fSwapDisplaysField->Hide(); 444 445 fUseLaptopPanelMenu = new BPopUpMenu("UseLaptopPanel", 446 true, true); 447 448 // !order is important - we rely that boolean value == idx 449 message = new BMessage(POP_USE_LAPTOP_PANEL_MSG); 450 message->AddBool("use", false); 451 fUseLaptopPanelMenu->AddItem(new BMenuItem(B_TRANSLATE("if needed"), 452 message)); 453 454 message = new BMessage(POP_USE_LAPTOP_PANEL_MSG); 455 message->AddBool("use", true); 456 fUseLaptopPanelMenu->AddItem(new BMenuItem(B_TRANSLATE("always"), 457 message)); 458 459 fUseLaptopPanelField = new BMenuField("UseLaptopPanel", 460 B_TRANSLATE("Use laptop panel:"), fUseLaptopPanelMenu); 461 fUseLaptopPanelField->SetAlignment(B_ALIGN_RIGHT); 462 463 if (!useLaptopPanelSupport) 464 fUseLaptopPanelField->Hide(); 465 466 fTVStandardMenu = new BPopUpMenu("TVStandard", true, true); 467 468 // arbitrary limit 469 uint32 i; 470 for (i = 0; i < 100; ++i) { 471 uint32 mode; 472 if (GetNthSupportedTVStandard(&screen, i, &mode) != B_OK) 473 break; 474 475 BString name = tv_standard_to_string(mode); 476 477 message = new BMessage(POP_TV_STANDARD_MSG); 478 message->AddInt32("tv_standard", mode); 479 480 fTVStandardMenu->AddItem(new BMenuItem(name.String(), message)); 481 } 482 483 fTVStandardField = new BMenuField("tv standard", 484 B_TRANSLATE("Video format:"), fTVStandardMenu); 485 fTVStandardField->SetAlignment(B_ALIGN_RIGHT); 486 487 if (!tvStandardSupport || i == 0) 488 fTVStandardField->Hide(); 489 } 490 491 BLayoutBuilder::Group<>(outerControlsView) 492 .AddGrid(B_USE_DEFAULT_SPACING, B_USE_SMALL_SPACING) 493 .Add(fResolutionField->CreateLabelLayoutItem(), 0, 0) 494 .Add(fResolutionField->CreateMenuBarLayoutItem(), 1, 0) 495 .Add(fColorsField->CreateLabelLayoutItem(), 0, 1) 496 .Add(fColorsField->CreateMenuBarLayoutItem(), 1, 1) 497 .Add(fRefreshField->CreateLabelLayoutItem(), 0, 2) 498 .Add(fRefreshField->CreateMenuBarLayoutItem(), 1, 2) 499 .Add(fCombineField->CreateLabelLayoutItem(), 0, 3) 500 .Add(fCombineField->CreateMenuBarLayoutItem(), 1, 3) 501 .Add(fSwapDisplaysField->CreateLabelLayoutItem(), 0, 4) 502 .Add(fSwapDisplaysField->CreateMenuBarLayoutItem(), 1, 4) 503 .Add(fUseLaptopPanelField->CreateLabelLayoutItem(), 0, 5) 504 .Add(fUseLaptopPanelField->CreateMenuBarLayoutItem(), 1, 5) 505 .Add(fTVStandardField->CreateLabelLayoutItem(), 0, 6) 506 .Add(fTVStandardField->CreateMenuBarLayoutItem(), 1, 6) 507 .End(); 508 509 fBrightnessSlider = new BSlider("brightness", "Brightness", 510 NULL, 0, 255, B_HORIZONTAL); 511 512 status_t result = screen.GetBrightness(&fOriginalBrightness); 513 if (result == B_OK) { 514 fBrightnessSlider->SetModificationMessage( 515 new BMessage(SLIDER_BRIGHTNESS_MSG)); 516 fBrightnessSlider->SetValue(fOriginalBrightness * 255); 517 } else { 518 // The driver does not support changing the brightness, 519 // so hide the slider 520 fBrightnessSlider->Hide(); 521 522 fOriginalBrightness = -1; 523 } 524 525 // TODO: we don't support getting the screen's preferred settings 526 /* fDefaultsButton = new BButton(buttonRect, "DefaultsButton", "Defaults", 527 new BMessage(BUTTON_DEFAULTS_MSG));*/ 528 529 fApplyButton = new BButton("ApplyButton", B_TRANSLATE("Apply"), 530 new BMessage(BUTTON_APPLY_MSG)); 531 fApplyButton->SetEnabled(false); 532 BLayoutBuilder::Group<>(outerControlsView) 533 .AddGlue() 534 .AddGroup(B_HORIZONTAL) 535 .AddGlue() 536 .Add(fApplyButton); 537 538 fRevertButton = new BButton("RevertButton", B_TRANSLATE("Revert"), 539 new BMessage(BUTTON_REVERT_MSG)); 540 fRevertButton->SetEnabled(false); 541 542 BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_DEFAULT_SPACING) 543 .AddGroup(B_HORIZONTAL) 544 .AddGroup(B_VERTICAL, 0, 1) 545 .AddStrut(floorf(controlsBox->TopBorderOffset()) - 1) 546 .Add(screenBox) 547 .End() 548 .AddGroup(B_VERTICAL, 0, 1) 549 .Add(controlsBox, 2) 550 .Add(fBrightnessSlider) 551 .End() 552 .End() 553 .AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING) 554 .Add(fRevertButton) 555 .AddGlue() 556 .End() 557 .SetInsets(B_USE_WINDOW_SPACING); 558 559 _UpdateControls(); 560 _UpdateMonitor(); 561 562 MoveOnScreen(); 563 } 564 565 566 ScreenWindow::~ScreenWindow() 567 { 568 delete fSettings; 569 } 570 571 572 bool 573 ScreenWindow::QuitRequested() 574 { 575 fSettings->SetWindowFrame(Frame()); 576 577 // Write mode of workspace 0 (the boot workspace) to the vesa settings file 578 screen_mode vesaMode; 579 if (fBootWorkspaceApplied && fScreenMode.Get(vesaMode, 0) == B_OK) { 580 status_t status = _WriteVesaModeFile(vesaMode); 581 if (status < B_OK) { 582 BString warning = B_TRANSLATE("Could not write VESA mode settings" 583 " file:\n\t"); 584 warning << strerror(status); 585 BAlert* alert = new BAlert(B_TRANSLATE("Warning"), 586 warning.String(), B_TRANSLATE("OK"), NULL, 587 NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 588 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 589 alert->Go(); 590 } 591 } 592 593 be_app->PostMessage(B_QUIT_REQUESTED); 594 595 return BWindow::QuitRequested(); 596 } 597 598 599 /*! Update resolution list according to combine mode 600 (some resolutions may not be combinable due to memory restrictions). 601 */ 602 void 603 ScreenWindow::_CheckResolutionMenu() 604 { 605 for (int32 i = 0; i < fResolutionMenu->CountItems(); i++) 606 fResolutionMenu->ItemAt(i)->SetEnabled(false); 607 608 for (int32 i = 0; i < fScreenMode.CountModes(); i++) { 609 screen_mode mode = fScreenMode.ModeAt(i); 610 if (mode.combine != fSelected.combine) 611 continue; 612 613 BString name; 614 name << mode.width << " x " << mode.height; 615 616 BMenuItem *item = fResolutionMenu->FindItem(name.String()); 617 if (item != NULL) 618 item->SetEnabled(true); 619 } 620 } 621 622 623 /*! Update color and refresh options according to current mode 624 (a color space is made active if there is any mode with 625 given resolution and this colour space; same applies for 626 refresh rate, though "Other…" is always possible) 627 */ 628 void 629 ScreenWindow::_CheckColorMenu() 630 { 631 int32 supportsAnything = false; 632 int32 index = 0; 633 634 for (int32 i = 0; i < kColorSpaceCount; i++) { 635 if ((fSupportedColorSpaces & (1 << i)) == 0) 636 continue; 637 638 bool supported = false; 639 640 for (int32 j = 0; j < fScreenMode.CountModes(); j++) { 641 screen_mode mode = fScreenMode.ModeAt(j); 642 643 if (fSelected.width == mode.width 644 && fSelected.height == mode.height 645 && kColorSpaces[i].space == mode.space 646 && fSelected.combine == mode.combine) { 647 supportsAnything = true; 648 supported = true; 649 break; 650 } 651 } 652 653 BMenuItem* item = fColorsMenu->ItemAt(index++); 654 if (item) 655 item->SetEnabled(supported); 656 } 657 658 fColorsField->SetEnabled(supportsAnything); 659 660 if (!supportsAnything) 661 return; 662 663 // Make sure a valid item is selected 664 665 BMenuItem* item = fColorsMenu->FindMarked(); 666 bool changed = false; 667 668 if (item != fUserSelectedColorSpace) { 669 if (fUserSelectedColorSpace != NULL 670 && fUserSelectedColorSpace->IsEnabled()) { 671 fUserSelectedColorSpace->SetMarked(true); 672 item = fUserSelectedColorSpace; 673 changed = true; 674 } 675 } 676 if (item != NULL && !item->IsEnabled()) { 677 // find the next best item 678 int32 index = fColorsMenu->IndexOf(item); 679 bool found = false; 680 681 for (int32 i = index + 1; i < fColorsMenu->CountItems(); i++) { 682 item = fColorsMenu->ItemAt(i); 683 if (item->IsEnabled()) { 684 found = true; 685 break; 686 } 687 } 688 if (!found) { 689 // search backwards as well 690 for (int32 i = index - 1; i >= 0; i--) { 691 item = fColorsMenu->ItemAt(i); 692 if (item->IsEnabled()) 693 break; 694 } 695 } 696 697 item->SetMarked(true); 698 changed = true; 699 } 700 701 if (changed) { 702 // Update selected space 703 704 BMessage* message = item->Message(); 705 int32 space; 706 if (message->FindInt32("space", &space) == B_OK) { 707 fSelected.space = (color_space)space; 708 _UpdateColorLabel(); 709 } 710 } 711 } 712 713 714 /*! Enable/disable refresh options according to current mode. */ 715 void 716 ScreenWindow::_CheckRefreshMenu() 717 { 718 float min, max; 719 if (fScreenMode.GetRefreshLimits(fSelected, min, max) != B_OK || min == max) 720 return; 721 722 for (int32 i = fRefreshMenu->CountItems(); i-- > 0;) { 723 BMenuItem* item = fRefreshMenu->ItemAt(i); 724 BMessage* message = item->Message(); 725 float refresh; 726 if (message != NULL && message->FindFloat("refresh", &refresh) == B_OK) 727 item->SetEnabled(refresh >= min && refresh <= max); 728 } 729 } 730 731 732 /*! Activate appropriate menu item according to selected refresh rate */ 733 void 734 ScreenWindow::_UpdateRefreshControl() 735 { 736 for (int32 i = 0; i < fRefreshMenu->CountItems(); i++) { 737 BMenuItem* item = fRefreshMenu->ItemAt(i); 738 if (item->Message()->FindFloat("refresh") == fSelected.refresh) { 739 item->SetMarked(true); 740 // "Other" items only contains a refresh rate when active 741 if (fOtherRefresh != NULL) 742 fOtherRefresh->SetLabel(B_TRANSLATE("Other" B_UTF8_ELLIPSIS)); 743 return; 744 } 745 } 746 747 // this is a non-standard refresh rate 748 if (fOtherRefresh != NULL) { 749 fOtherRefresh->Message()->ReplaceFloat("refresh", fSelected.refresh); 750 fOtherRefresh->SetMarked(true); 751 752 BString string; 753 refresh_rate_to_string(fSelected.refresh, string); 754 fRefreshMenu->Superitem()->SetLabel(string.String()); 755 756 string.Append(B_TRANSLATE("/other" B_UTF8_ELLIPSIS)); 757 fOtherRefresh->SetLabel(string.String()); 758 } 759 } 760 761 762 void 763 ScreenWindow::_UpdateMonitorView() 764 { 765 BMessage updateMessage(UPDATE_DESKTOP_MSG); 766 updateMessage.AddInt32("width", fSelected.width); 767 updateMessage.AddInt32("height", fSelected.height); 768 769 PostMessage(&updateMessage, fMonitorView); 770 } 771 772 773 void 774 ScreenWindow::_UpdateControls() 775 { 776 _UpdateWorkspaceButtons(); 777 778 BMenuItem* item = fSwapDisplaysMenu->ItemAt((int32)fSelected.swap_displays); 779 if (item != NULL && !item->IsMarked()) 780 item->SetMarked(true); 781 782 item = fUseLaptopPanelMenu->ItemAt((int32)fSelected.use_laptop_panel); 783 if (item != NULL && !item->IsMarked()) 784 item->SetMarked(true); 785 786 for (int32 i = 0; i < fTVStandardMenu->CountItems(); i++) { 787 item = fTVStandardMenu->ItemAt(i); 788 789 uint32 tvStandard; 790 item->Message()->FindInt32("tv_standard", (int32 *)&tvStandard); 791 if (tvStandard == fSelected.tv_standard) { 792 if (!item->IsMarked()) 793 item->SetMarked(true); 794 break; 795 } 796 } 797 798 _CheckResolutionMenu(); 799 _CheckColorMenu(); 800 _CheckRefreshMenu(); 801 802 BString string; 803 resolution_to_string(fSelected, string); 804 item = fResolutionMenu->FindItem(string.String()); 805 806 if (item != NULL) { 807 if (!item->IsMarked()) 808 item->SetMarked(true); 809 } else { 810 // this is bad luck - if mode has been set via screen references, 811 // this case cannot occur; there are three possible solutions: 812 // 1. add a new resolution to list 813 // - we had to remove it as soon as a "valid" one is selected 814 // - we don't know which frequencies/bit depths are supported 815 // - as long as we haven't the GMT formula to create 816 // parameters for any resolution given, we cannot 817 // really set current mode - it's just not in the list 818 // 2. choose nearest resolution 819 // - probably a good idea, but implies coding and testing 820 // 3. choose lowest resolution 821 // - do you really think we are so lazy? yes, we are 822 item = fResolutionMenu->ItemAt(0); 823 if (item) 824 item->SetMarked(true); 825 826 // okay - at least we set menu label to active resolution 827 fResolutionMenu->Superitem()->SetLabel(string.String()); 828 } 829 830 // mark active combine mode 831 for (int32 i = 0; i < kCombineModeCount; i++) { 832 if (kCombineModes[i].mode == fSelected.combine) { 833 item = fCombineMenu->ItemAt(i); 834 if (item != NULL && !item->IsMarked()) 835 item->SetMarked(true); 836 break; 837 } 838 } 839 840 item = fColorsMenu->ItemAt(0); 841 842 for (int32 i = 0, index = 0; i < kColorSpaceCount; i++) { 843 if ((fSupportedColorSpaces & (1 << i)) == 0) 844 continue; 845 846 if (kColorSpaces[i].space == fSelected.space) { 847 item = fColorsMenu->ItemAt(index); 848 break; 849 } 850 851 index++; 852 } 853 854 if (item != NULL && !item->IsMarked()) 855 item->SetMarked(true); 856 857 _UpdateColorLabel(); 858 _UpdateMonitorView(); 859 _UpdateRefreshControl(); 860 861 _CheckApplyEnabled(); 862 } 863 864 865 /*! Reflect active mode in chosen settings */ 866 void 867 ScreenWindow::_UpdateActiveMode() 868 { 869 _UpdateActiveMode(current_workspace()); 870 } 871 872 873 void 874 ScreenWindow::_UpdateActiveMode(int32 workspace) 875 { 876 // Usually, this function gets called after a mode 877 // has been set manually; still, as the graphics driver 878 // is free to fiddle with mode passed, we better ask 879 // what kind of mode we actually got 880 if (fScreenMode.Get(fActive, workspace) == B_OK) { 881 fSelected = fActive; 882 883 _UpdateMonitor(); 884 _BuildSupportedColorSpaces(); 885 _UpdateControls(); 886 } 887 } 888 889 890 void 891 ScreenWindow::_UpdateWorkspaceButtons() 892 { 893 uint32 columns; 894 uint32 rows; 895 BPrivate::get_workspaces_layout(&columns, &rows); 896 897 // Set the max values enabling/disabling the up/down arrows 898 899 if (rows == 1) 900 fColumnsControl->SetMaxValue(32); 901 else if (rows == 2) 902 fColumnsControl->SetMaxValue(16); 903 else if (rows <= 4) 904 fColumnsControl->SetMaxValue(8); 905 else if (rows <= 8) 906 fColumnsControl->SetMaxValue(4); 907 else if (rows <= 16) 908 fColumnsControl->SetMaxValue(2); 909 else if (rows <= 32) 910 fColumnsControl->SetMaxValue(1); 911 912 if (columns == 1) 913 fRowsControl->SetMaxValue(32); 914 else if (columns == 2) 915 fRowsControl->SetMaxValue(16); 916 else if (columns <= 4) 917 fRowsControl->SetMaxValue(8); 918 else if (columns <= 8) 919 fRowsControl->SetMaxValue(4); 920 else if (columns <= 16) 921 fRowsControl->SetMaxValue(2); 922 else if (columns <= 32) 923 fRowsControl->SetMaxValue(1); 924 } 925 926 927 void 928 ScreenWindow::ScreenChanged(BRect frame, color_space mode) 929 { 930 // move window on screen, if necessary 931 if (frame.right <= Frame().right 932 && frame.bottom <= Frame().bottom) { 933 MoveTo((frame.Width() - Frame().Width()) / 2, 934 (frame.Height() - Frame().Height()) / 2); 935 } 936 } 937 938 939 void 940 ScreenWindow::WorkspaceActivated(int32 workspace, bool state) 941 { 942 if (fScreenMode.GetOriginalMode(fOriginal, workspace) == B_OK) { 943 _UpdateActiveMode(workspace); 944 945 BMessage message(UPDATE_DESKTOP_COLOR_MSG); 946 PostMessage(&message, fMonitorView); 947 } 948 } 949 950 951 void 952 ScreenWindow::MessageReceived(BMessage* message) 953 { 954 switch (message->what) { 955 case WORKSPACE_CHECK_MSG: 956 _CheckApplyEnabled(); 957 break; 958 959 case kMsgWorkspaceColumnsChanged: 960 { 961 uint32 newColumns = (uint32)fColumnsControl->Value(); 962 963 uint32 rows; 964 BPrivate::get_workspaces_layout(NULL, &rows); 965 BPrivate::set_workspaces_layout(newColumns, rows); 966 967 _UpdateWorkspaceButtons(); 968 fRowsControl->SetValue(rows); 969 // enables/disables up/down arrows 970 _CheckApplyEnabled(); 971 972 break; 973 } 974 975 case kMsgWorkspaceRowsChanged: 976 { 977 uint32 newRows = (uint32)fRowsControl->Value(); 978 979 uint32 columns; 980 BPrivate::get_workspaces_layout(&columns, NULL); 981 BPrivate::set_workspaces_layout(columns, newRows); 982 983 _UpdateWorkspaceButtons(); 984 fColumnsControl->SetValue(columns); 985 // enables/disables up/down arrows 986 _CheckApplyEnabled(); 987 break; 988 } 989 990 case POP_RESOLUTION_MSG: 991 { 992 message->FindInt32("width", &fSelected.width); 993 message->FindInt32("height", &fSelected.height); 994 995 _CheckColorMenu(); 996 _CheckRefreshMenu(); 997 998 _UpdateMonitorView(); 999 _UpdateRefreshControl(); 1000 1001 _CheckApplyEnabled(); 1002 break; 1003 } 1004 1005 case POP_COLORS_MSG: 1006 { 1007 int32 space; 1008 if (message->FindInt32("space", &space) != B_OK) 1009 break; 1010 1011 int32 index; 1012 if (message->FindInt32("index", &index) == B_OK 1013 && fColorsMenu->ItemAt(index) != NULL) 1014 fUserSelectedColorSpace = fColorsMenu->ItemAt(index); 1015 1016 fSelected.space = (color_space)space; 1017 _UpdateColorLabel(); 1018 1019 _CheckApplyEnabled(); 1020 break; 1021 } 1022 1023 case POP_REFRESH_MSG: 1024 { 1025 message->FindFloat("refresh", &fSelected.refresh); 1026 fOtherRefresh->SetLabel(B_TRANSLATE("Other" B_UTF8_ELLIPSIS)); 1027 // revert "Other…" label - it might have a refresh rate prefix 1028 1029 _CheckApplyEnabled(); 1030 break; 1031 } 1032 1033 case POP_OTHER_REFRESH_MSG: 1034 { 1035 // make sure menu shows something useful 1036 _UpdateRefreshControl(); 1037 1038 float min = 0, max = 999; 1039 fScreenMode.GetRefreshLimits(fSelected, min, max); 1040 if (min < gMinRefresh) 1041 min = gMinRefresh; 1042 if (max > gMaxRefresh) 1043 max = gMaxRefresh; 1044 1045 monitor_info info; 1046 if (fScreenMode.GetMonitorInfo(info) == B_OK) { 1047 min = max_c(info.min_vertical_frequency, min); 1048 max = min_c(info.max_vertical_frequency, max); 1049 } 1050 1051 RefreshWindow *fRefreshWindow = new RefreshWindow( 1052 fRefreshField->ConvertToScreen(B_ORIGIN), fSelected.refresh, 1053 min, max); 1054 fRefreshWindow->Show(); 1055 break; 1056 } 1057 1058 case SET_CUSTOM_REFRESH_MSG: 1059 { 1060 // user pressed "done" in "Other…" refresh dialog; 1061 // select the refresh rate chosen 1062 message->FindFloat("refresh", &fSelected.refresh); 1063 1064 _UpdateRefreshControl(); 1065 _CheckApplyEnabled(); 1066 break; 1067 } 1068 1069 case POP_COMBINE_DISPLAYS_MSG: 1070 { 1071 // new combine mode has bee chosen 1072 int32 mode; 1073 if (message->FindInt32("mode", &mode) == B_OK) 1074 fSelected.combine = (combine_mode)mode; 1075 1076 _CheckResolutionMenu(); 1077 _CheckApplyEnabled(); 1078 break; 1079 } 1080 1081 case POP_SWAP_DISPLAYS_MSG: 1082 message->FindBool("swap", &fSelected.swap_displays); 1083 _CheckApplyEnabled(); 1084 break; 1085 1086 case POP_USE_LAPTOP_PANEL_MSG: 1087 message->FindBool("use", &fSelected.use_laptop_panel); 1088 _CheckApplyEnabled(); 1089 break; 1090 1091 case POP_TV_STANDARD_MSG: 1092 message->FindInt32("tv_standard", (int32 *)&fSelected.tv_standard); 1093 _CheckApplyEnabled(); 1094 break; 1095 1096 case BUTTON_LAUNCH_BACKGROUNDS_MSG: 1097 if (be_roster->Launch(kBackgroundsSignature) == B_ALREADY_RUNNING) { 1098 app_info info; 1099 be_roster->GetAppInfo(kBackgroundsSignature, &info); 1100 be_roster->ActivateApp(info.team); 1101 } 1102 break; 1103 1104 case BUTTON_DEFAULTS_MSG: 1105 { 1106 // TODO: get preferred settings of screen 1107 fSelected.width = 640; 1108 fSelected.height = 480; 1109 fSelected.space = B_CMAP8; 1110 fSelected.refresh = 60.0; 1111 fSelected.combine = kCombineDisable; 1112 fSelected.swap_displays = false; 1113 fSelected.use_laptop_panel = false; 1114 fSelected.tv_standard = 0; 1115 1116 // TODO: workspace defaults 1117 1118 _UpdateControls(); 1119 break; 1120 } 1121 1122 case BUTTON_UNDO_MSG: 1123 fUndoScreenMode.Revert(); 1124 _UpdateActiveMode(); 1125 break; 1126 1127 case BUTTON_REVERT_MSG: 1128 { 1129 fModified = false; 1130 fBootWorkspaceApplied = false; 1131 1132 // ScreenMode::Revert() assumes that we first set the correct 1133 // number of workspaces 1134 1135 BPrivate::set_workspaces_layout(fOriginalWorkspacesColumns, 1136 fOriginalWorkspacesRows); 1137 _UpdateWorkspaceButtons(); 1138 1139 fScreenMode.Revert(); 1140 _UpdateActiveMode(); 1141 1142 BScreen screen(this); 1143 screen.SetBrightness(fOriginalBrightness); 1144 fBrightnessSlider->SetValue(fOriginalBrightness * 255); 1145 break; 1146 } 1147 1148 case BUTTON_APPLY_MSG: 1149 _Apply(); 1150 break; 1151 1152 case MAKE_INITIAL_MSG: 1153 // user pressed "keep" in confirmation dialog 1154 fModified = true; 1155 _UpdateActiveMode(); 1156 break; 1157 1158 case UPDATE_DESKTOP_COLOR_MSG: 1159 PostMessage(message, fMonitorView); 1160 break; 1161 1162 case SLIDER_BRIGHTNESS_MSG: 1163 { 1164 BScreen screen(this); 1165 screen.SetBrightness(message->FindInt32("be:value") / 255.f); 1166 _CheckApplyEnabled(); 1167 break; 1168 } 1169 1170 default: 1171 BWindow::MessageReceived(message); 1172 } 1173 } 1174 1175 1176 status_t 1177 ScreenWindow::_WriteVesaModeFile(const screen_mode& mode) const 1178 { 1179 BPath path; 1180 status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true); 1181 if (status < B_OK) 1182 return status; 1183 1184 path.Append("kernel/drivers"); 1185 status = create_directory(path.Path(), 0755); 1186 if (status < B_OK) 1187 return status; 1188 1189 path.Append("vesa"); 1190 BFile file; 1191 status = file.SetTo(path.Path(), B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE); 1192 if (status < B_OK) 1193 return status; 1194 1195 char buffer[256]; 1196 snprintf(buffer, sizeof(buffer), "mode %" B_PRId32 " %" B_PRId32 " %" 1197 B_PRId32 "\n", mode.width, mode.height, mode.BitsPerPixel()); 1198 1199 ssize_t bytesWritten = file.Write(buffer, strlen(buffer)); 1200 if (bytesWritten < B_OK) 1201 return bytesWritten; 1202 1203 return B_OK; 1204 } 1205 1206 1207 void 1208 ScreenWindow::_BuildSupportedColorSpaces() 1209 { 1210 fSupportedColorSpaces = 0; 1211 1212 for (int32 i = 0; i < kColorSpaceCount; i++) { 1213 for (int32 j = 0; j < fScreenMode.CountModes(); j++) { 1214 if (fScreenMode.ModeAt(j).space == kColorSpaces[i].space) { 1215 fSupportedColorSpaces |= 1 << i; 1216 break; 1217 } 1218 } 1219 } 1220 } 1221 1222 1223 void 1224 ScreenWindow::_CheckApplyEnabled() 1225 { 1226 bool applyEnabled = true; 1227 1228 if (fSelected == fActive) { 1229 applyEnabled = false; 1230 if (fAllWorkspacesItem->IsMarked()) { 1231 screen_mode screenMode; 1232 const int32 workspaceCount = count_workspaces(); 1233 for (int32 i = 0; i < workspaceCount; i++) { 1234 fScreenMode.Get(screenMode, i); 1235 if (screenMode != fSelected) { 1236 applyEnabled = true; 1237 break; 1238 } 1239 } 1240 } 1241 } 1242 1243 fApplyButton->SetEnabled(applyEnabled); 1244 1245 uint32 columns; 1246 uint32 rows; 1247 BPrivate::get_workspaces_layout(&columns, &rows); 1248 1249 BScreen screen(this); 1250 float brightness = -1; 1251 screen.GetBrightness(&brightness); 1252 1253 fRevertButton->SetEnabled(columns != fOriginalWorkspacesColumns 1254 || rows != fOriginalWorkspacesRows 1255 || brightness != fOriginalBrightness 1256 || fSelected != fOriginal); 1257 } 1258 1259 1260 void 1261 ScreenWindow::_UpdateOriginal() 1262 { 1263 BPrivate::get_workspaces_layout(&fOriginalWorkspacesColumns, 1264 &fOriginalWorkspacesRows); 1265 1266 fScreenMode.Get(fOriginal); 1267 fScreenMode.UpdateOriginalModes(); 1268 } 1269 1270 1271 void 1272 ScreenWindow::_UpdateMonitor() 1273 { 1274 monitor_info info; 1275 float diagonalInches; 1276 status_t status = fScreenMode.GetMonitorInfo(info, &diagonalInches); 1277 if (status == B_OK) { 1278 char text[512]; 1279 snprintf(text, sizeof(text), "%s%s%s %g\"", info.vendor, 1280 info.name[0] ? " " : "", info.name, diagonalInches); 1281 1282 fMonitorInfo->SetText(text); 1283 1284 if (fMonitorInfo->IsHidden(fMonitorInfo)) 1285 fMonitorInfo->Show(); 1286 } else { 1287 if (!fMonitorInfo->IsHidden(fMonitorInfo)) 1288 fMonitorInfo->Hide(); 1289 } 1290 1291 // Add info about the graphics device 1292 1293 accelerant_device_info deviceInfo; 1294 1295 if (fScreenMode.GetDeviceInfo(deviceInfo) == B_OK) { 1296 BString deviceString; 1297 1298 if (deviceInfo.name[0] && deviceInfo.chipset[0]) { 1299 deviceString.SetToFormat("%s (%s)", deviceInfo.name, 1300 deviceInfo.chipset); 1301 } else if (deviceInfo.name[0] || deviceInfo.chipset[0]) { 1302 deviceString 1303 = deviceInfo.name[0] ? deviceInfo.name : deviceInfo.chipset; 1304 } 1305 1306 fDeviceInfo->SetText(deviceString); 1307 } 1308 1309 1310 char text[512]; 1311 size_t length = 0; 1312 text[0] = 0; 1313 1314 if (status == B_OK) { 1315 if (info.min_horizontal_frequency != 0 1316 && info.min_vertical_frequency != 0 1317 && info.max_pixel_clock != 0) { 1318 length = snprintf(text, sizeof(text), 1319 B_TRANSLATE("Horizonal frequency:\t%lu - %lu kHz\n" 1320 "Vertical frequency:\t%lu - %lu Hz\n\n" 1321 "Maximum pixel clock:\t%g MHz"), 1322 info.min_horizontal_frequency, info.max_horizontal_frequency, 1323 info.min_vertical_frequency, info.max_vertical_frequency, 1324 info.max_pixel_clock / 1000.0); 1325 } 1326 if (info.serial_number[0] && length < sizeof(text)) { 1327 length += snprintf(text + length, sizeof(text) - length, 1328 B_TRANSLATE("%sSerial no.: %s"), length ? "\n\n" : "", 1329 info.serial_number); 1330 if (info.produced.week != 0 && info.produced.year != 0 1331 && length < sizeof(text)) { 1332 length += snprintf(text + length, sizeof(text) - length, 1333 " (%u/%u)", info.produced.week, info.produced.year); 1334 } 1335 } 1336 } 1337 1338 if (text[0]) 1339 fMonitorView->SetToolTip(text); 1340 } 1341 1342 1343 void 1344 ScreenWindow::_UpdateColorLabel() 1345 { 1346 BString string; 1347 string << fSelected.BitsPerPixel() << " " << B_TRANSLATE("bits/pixel"); 1348 fColorsMenu->Superitem()->SetLabel(string.String()); 1349 } 1350 1351 1352 void 1353 ScreenWindow::_Apply() 1354 { 1355 // make checkpoint, so we can undo these changes 1356 fUndoScreenMode.UpdateOriginalModes(); 1357 1358 status_t status = fScreenMode.Set(fSelected); 1359 if (status == B_OK) { 1360 // use the mode that has eventually been set and 1361 // thus we know to be working; it can differ from 1362 // the mode selected by user due to hardware limitation 1363 display_mode newMode; 1364 BScreen screen(this); 1365 screen.GetMode(&newMode); 1366 1367 if (fAllWorkspacesItem->IsMarked()) { 1368 int32 originatingWorkspace = current_workspace(); 1369 const int32 workspaceCount = count_workspaces(); 1370 for (int32 i = 0; i < workspaceCount; i++) { 1371 if (i != originatingWorkspace) 1372 screen.SetMode(i, &newMode, true); 1373 } 1374 fBootWorkspaceApplied = true; 1375 } else { 1376 if (current_workspace() == 0) 1377 fBootWorkspaceApplied = true; 1378 } 1379 1380 fActive = fSelected; 1381 1382 // TODO: only show alert when this is an unknown mode 1383 BAlert* window = new AlertWindow(this); 1384 window->Go(NULL); 1385 } else { 1386 char message[256]; 1387 snprintf(message, sizeof(message), 1388 B_TRANSLATE("The screen mode could not be set:\n\t%s\n"), 1389 screen_errors(status)); 1390 BAlert* alert = new BAlert(B_TRANSLATE("Warning"), message, 1391 B_TRANSLATE("OK"), NULL, NULL, 1392 B_WIDTH_AS_USUAL, B_WARNING_ALERT); 1393 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 1394 alert->Go(); 1395 } 1396 } 1397