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