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