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