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