display_controller.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "ash/display/display_controller.h" 6 7#include <algorithm> 8 9#include "ash/ash_switches.h" 10#include "ash/display/display_manager.h" 11#include "ash/host/root_window_host_factory.h" 12#include "ash/root_window_controller.h" 13#include "ash/screen_ash.h" 14#include "ash/shell.h" 15#include "ash/wm/coordinate_conversion.h" 16#include "ash/wm/property_util.h" 17#include "ash/wm/window_util.h" 18#include "base/command_line.h" 19#include "base/json/json_value_converter.h" 20#include "base/string_piece.h" 21#include "base/stringprintf.h" 22#include "base/values.h" 23#include "ui/aura/client/screen_position_client.h" 24#include "ui/aura/env.h" 25#include "ui/aura/root_window.h" 26#include "ui/aura/window.h" 27#include "ui/aura/window_property.h" 28#include "ui/compositor/dip_util.h" 29#include "ui/gfx/display.h" 30#include "ui/gfx/screen.h" 31 32#if defined(OS_CHROMEOS) 33#include "ash/display/output_configurator_animation.h" 34#include "base/chromeos/chromeos_version.h" 35#include "base/string_number_conversions.h" 36#include "base/time.h" 37#include "chromeos/display/output_configurator.h" 38#include "ui/base/x/x11_util.h" 39 40// Including this at the bottom to avoid other 41// potential conflict with chrome headers. 42#include <X11/extensions/Xrandr.h> 43#undef RootWindow 44#endif // defined(OS_CHROMEOS) 45 46DECLARE_WINDOW_PROPERTY_TYPE(gfx::Display::Rotation); 47 48namespace ash { 49namespace { 50 51DEFINE_WINDOW_PROPERTY_KEY(gfx::Display::Rotation, kRotationPropertyKey, 52 gfx::Display::ROTATE_0); 53 54// Primary display stored in global object as it can be 55// accessed after Shell is deleted. A separate display instance is created 56// during the shutdown instead of always keeping two display instances 57// (one here and another one in display_manager) in sync, which is error prone. 58int64 primary_display_id = gfx::Display::kInvalidDisplayID; 59gfx::Display* primary_display_for_shutdown = NULL; 60// Keeps the number of displays during the shutdown after 61// ash::Shell:: is deleted. 62int num_displays_for_shutdown = -1; 63 64// The maximum value for 'offset' in DisplayLayout in case of outliers. Need 65// to change this value in case to support even larger displays. 66const int kMaxValidOffset = 10000; 67 68// The number of pixels to overlap between the primary and secondary displays, 69// in case that the offset value is too large. 70const int kMinimumOverlapForInvalidOffset = 100; 71 72// Specifies how long the display change should have been disabled 73// after each display change operations. 74// |kCycleDisplayThrottleTimeoutMs| is set to be longer to avoid 75// changing the settings while the system is still configurating 76// displays. It will be overriden by |kAfterDisplayChangeThrottleTimeoutMs| 77// when the display change happens, so the actual timeout is much shorter. 78const int64 kAfterDisplayChangeThrottleTimeoutMs = 500; 79const int64 kCycleDisplayThrottleTimeoutMs = 4000; 80const int64 kSwapDisplayThrottleTimeoutMs = 500; 81 82// Persistent key names 83const char kPositionKey[] = "position"; 84const char kOffsetKey[] = "offset"; 85const char kMirroredKey[] = "mirrored"; 86 87bool GetPositionFromString(const base::StringPiece& position, 88 DisplayLayout::Position* field) { 89 if (position == "top") { 90 *field = DisplayLayout::TOP; 91 return true; 92 } else if (position == "bottom") { 93 *field = DisplayLayout::BOTTOM; 94 return true; 95 } else if (position == "right") { 96 *field = DisplayLayout::RIGHT; 97 return true; 98 } else if (position == "left") { 99 *field = DisplayLayout::LEFT; 100 return true; 101 } 102 LOG(ERROR) << "Invalid position value: " << position; 103 return false; 104} 105 106std::string GetStringFromPosition(DisplayLayout::Position position) { 107 switch (position) { 108 case DisplayLayout::TOP: 109 return std::string("top"); 110 case DisplayLayout::BOTTOM: 111 return std::string("bottom"); 112 case DisplayLayout::RIGHT: 113 return std::string("right"); 114 case DisplayLayout::LEFT: 115 return std::string("left"); 116 } 117 return std::string("unknown"); 118} 119 120internal::DisplayManager* GetDisplayManager() { 121 return Shell::GetInstance()->display_manager(); 122} 123 124void RotateRootWindow(aura::RootWindow* root_window, 125 const gfx::Display& display, 126 const internal::DisplayInfo& info) { 127 // TODO(oshima): Add animation. (crossfade+rotation, or just cross-fade) 128#if defined(OS_WIN) 129 // Windows 8 bots refused to resize the host window, and 130 // updating the transform results in incorrectly resizing 131 // the root window. Don't apply the transform unless 132 // necessary so that unit tests pass on win8 bots. 133 if (info.rotation() == root_window->GetProperty(kRotationPropertyKey)) 134 return; 135 root_window->SetProperty(kRotationPropertyKey, info.rotation()); 136#endif 137 gfx::Transform rotate; 138 // TODO(oshima): Manually complute the inverse of the 139 // rotate+translate matrix to compensate for computation error in 140 // the inverted matrix. Ideally, SkMatrix should have special 141 // case handling for rotate+translate case. crbug.com/222483. 142 gfx::Transform reverse_rotate; 143 144 // The origin is (0, 0), so the translate width/height must be reduced by 1. 145 switch (info.rotation()) { 146 case gfx::Display::ROTATE_0: 147 break; 148 case gfx::Display::ROTATE_90: 149 rotate.Translate(display.bounds().height() - 1, 0); 150 rotate.Rotate(90); 151 // Rotate 270 instead of 90 as it will cause calcuration error. 152 reverse_rotate.Rotate(270); 153 reverse_rotate.Translate(-(display.bounds().height() - 1), 0); 154 break; 155 case gfx::Display::ROTATE_270: 156 rotate.Translate(0, display.bounds().width() - 1); 157 rotate.Rotate(270); 158 reverse_rotate.Rotate(90); 159 reverse_rotate.Translate(0, -(display.bounds().width() - 1)); 160 break; 161 case gfx::Display::ROTATE_180: 162 rotate.Translate(display.bounds().width() - 1, 163 display.bounds().height() - 1); 164 rotate.Rotate(180); 165 reverse_rotate.Rotate(180); 166 reverse_rotate.Translate(-(display.bounds().width() - 1), 167 -(display.bounds().height() - 1)); 168 break; 169 } 170 root_window->SetTransformPair(rotate, reverse_rotate); 171} 172 173void SetDisplayPropertiesOnHostWindow(aura::RootWindow* root, 174 const gfx::Display& display) { 175 internal::DisplayInfo info = 176 GetDisplayManager()->GetDisplayInfo(display.id()); 177#if defined(OS_CHROMEOS) 178 // Native window property (Atom in X11) that specifies the display's 179 // rotation, scale factor and if it's internal display. They are 180 // read and used by touchpad/mouse driver directly on X (contact 181 // adlr@ for more details on touchpad/mouse driver side). The value 182 // of the rotation is one of 0 (normal), 1 (90 degrees clockwise), 2 183 // (180 degree) or 3 (270 degrees clockwise). The value of the 184 // scale factor is in percent (100, 140, 200 etc). 185 const char kRotationProp[] = "_CHROME_DISPLAY_ROTATION"; 186 const char kScaleFactorProp[] = "_CHROME_DISPLAY_SCALE_FACTOR"; 187 const char kInternalProp[] = "_CHROME_DISPLAY_INTERNAL"; 188 const char kCARDINAL[] = "CARDINAL"; 189 int xrandr_rotation = RR_Rotate_0; 190 switch (info.rotation()) { 191 case gfx::Display::ROTATE_0: 192 xrandr_rotation = RR_Rotate_0; 193 break; 194 case gfx::Display::ROTATE_90: 195 xrandr_rotation = RR_Rotate_90; 196 break; 197 case gfx::Display::ROTATE_180: 198 xrandr_rotation = RR_Rotate_180; 199 break; 200 case gfx::Display::ROTATE_270: 201 xrandr_rotation = RR_Rotate_270; 202 break; 203 } 204 205 int internal = display.IsInternal() ? 1 : 0; 206 gfx::AcceleratedWidget xwindow = root->GetAcceleratedWidget(); 207 ui::SetIntProperty(xwindow, kInternalProp, kCARDINAL, internal); 208 ui::SetIntProperty(xwindow, kRotationProp, kCARDINAL, xrandr_rotation); 209 ui::SetIntProperty(xwindow, 210 kScaleFactorProp, 211 kCARDINAL, 212 100 * display.device_scale_factor()); 213#endif 214 RotateRootWindow(root, display, info); 215} 216 217} // namespace 218 219//////////////////////////////////////////////////////////////////////////////// 220// DisplayLayout 221 222// static 223DisplayLayout DisplayLayout::FromInts(int position, int offsets) { 224 return DisplayLayout(static_cast<Position>(position), offsets); 225} 226 227DisplayLayout::DisplayLayout() 228 : position(RIGHT), 229 offset(0), 230 mirrored(false) {} 231 232DisplayLayout::DisplayLayout(DisplayLayout::Position position, int offset) 233 : position(position), 234 offset(offset), 235 mirrored(false) { 236 DCHECK_LE(TOP, position); 237 DCHECK_GE(LEFT, position); 238 239 // Set the default value to |position| in case position is invalid. DCHECKs 240 // above doesn't stop in Release builds. 241 if (TOP > position || LEFT < position) 242 this->position = RIGHT; 243 244 DCHECK_GE(kMaxValidOffset, abs(offset)); 245} 246 247DisplayLayout DisplayLayout::Invert() const { 248 Position inverted_position = RIGHT; 249 switch (position) { 250 case TOP: 251 inverted_position = BOTTOM; 252 break; 253 case BOTTOM: 254 inverted_position = TOP; 255 break; 256 case RIGHT: 257 inverted_position = LEFT; 258 break; 259 case LEFT: 260 inverted_position = RIGHT; 261 break; 262 } 263 return DisplayLayout(inverted_position, -offset); 264} 265 266// static 267bool DisplayLayout::ConvertFromValue(const base::Value& value, 268 DisplayLayout* layout) { 269 base::JSONValueConverter<DisplayLayout> converter; 270 return converter.Convert(value, layout); 271} 272 273// static 274bool DisplayLayout::ConvertToValue(const DisplayLayout& layout, 275 base::Value* value) { 276 base::DictionaryValue* dict_value = NULL; 277 if (!value->GetAsDictionary(&dict_value) || dict_value == NULL) 278 return false; 279 280 const std::string position_str = GetStringFromPosition(layout.position); 281 dict_value->SetString(kPositionKey, position_str); 282 dict_value->SetInteger(kOffsetKey, layout.offset); 283 dict_value->SetBoolean(kMirroredKey, layout.mirrored); 284 return true; 285} 286 287std::string DisplayLayout::ToString() const { 288 const std::string position_str = GetStringFromPosition(position); 289 return base::StringPrintf( 290 "%s, %d%s", 291 position_str.c_str(), offset, mirrored ? ", mirrored" : ""); 292} 293 294// static 295void DisplayLayout::RegisterJSONConverter( 296 base::JSONValueConverter<DisplayLayout>* converter) { 297 converter->RegisterCustomField<Position>( 298 kPositionKey, &DisplayLayout::position, &GetPositionFromString); 299 converter->RegisterIntField(kOffsetKey, &DisplayLayout::offset); 300 converter->RegisterBoolField(kMirroredKey, &DisplayLayout::mirrored); 301} 302 303//////////////////////////////////////////////////////////////////////////////// 304// DisplayChangeLimiter 305 306DisplayController::DisplayChangeLimiter::DisplayChangeLimiter() 307 : throttle_timeout_(base::Time::Now()) { 308} 309 310void DisplayController::DisplayChangeLimiter::SetThrottleTimeout( 311 int64 throttle_ms) { 312 throttle_timeout_ = 313 base::Time::Now() + base::TimeDelta::FromMilliseconds(throttle_ms); 314} 315 316bool DisplayController::DisplayChangeLimiter::IsThrottled() const { 317 return base::Time::Now() < throttle_timeout_; 318} 319 320//////////////////////////////////////////////////////////////////////////////// 321// DisplayController 322 323DisplayController::DisplayController() 324 : desired_primary_display_id_(gfx::Display::kInvalidDisplayID), 325 primary_root_window_for_replace_(NULL) { 326 CommandLine* command_line = CommandLine::ForCurrentProcess(); 327#if defined(OS_CHROMEOS) 328 if (!command_line->HasSwitch(switches::kAshDisableDisplayChangeLimiter) && 329 base::chromeos::IsRunningOnChromeOS()) 330 limiter_.reset(new DisplayChangeLimiter); 331#endif 332 if (command_line->HasSwitch(switches::kAshSecondaryDisplayLayout)) { 333 std::string value = command_line->GetSwitchValueASCII( 334 switches::kAshSecondaryDisplayLayout); 335 char layout; 336 int offset = 0; 337 if (sscanf(value.c_str(), "%c,%d", &layout, &offset) == 2) { 338 if (layout == 't') 339 default_display_layout_.position = DisplayLayout::TOP; 340 else if (layout == 'b') 341 default_display_layout_.position = DisplayLayout::BOTTOM; 342 else if (layout == 'r') 343 default_display_layout_.position = DisplayLayout::RIGHT; 344 else if (layout == 'l') 345 default_display_layout_.position = DisplayLayout::LEFT; 346 default_display_layout_.offset = offset; 347 } 348 } 349 // Reset primary display to make sure that tests don't use 350 // stale display info from previous tests. 351 primary_display_id = gfx::Display::kInvalidDisplayID; 352 delete primary_display_for_shutdown; 353 primary_display_for_shutdown = NULL; 354 num_displays_for_shutdown = -1; 355} 356 357DisplayController::~DisplayController() { 358 DCHECK(primary_display_for_shutdown); 359} 360 361void DisplayController::Start() { 362 Shell::GetScreen()->AddObserver(this); 363} 364 365void DisplayController::Shutdown() { 366 DCHECK(!primary_display_for_shutdown); 367 primary_display_for_shutdown = new gfx::Display( 368 GetDisplayManager()->GetDisplayForId(primary_display_id)); 369 num_displays_for_shutdown = GetDisplayManager()->GetNumDisplays(); 370 371 Shell::GetScreen()->RemoveObserver(this); 372 // Delete all root window controllers, which deletes root window 373 // from the last so that the primary root window gets deleted last. 374 for (std::map<int64, aura::RootWindow*>::const_reverse_iterator it = 375 root_windows_.rbegin(); it != root_windows_.rend(); ++it) { 376 internal::RootWindowController* controller = 377 GetRootWindowController(it->second); 378 DCHECK(controller); 379 delete controller; 380 } 381} 382 383// static 384const gfx::Display& DisplayController::GetPrimaryDisplay() { 385 DCHECK_NE(primary_display_id, gfx::Display::kInvalidDisplayID); 386 if (primary_display_for_shutdown) 387 return *primary_display_for_shutdown; 388 return GetDisplayManager()->GetDisplayForId(primary_display_id); 389} 390 391// static 392int DisplayController::GetNumDisplays() { 393 if (num_displays_for_shutdown >= 0) 394 return num_displays_for_shutdown; 395 return GetDisplayManager()->GetNumDisplays(); 396} 397 398// static 399bool DisplayController::HasPrimaryDisplay() { 400 return primary_display_id != gfx::Display::kInvalidDisplayID; 401} 402 403void DisplayController::InitPrimaryDisplay() { 404 const gfx::Display* primary_candidate = 405 GetDisplayManager()->GetPrimaryDisplayCandidate(); 406 primary_display_id = primary_candidate->id(); 407 AddRootWindowForDisplay(*primary_candidate); 408 UpdateDisplayBoundsForLayout(); 409} 410 411void DisplayController::InitSecondaryDisplays() { 412 internal::DisplayManager* display_manager = GetDisplayManager(); 413 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) { 414 const gfx::Display* display = display_manager->GetDisplayAt(i); 415 if (primary_display_id != display->id()) { 416 aura::RootWindow* root = AddRootWindowForDisplay(*display); 417 if (desired_primary_display_id_ == display->id()) 418 SetPrimaryDisplay(*display); 419 Shell::GetInstance()->InitRootWindowForSecondaryDisplay(root); 420 } 421 } 422 UpdateDisplayBoundsForLayout(); 423} 424 425void DisplayController::AddObserver(Observer* observer) { 426 observers_.AddObserver(observer); 427} 428 429void DisplayController::RemoveObserver(Observer* observer) { 430 observers_.RemoveObserver(observer); 431} 432 433aura::RootWindow* DisplayController::GetPrimaryRootWindow() { 434 DCHECK(!root_windows_.empty()); 435 return root_windows_[primary_display_id]; 436} 437 438aura::RootWindow* DisplayController::GetRootWindowForDisplayId(int64 id) { 439 return root_windows_[id]; 440} 441 442void DisplayController::CloseChildWindows() { 443 for (std::map<int64, aura::RootWindow*>::const_iterator it = 444 root_windows_.begin(); it != root_windows_.end(); ++it) { 445 aura::RootWindow* root_window = it->second; 446 internal::RootWindowController* controller = 447 GetRootWindowController(root_window); 448 if (controller) { 449 controller->CloseChildWindows(); 450 } else { 451 while (!root_window->children().empty()) { 452 aura::Window* child = root_window->children()[0]; 453 delete child; 454 } 455 } 456 } 457} 458 459std::vector<aura::RootWindow*> DisplayController::GetAllRootWindows() { 460 std::vector<aura::RootWindow*> windows; 461 for (std::map<int64, aura::RootWindow*>::const_iterator it = 462 root_windows_.begin(); it != root_windows_.end(); ++it) { 463 DCHECK(it->second); 464 if (GetRootWindowController(it->second)) 465 windows.push_back(it->second); 466 } 467 return windows; 468} 469 470gfx::Insets DisplayController::GetOverscanInsets(int64 display_id) const { 471 return GetDisplayManager()->GetOverscanInsets(display_id); 472} 473 474void DisplayController::SetOverscanInsets(int64 display_id, 475 const gfx::Insets& insets_in_dip) { 476 GetDisplayManager()->SetOverscanInsets(display_id, insets_in_dip); 477} 478 479void DisplayController::ClearCustomOverscanInsets(int64 display_id) { 480 GetDisplayManager()->ClearCustomOverscanInsets(display_id); 481} 482 483std::vector<internal::RootWindowController*> 484DisplayController::GetAllRootWindowControllers() { 485 std::vector<internal::RootWindowController*> controllers; 486 for (std::map<int64, aura::RootWindow*>::const_iterator it = 487 root_windows_.begin(); it != root_windows_.end(); ++it) { 488 internal::RootWindowController* controller = 489 GetRootWindowController(it->second); 490 if (controller) 491 controllers.push_back(controller); 492 } 493 return controllers; 494} 495 496void DisplayController::SetDefaultDisplayLayout(const DisplayLayout& layout) { 497 CommandLine* command_line = CommandLine::ForCurrentProcess(); 498 if (!command_line->HasSwitch(switches::kAshSecondaryDisplayLayout) && 499 (default_display_layout_.position != layout.position || 500 default_display_layout_.offset != layout.offset)) { 501 default_display_layout_ = layout; 502 NotifyDisplayConfigurationChanging(); 503 UpdateDisplayBoundsForLayout(); 504 NotifyDisplayConfigurationChanged(); 505 } 506} 507 508void DisplayController::RegisterLayoutForDisplayIdPair( 509 int64 id1, 510 int64 id2, 511 const DisplayLayout& layout) { 512 RegisterLayoutForDisplayIdPairInternal(id1, id2, layout, true); 513} 514 515void DisplayController::RegisterLayoutForDisplayId( 516 int64 id, 517 const DisplayLayout& layout) { 518 int64 first_id = gfx::Display::InternalDisplayId(); 519 if (first_id == gfx::Display::kInvalidDisplayID) 520 first_id = GetDisplayManager()->first_display_id(); 521 // Caveat: This doesn't work if the machine booted with 522 // no display. 523 // Ignore if the layout was registered for the internal or 524 // 1st display. 525 if (first_id != id) 526 RegisterLayoutForDisplayIdPairInternal(first_id, id, layout, false); 527} 528 529void DisplayController::SetLayoutForCurrentDisplays( 530 const DisplayLayout& layout_relative_to_primary) { 531 DCHECK_EQ(2U, GetDisplayManager()->GetNumDisplays()); 532 if (GetDisplayManager()->GetNumDisplays() < 2) 533 return; 534 const gfx::Display& primary = GetPrimaryDisplay(); 535 const DisplayIdPair pair = GetCurrentDisplayIdPair(); 536 // Invert if the primary was swapped. 537 DisplayLayout to_set = pair.first == primary.id() ? 538 layout_relative_to_primary : layout_relative_to_primary.Invert(); 539 540 const DisplayLayout& current_layout = paired_layouts_[pair]; 541 if (to_set.position != current_layout.position || 542 to_set.offset != current_layout.offset) { 543 paired_layouts_[pair] = to_set; 544 NotifyDisplayConfigurationChanging(); 545 UpdateDisplayBoundsForLayout(); 546 NotifyDisplayConfigurationChanged(); 547 } 548} 549 550DisplayLayout DisplayController::GetCurrentDisplayLayout() const { 551 DCHECK_EQ(2U, GetDisplayManager()->num_connected_displays()); 552 // Invert if the primary was swapped. 553 if (GetDisplayManager()->num_connected_displays() > 1) { 554 DisplayIdPair pair = GetCurrentDisplayIdPair(); 555 DisplayLayout layout = GetRegisteredDisplayLayout(pair); 556 const gfx::Display& primary = GetPrimaryDisplay(); 557 // Invert if the primary was swapped. If mirrored, first is always 558 // primary. 559 return pair.first == primary.id() ? layout : layout.Invert(); 560 } 561 // On release build, just fallback to default instead of blowing up. 562 return default_display_layout_; 563} 564 565DisplayIdPair DisplayController::GetCurrentDisplayIdPair() const { 566 internal::DisplayManager* display_manager = GetDisplayManager(); 567 const gfx::Display& primary = GetPrimaryDisplay(); 568 if (display_manager->IsMirrored()) 569 return std::make_pair(primary.id(), display_manager->mirrored_display_id()); 570 571 const gfx::Display& secondary = ScreenAsh::GetSecondaryDisplay(); 572 if (primary.IsInternal() || 573 GetDisplayManager()->first_display_id() == primary.id()) { 574 return std::make_pair(primary.id(), secondary.id()); 575 } else { 576 // Display has been Swapped. 577 return std::make_pair(secondary.id(), primary.id()); 578 } 579} 580 581DisplayLayout DisplayController::GetRegisteredDisplayLayout( 582 const DisplayIdPair& pair) const { 583 std::map<DisplayIdPair, DisplayLayout>::const_iterator iter = 584 paired_layouts_.find(pair); 585 return iter != paired_layouts_.end() ? iter->second : default_display_layout_; 586} 587 588void DisplayController::CycleDisplayMode() { 589 if (limiter_.get()) { 590 if (limiter_->IsThrottled()) 591 return; 592 limiter_->SetThrottleTimeout(kCycleDisplayThrottleTimeoutMs); 593 } 594#if defined(OS_CHROMEOS) 595 Shell* shell = Shell::GetInstance(); 596 internal::DisplayManager* display_manager = GetDisplayManager(); 597 if (!base::chromeos::IsRunningOnChromeOS()) { 598 internal::DisplayManager::CycleDisplay(); 599 } else if (display_manager->num_connected_displays() > 1) { 600 chromeos::OutputState new_state = display_manager->IsMirrored() ? 601 chromeos::STATE_DUAL_EXTENDED : chromeos::STATE_DUAL_MIRROR; 602 internal::OutputConfiguratorAnimation* animation = 603 shell->output_configurator_animation(); 604 animation->StartFadeOutAnimation(base::Bind( 605 base::IgnoreResult(&chromeos::OutputConfigurator::SetDisplayMode), 606 base::Unretained(shell->output_configurator()), 607 new_state)); 608 } 609#endif 610} 611 612void DisplayController::SwapPrimaryDisplay() { 613 if (limiter_.get()) { 614 if (limiter_->IsThrottled()) 615 return; 616 limiter_->SetThrottleTimeout(kSwapDisplayThrottleTimeoutMs); 617 } 618 619 if (Shell::GetScreen()->GetNumDisplays() > 1) { 620#if defined(OS_CHROMEOS) 621 internal::OutputConfiguratorAnimation* animation = 622 Shell::GetInstance()->output_configurator_animation(); 623 if (animation) { 624 animation->StartFadeOutAnimation(base::Bind( 625 &DisplayController::OnFadeOutForSwapDisplayFinished, 626 base::Unretained(this))); 627 } else { 628 SetPrimaryDisplay(ScreenAsh::GetSecondaryDisplay()); 629 } 630#else 631 SetPrimaryDisplay(ScreenAsh::GetSecondaryDisplay()); 632#endif 633 } 634} 635 636void DisplayController::SetPrimaryDisplayId(int64 id) { 637 desired_primary_display_id_ = id; 638 639 if (desired_primary_display_id_ == primary_display_id) 640 return; 641 642 internal::DisplayManager* display_manager = GetDisplayManager(); 643 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) { 644 gfx::Display* display = display_manager->GetDisplayAt(i); 645 if (display->id() == id) { 646 SetPrimaryDisplay(*display); 647 break; 648 } 649 } 650} 651 652void DisplayController::SetPrimaryDisplay( 653 const gfx::Display& new_primary_display) { 654 internal::DisplayManager* display_manager = GetDisplayManager(); 655 DCHECK(new_primary_display.is_valid()); 656 DCHECK(display_manager->IsActiveDisplay(new_primary_display)); 657 658 if (!new_primary_display.is_valid() || 659 !display_manager->IsActiveDisplay(new_primary_display)) { 660 LOG(ERROR) << "Invalid or non-existent display is requested:" 661 << new_primary_display.ToString(); 662 return; 663 } 664 665 if (primary_display_id == new_primary_display.id() || 666 root_windows_.size() < 2) { 667 return; 668 } 669 670 aura::RootWindow* non_primary_root = root_windows_[new_primary_display.id()]; 671 LOG_IF(ERROR, !non_primary_root) 672 << "Unknown display is requested in SetPrimaryDisplay: id=" 673 << new_primary_display.id(); 674 if (!non_primary_root) 675 return; 676 677 gfx::Display old_primary_display = GetPrimaryDisplay(); 678 679 // Swap root windows between current and new primary display. 680 aura::RootWindow* primary_root = root_windows_[primary_display_id]; 681 DCHECK(primary_root); 682 DCHECK_NE(primary_root, non_primary_root); 683 684 root_windows_[new_primary_display.id()] = primary_root; 685 primary_root->SetProperty(internal::kDisplayIdKey, new_primary_display.id()); 686 687 root_windows_[old_primary_display.id()] = non_primary_root; 688 non_primary_root->SetProperty(internal::kDisplayIdKey, 689 old_primary_display.id()); 690 691 primary_display_id = new_primary_display.id(); 692 desired_primary_display_id_ = primary_display_id; 693 694 display_manager->UpdateWorkAreaOfDisplayNearestWindow( 695 primary_root, old_primary_display.GetWorkAreaInsets()); 696 display_manager->UpdateWorkAreaOfDisplayNearestWindow( 697 non_primary_root, new_primary_display.GetWorkAreaInsets()); 698 699 // Update the dispay manager with new display info. 700 std::vector<internal::DisplayInfo> display_info_list; 701 display_info_list.push_back(display_manager->GetDisplayInfo( 702 primary_display_id)); 703 display_info_list.push_back(display_manager->GetDisplayInfo( 704 GetSecondaryDisplay()->id())); 705 GetDisplayManager()->set_force_bounds_changed(true); 706 GetDisplayManager()->UpdateDisplays(display_info_list); 707 GetDisplayManager()->set_force_bounds_changed(false); 708} 709 710gfx::Display* DisplayController::GetSecondaryDisplay() { 711 internal::DisplayManager* display_manager = GetDisplayManager(); 712 CHECK_EQ(2U, display_manager->GetNumDisplays()); 713 return display_manager->GetDisplayAt(0)->id() == primary_display_id ? 714 display_manager->GetDisplayAt(1) : display_manager->GetDisplayAt(0); 715} 716 717void DisplayController::OnDisplayBoundsChanged(const gfx::Display& display) { 718 if (limiter_.get()) 719 limiter_->SetThrottleTimeout(kAfterDisplayChangeThrottleTimeoutMs); 720 const internal::DisplayInfo& display_info = 721 GetDisplayManager()->GetDisplayInfo(display.id()); 722 DCHECK(!display_info.bounds_in_pixel().IsEmpty()); 723 724 UpdateDisplayBoundsForLayout(); 725 aura::RootWindow* root = root_windows_[display.id()]; 726 root->SetHostBoundsAndInsetsAndRootWindowScale( 727 display_info.bounds_in_pixel(), 728 display_info.GetOverscanInsetsInPixel(), 729 display_info.ui_scale()); 730 SetDisplayPropertiesOnHostWindow(root, display); 731} 732 733void DisplayController::OnDisplayAdded(const gfx::Display& display) { 734 if (limiter_.get()) 735 limiter_->SetThrottleTimeout(kAfterDisplayChangeThrottleTimeoutMs); 736 737 if (primary_root_window_for_replace_) { 738 DCHECK(root_windows_.empty()); 739 primary_display_id = display.id(); 740 root_windows_[display.id()] = primary_root_window_for_replace_; 741 primary_root_window_for_replace_->SetProperty( 742 internal::kDisplayIdKey, display.id()); 743 primary_root_window_for_replace_ = NULL; 744 UpdateDisplayBoundsForLayout(); 745 const internal::DisplayInfo& display_info = 746 GetDisplayManager()->GetDisplayInfo(display.id()); 747 root_windows_[display.id()]->SetHostBoundsAndInsetsAndRootWindowScale( 748 display_info.bounds_in_pixel(), 749 display_info.GetOverscanInsetsInPixel(), 750 display_info.ui_scale()); 751 } else { 752 DCHECK(!root_windows_.empty()); 753 aura::RootWindow* root = AddRootWindowForDisplay(display); 754 UpdateDisplayBoundsForLayout(); 755 if (desired_primary_display_id_ == display.id()) 756 SetPrimaryDisplay(display); 757 Shell::GetInstance()->InitRootWindowForSecondaryDisplay(root); 758 } 759} 760 761void DisplayController::OnDisplayRemoved(const gfx::Display& display) { 762 if (limiter_.get()) 763 limiter_->SetThrottleTimeout(kAfterDisplayChangeThrottleTimeoutMs); 764 765 aura::RootWindow* root_to_delete = root_windows_[display.id()]; 766 DCHECK(root_to_delete) << display.ToString(); 767 768 // Display for root window will be deleted when the Primary RootWindow 769 // is deleted by the Shell. 770 root_windows_.erase(display.id()); 771 772 // When the primary root window's display is removed, move the primary 773 // root to the other display. 774 if (primary_display_id == display.id()) { 775 // Temporarily store the primary root window in 776 // |primary_root_window_for_replace_| when replacing the display. 777 if (root_windows_.size() == 0) { 778 primary_display_id = gfx::Display::kInvalidDisplayID; 779 primary_root_window_for_replace_ = root_to_delete; 780 return; 781 } 782 DCHECK_EQ(1U, root_windows_.size()); 783 primary_display_id = GetSecondaryDisplay()->id(); 784 aura::RootWindow* primary_root = root_to_delete; 785 786 // Delete the other root instead. 787 root_to_delete = root_windows_[primary_display_id]; 788 root_to_delete->SetProperty(internal::kDisplayIdKey, display.id()); 789 790 // Setup primary root. 791 root_windows_[primary_display_id] = primary_root; 792 primary_root->SetProperty(internal::kDisplayIdKey, primary_display_id); 793 794 OnDisplayBoundsChanged( 795 GetDisplayManager()->GetDisplayForId(primary_display_id)); 796 } 797 internal::RootWindowController* controller = 798 GetRootWindowController(root_to_delete); 799 DCHECK(controller); 800 controller->MoveWindowsTo(GetPrimaryRootWindow()); 801 // Delete most of root window related objects, but don't delete 802 // root window itself yet because the stack may be using it. 803 controller->Shutdown(); 804 MessageLoop::current()->DeleteSoon(FROM_HERE, controller); 805} 806 807aura::RootWindow* DisplayController::CreateRootWindowForDisplay( 808 const gfx::Display& display) { 809 static int root_window_count = 0; 810 const internal::DisplayInfo& display_info = 811 GetDisplayManager()->GetDisplayInfo(display.id()); 812 const gfx::Rect& bounds_in_pixel = display_info.bounds_in_pixel(); 813 aura::RootWindow::CreateParams params(bounds_in_pixel); 814 params.host = Shell::GetInstance()->root_window_host_factory()-> 815 CreateRootWindowHost(bounds_in_pixel); 816 params.initial_insets = display_info.GetOverscanInsetsInPixel(); 817 params.initial_root_window_scale = display_info.ui_scale(); 818 aura::RootWindow* root_window = new aura::RootWindow(params); 819 root_window->SetName( 820 base::StringPrintf("RootWindow-%d", root_window_count++)); 821 822 // No need to remove RootWindowObserver because 823 // the DisplayManager object outlives RootWindow objects. 824 root_window->AddRootWindowObserver(GetDisplayManager()); 825 root_window->SetProperty(internal::kDisplayIdKey, display.id()); 826 root_window->Init(); 827 return root_window; 828} 829 830aura::RootWindow* DisplayController::AddRootWindowForDisplay( 831 const gfx::Display& display) { 832 aura::RootWindow* root = CreateRootWindowForDisplay(display); 833 root_windows_[display.id()] = root; 834 SetDisplayPropertiesOnHostWindow(root, display); 835 836#if defined(OS_CHROMEOS) 837 static bool force_constrain_pointer_to_root = 838 CommandLine::ForCurrentProcess()->HasSwitch( 839 switches::kAshConstrainPointerToRoot); 840 if (base::chromeos::IsRunningOnChromeOS() || force_constrain_pointer_to_root) 841 root->ConfineCursorToWindow(); 842#endif 843 return root; 844} 845 846void DisplayController::UpdateDisplayBoundsForLayout() { 847 if (Shell::GetScreen()->GetNumDisplays() < 2 || 848 GetDisplayManager()->num_connected_displays() < 2) { 849 return; 850 } 851 852 DCHECK_EQ(2, Shell::GetScreen()->GetNumDisplays()); 853 const gfx::Rect& primary_bounds = GetPrimaryDisplay().bounds(); 854 855 gfx::Display* secondary_display = GetSecondaryDisplay(); 856 const gfx::Rect& secondary_bounds = secondary_display->bounds(); 857 gfx::Point new_secondary_origin = primary_bounds.origin(); 858 859 const DisplayLayout layout = GetCurrentDisplayLayout(); 860 DisplayLayout::Position position = layout.position; 861 862 // Ignore the offset in case the secondary display doesn't share edges with 863 // the primary display. 864 int offset = layout.offset; 865 if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM) { 866 offset = std::min( 867 offset, primary_bounds.width() - kMinimumOverlapForInvalidOffset); 868 offset = std::max( 869 offset, -secondary_bounds.width() + kMinimumOverlapForInvalidOffset); 870 } else { 871 offset = std::min( 872 offset, primary_bounds.height() - kMinimumOverlapForInvalidOffset); 873 offset = std::max( 874 offset, -secondary_bounds.height() + kMinimumOverlapForInvalidOffset); 875 } 876 switch (position) { 877 case DisplayLayout::TOP: 878 new_secondary_origin.Offset(offset, -secondary_bounds.height()); 879 break; 880 case DisplayLayout::RIGHT: 881 new_secondary_origin.Offset(primary_bounds.width(), offset); 882 break; 883 case DisplayLayout::BOTTOM: 884 new_secondary_origin.Offset(offset, primary_bounds.height()); 885 break; 886 case DisplayLayout::LEFT: 887 new_secondary_origin.Offset(-secondary_bounds.width(), offset); 888 break; 889 } 890 gfx::Insets insets = secondary_display->GetWorkAreaInsets(); 891 secondary_display->set_bounds( 892 gfx::Rect(new_secondary_origin, secondary_bounds.size())); 893 secondary_display->UpdateWorkAreaFromInsets(insets); 894} 895 896void DisplayController::NotifyDisplayConfigurationChanging() { 897 FOR_EACH_OBSERVER(Observer, observers_, OnDisplayConfigurationChanging()); 898} 899 900void DisplayController::NotifyDisplayConfigurationChanged() { 901 internal::DisplayManager* display_manager = GetDisplayManager(); 902 if (display_manager->num_connected_displays() > 1) { 903 DisplayIdPair pair = GetCurrentDisplayIdPair(); 904 bool exists = paired_layouts_.find(pair) != paired_layouts_.end(); 905 if (exists || display_manager->IsMirrored()) { 906 if (!exists) 907 paired_layouts_[pair] = default_display_layout_; 908 paired_layouts_[pair].mirrored = display_manager->IsMirrored(); 909 } 910 } 911 FOR_EACH_OBSERVER(Observer, observers_, OnDisplayConfigurationChanged()); 912} 913 914void DisplayController::RegisterLayoutForDisplayIdPairInternal( 915 int64 id1, 916 int64 id2, 917 const DisplayLayout& layout, 918 bool override) { 919 DisplayIdPair pair = std::make_pair(id1, id2); 920 if (override || paired_layouts_.find(pair) == paired_layouts_.end()) 921 paired_layouts_[pair] = layout; 922} 923 924void DisplayController::OnFadeOutForSwapDisplayFinished() { 925#if defined(OS_CHROMEOS) 926 SetPrimaryDisplay(ScreenAsh::GetSecondaryDisplay()); 927 Shell::GetInstance()->output_configurator_animation()->StartFadeInAnimation(); 928#endif 929} 930 931} // namespace ash 932