display_controller.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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_layout_store.h" 13#include "ash/display/display_manager.h" 14#include "ash/display/mirror_window_controller.h" 15#include "ash/display/root_window_transformers.h" 16#include "ash/host/root_window_host_factory.h" 17#include "ash/root_window_controller.h" 18#include "ash/root_window_settings.h" 19#include "ash/screen_ash.h" 20#include "ash/shell.h" 21#include "ash/wm/coordinate_conversion.h" 22#include "base/command_line.h" 23#include "base/strings/stringprintf.h" 24#include "third_party/skia/include/utils/SkMatrix44.h" 25#include "ui/aura/client/activation_client.h" 26#include "ui/aura/client/capture_client.h" 27#include "ui/aura/client/cursor_client.h" 28#include "ui/aura/client/focus_client.h" 29#include "ui/aura/client/screen_position_client.h" 30#include "ui/aura/root_window.h" 31#include "ui/aura/root_window_transformer.h" 32#include "ui/aura/window.h" 33#include "ui/aura/window_property.h" 34#include "ui/aura/window_tracker.h" 35#include "ui/compositor/compositor.h" 36#include "ui/compositor/dip_util.h" 37#include "ui/gfx/display.h" 38#include "ui/gfx/screen.h" 39 40#if defined(OS_CHROMEOS) 41#include "base/sys_info.h" 42#include "base/time/time.h" 43#if defined(USE_X11) 44#include "ash/display/output_configurator_animation.h" 45#include "chromeos/display/output_configurator.h" 46#include "ui/base/x/x11_util.h" 47#include "ui/gfx/x/x11_types.h" 48 49// Including this at the bottom to avoid other 50// potential conflict with chrome headers. 51#include <X11/extensions/Xrandr.h> 52#undef RootWindow 53#endif // defined(USE_X11) 54#endif // defined(OS_CHROMEOS) 55 56namespace ash { 57namespace { 58 59// Primary display stored in global object as it can be 60// accessed after Shell is deleted. A separate display instance is created 61// during the shutdown instead of always keeping two display instances 62// (one here and another one in display_manager) in sync, which is error prone. 63int64 primary_display_id = gfx::Display::kInvalidDisplayID; 64gfx::Display* primary_display_for_shutdown = NULL; 65// Keeps the number of displays during the shutdown after 66// ash::Shell:: is deleted. 67int num_displays_for_shutdown = -1; 68 69// Specifies how long the display change should have been disabled 70// after each display change operations. 71// |kCycleDisplayThrottleTimeoutMs| is set to be longer to avoid 72// changing the settings while the system is still configurating 73// displays. It will be overriden by |kAfterDisplayChangeThrottleTimeoutMs| 74// when the display change happens, so the actual timeout is much shorter. 75const int64 kAfterDisplayChangeThrottleTimeoutMs = 500; 76const int64 kCycleDisplayThrottleTimeoutMs = 4000; 77const int64 kSwapDisplayThrottleTimeoutMs = 500; 78 79internal::DisplayManager* GetDisplayManager() { 80 return Shell::GetInstance()->display_manager(); 81} 82 83void SetDisplayPropertiesOnHostWindow(aura::RootWindow* root, 84 const gfx::Display& display) { 85 internal::DisplayInfo info = 86 GetDisplayManager()->GetDisplayInfo(display.id()); 87#if defined(OS_CHROMEOS) && defined(USE_X11) 88 // Native window property (Atom in X11) that specifies the display's 89 // rotation, scale factor and if it's internal display. They are 90 // read and used by touchpad/mouse driver directly on X (contact 91 // adlr@ for more details on touchpad/mouse driver side). The value 92 // of the rotation is one of 0 (normal), 1 (90 degrees clockwise), 2 93 // (180 degree) or 3 (270 degrees clockwise). The value of the 94 // scale factor is in percent (100, 140, 200 etc). 95 const char kRotationProp[] = "_CHROME_DISPLAY_ROTATION"; 96 const char kScaleFactorProp[] = "_CHROME_DISPLAY_SCALE_FACTOR"; 97 const char kInternalProp[] = "_CHROME_DISPLAY_INTERNAL"; 98 const char kCARDINAL[] = "CARDINAL"; 99 int xrandr_rotation = RR_Rotate_0; 100 switch (info.rotation()) { 101 case gfx::Display::ROTATE_0: 102 xrandr_rotation = RR_Rotate_0; 103 break; 104 case gfx::Display::ROTATE_90: 105 xrandr_rotation = RR_Rotate_90; 106 break; 107 case gfx::Display::ROTATE_180: 108 xrandr_rotation = RR_Rotate_180; 109 break; 110 case gfx::Display::ROTATE_270: 111 xrandr_rotation = RR_Rotate_270; 112 break; 113 } 114 115 int internal = display.IsInternal() ? 1 : 0; 116 gfx::AcceleratedWidget xwindow = root->GetAcceleratedWidget(); 117 ui::SetIntProperty(xwindow, kInternalProp, kCARDINAL, internal); 118 ui::SetIntProperty(xwindow, kRotationProp, kCARDINAL, xrandr_rotation); 119 ui::SetIntProperty(xwindow, 120 kScaleFactorProp, 121 kCARDINAL, 122 100 * display.device_scale_factor()); 123#endif 124 scoped_ptr<aura::RootWindowTransformer> transformer( 125 internal::CreateRootWindowTransformerForDisplay(root, display)); 126 root->SetRootWindowTransformer(transformer.Pass()); 127} 128 129} // namespace 130 131namespace internal { 132 133// A utility class to store/restore focused/active window 134// when the display configuration has changed. 135class FocusActivationStore { 136 public: 137 FocusActivationStore() 138 : activation_client_(NULL), 139 capture_client_(NULL), 140 focus_client_(NULL), 141 focused_(NULL), 142 active_(NULL) { 143 } 144 145 void Store(bool display_removed) { 146 if (!activation_client_) { 147 aura::RootWindow* root = Shell::GetPrimaryRootWindow(); 148 activation_client_ = aura::client::GetActivationClient(root); 149 capture_client_ = aura::client::GetCaptureClient(root); 150 focus_client_ = aura::client::GetFocusClient(root); 151 } 152 focused_ = focus_client_->GetFocusedWindow(); 153 if (focused_) 154 tracker_.Add(focused_); 155 active_ = activation_client_->GetActiveWindow(); 156 if (active_ && focused_ != active_) 157 tracker_.Add(active_); 158 159 // Deactivate the window to close menu / bubble windows. 160 if (display_removed) 161 activation_client_->DeactivateWindow(active_); 162 163 // Release capture if any. 164 capture_client_->SetCapture(NULL); 165 // Clear the focused window if any. This is necessary because a 166 // window may be deleted when losing focus (fullscreen flash for 167 // example). If the focused window is still alive after move, it'll 168 // be re-focused below. 169 if (display_removed) 170 focus_client_->FocusWindow(NULL); 171 } 172 173 void Restore() { 174 // Restore focused or active window if it's still alive. 175 if (focused_ && tracker_.Contains(focused_)) { 176 focus_client_->FocusWindow(focused_); 177 } else if (active_ && tracker_.Contains(active_)) { 178 activation_client_->ActivateWindow(active_); 179 } 180 if (focused_) 181 tracker_.Remove(focused_); 182 if (active_) 183 tracker_.Remove(active_); 184 focused_ = NULL; 185 active_ = NULL; 186 } 187 188 private: 189 aura::client::ActivationClient* activation_client_; 190 aura::client::CaptureClient* capture_client_; 191 aura::client::FocusClient* focus_client_; 192 aura::WindowTracker tracker_; 193 aura::Window* focused_; 194 aura::Window* active_; 195 196 DISALLOW_COPY_AND_ASSIGN(FocusActivationStore); 197}; 198 199} // namespace internal 200 201//////////////////////////////////////////////////////////////////////////////// 202// DisplayChangeLimiter 203 204DisplayController::DisplayChangeLimiter::DisplayChangeLimiter() 205 : throttle_timeout_(base::Time::Now()) { 206} 207 208void DisplayController::DisplayChangeLimiter::SetThrottleTimeout( 209 int64 throttle_ms) { 210 throttle_timeout_ = 211 base::Time::Now() + base::TimeDelta::FromMilliseconds(throttle_ms); 212} 213 214bool DisplayController::DisplayChangeLimiter::IsThrottled() const { 215 return base::Time::Now() < throttle_timeout_; 216} 217 218//////////////////////////////////////////////////////////////////////////////// 219// DisplayController 220 221DisplayController::DisplayController() 222 : primary_root_window_for_replace_(NULL), 223 focus_activation_store_(new internal::FocusActivationStore()), 224 mirror_window_controller_(new internal::MirrorWindowController) { 225#if defined(OS_CHROMEOS) 226 CommandLine* command_line = CommandLine::ForCurrentProcess(); 227 if (!command_line->HasSwitch(switches::kAshDisableDisplayChangeLimiter) && 228 base::SysInfo::IsRunningOnChromeOS()) 229 limiter_.reset(new DisplayChangeLimiter); 230#endif 231 // Reset primary display to make sure that tests don't use 232 // stale display info from previous tests. 233 primary_display_id = gfx::Display::kInvalidDisplayID; 234 delete primary_display_for_shutdown; 235 primary_display_for_shutdown = NULL; 236 num_displays_for_shutdown = -1; 237} 238 239DisplayController::~DisplayController() { 240 DCHECK(primary_display_for_shutdown); 241} 242 243void DisplayController::Start() { 244 Shell::GetScreen()->AddObserver(this); 245 Shell::GetInstance()->display_manager()->set_delegate(this); 246} 247 248void DisplayController::Shutdown() { 249 // Unset the display manager's delegate here because 250 // DisplayManager outlives DisplayController. 251 Shell::GetInstance()->display_manager()->set_delegate(NULL); 252 253 mirror_window_controller_.reset(); 254 255 DCHECK(!primary_display_for_shutdown); 256 primary_display_for_shutdown = new gfx::Display( 257 GetDisplayManager()->GetDisplayForId(primary_display_id)); 258 num_displays_for_shutdown = GetDisplayManager()->GetNumDisplays(); 259 260 Shell::GetScreen()->RemoveObserver(this); 261 // Delete all root window controllers, which deletes root window 262 // from the last so that the primary root window gets deleted last. 263 for (std::map<int64, aura::RootWindow*>::const_reverse_iterator it = 264 root_windows_.rbegin(); it != root_windows_.rend(); ++it) { 265 internal::RootWindowController* controller = 266 internal::GetRootWindowController(it->second); 267 DCHECK(controller); 268 delete controller; 269 } 270} 271 272// static 273const gfx::Display& DisplayController::GetPrimaryDisplay() { 274 DCHECK_NE(primary_display_id, gfx::Display::kInvalidDisplayID); 275 if (primary_display_for_shutdown) 276 return *primary_display_for_shutdown; 277 return GetDisplayManager()->GetDisplayForId(primary_display_id); 278} 279 280// static 281int DisplayController::GetNumDisplays() { 282 if (num_displays_for_shutdown >= 0) 283 return num_displays_for_shutdown; 284 return GetDisplayManager()->GetNumDisplays(); 285} 286 287void DisplayController::InitPrimaryDisplay() { 288 const gfx::Display& primary_candidate = 289 GetDisplayManager()->GetPrimaryDisplayCandidate(); 290 primary_display_id = primary_candidate.id(); 291 AddRootWindowForDisplay(primary_candidate); 292} 293 294void DisplayController::InitSecondaryDisplays() { 295 internal::DisplayManager* display_manager = GetDisplayManager(); 296 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) { 297 const gfx::Display& display = display_manager->GetDisplayAt(i); 298 if (primary_display_id != display.id()) { 299 aura::RootWindow* root = AddRootWindowForDisplay(display); 300 internal::RootWindowController::CreateForSecondaryDisplay(root); 301 } 302 } 303 UpdateHostWindowNames(); 304} 305 306void DisplayController::AddObserver(Observer* observer) { 307 observers_.AddObserver(observer); 308} 309 310void DisplayController::RemoveObserver(Observer* observer) { 311 observers_.RemoveObserver(observer); 312} 313 314aura::RootWindow* DisplayController::GetPrimaryRootWindow() { 315 DCHECK(!root_windows_.empty()); 316 return root_windows_[primary_display_id]; 317} 318 319aura::RootWindow* DisplayController::GetRootWindowForDisplayId(int64 id) { 320 return root_windows_[id]; 321} 322 323void DisplayController::CloseChildWindows() { 324 for (std::map<int64, aura::RootWindow*>::const_iterator it = 325 root_windows_.begin(); it != root_windows_.end(); ++it) { 326 aura::RootWindow* root_window = it->second; 327 internal::RootWindowController* controller = 328 internal::GetRootWindowController(root_window); 329 if (controller) { 330 controller->CloseChildWindows(); 331 } else { 332 while (!root_window->children().empty()) { 333 aura::Window* child = root_window->children()[0]; 334 delete child; 335 } 336 } 337 } 338} 339 340std::vector<aura::RootWindow*> DisplayController::GetAllRootWindows() { 341 std::vector<aura::RootWindow*> windows; 342 for (std::map<int64, aura::RootWindow*>::const_iterator it = 343 root_windows_.begin(); it != root_windows_.end(); ++it) { 344 DCHECK(it->second); 345 if (internal::GetRootWindowController(it->second)) 346 windows.push_back(it->second); 347 } 348 return windows; 349} 350 351gfx::Insets DisplayController::GetOverscanInsets(int64 display_id) const { 352 return GetDisplayManager()->GetOverscanInsets(display_id); 353} 354 355void DisplayController::SetOverscanInsets(int64 display_id, 356 const gfx::Insets& insets_in_dip) { 357 GetDisplayManager()->SetOverscanInsets(display_id, insets_in_dip); 358} 359 360std::vector<internal::RootWindowController*> 361DisplayController::GetAllRootWindowControllers() { 362 std::vector<internal::RootWindowController*> controllers; 363 for (std::map<int64, aura::RootWindow*>::const_iterator it = 364 root_windows_.begin(); it != root_windows_.end(); ++it) { 365 internal::RootWindowController* controller = 366 internal::GetRootWindowController(it->second); 367 if (controller) 368 controllers.push_back(controller); 369 } 370 return controllers; 371} 372 373void DisplayController::ToggleMirrorMode() { 374 internal::DisplayManager* display_manager = GetDisplayManager(); 375 if (display_manager->num_connected_displays() <= 1) 376 return; 377 378 if (limiter_) { 379 if (limiter_->IsThrottled()) 380 return; 381 limiter_->SetThrottleTimeout(kCycleDisplayThrottleTimeoutMs); 382 } 383#if defined(OS_CHROMEOS) && defined(USE_X11) 384 Shell* shell = Shell::GetInstance(); 385 internal::OutputConfiguratorAnimation* animation = 386 shell->output_configurator_animation(); 387 animation->StartFadeOutAnimation(base::Bind( 388 base::IgnoreResult(&internal::DisplayManager::SetMirrorMode), 389 base::Unretained(display_manager), 390 !display_manager->IsMirrored())); 391#endif 392} 393 394void DisplayController::SwapPrimaryDisplay() { 395 if (limiter_) { 396 if (limiter_->IsThrottled()) 397 return; 398 limiter_->SetThrottleTimeout(kSwapDisplayThrottleTimeoutMs); 399 } 400 401 if (Shell::GetScreen()->GetNumDisplays() > 1) { 402#if defined(OS_CHROMEOS) && defined(USE_X11) 403 internal::OutputConfiguratorAnimation* animation = 404 Shell::GetInstance()->output_configurator_animation(); 405 if (animation) { 406 animation->StartFadeOutAnimation(base::Bind( 407 &DisplayController::OnFadeOutForSwapDisplayFinished, 408 base::Unretained(this))); 409 } else { 410 SetPrimaryDisplay(ScreenAsh::GetSecondaryDisplay()); 411 } 412#else 413 SetPrimaryDisplay(ScreenAsh::GetSecondaryDisplay()); 414#endif 415 } 416} 417 418void DisplayController::SetPrimaryDisplayId(int64 id) { 419 DCHECK_NE(gfx::Display::kInvalidDisplayID, id); 420 if (id == gfx::Display::kInvalidDisplayID || primary_display_id == id) 421 return; 422 423 const gfx::Display& display = GetDisplayManager()->GetDisplayForId(id); 424 if (display.is_valid()) 425 SetPrimaryDisplay(display); 426} 427 428void DisplayController::SetPrimaryDisplay( 429 const gfx::Display& new_primary_display) { 430 internal::DisplayManager* display_manager = GetDisplayManager(); 431 DCHECK(new_primary_display.is_valid()); 432 DCHECK(display_manager->IsActiveDisplay(new_primary_display)); 433 434 if (!new_primary_display.is_valid() || 435 !display_manager->IsActiveDisplay(new_primary_display)) { 436 LOG(ERROR) << "Invalid or non-existent display is requested:" 437 << new_primary_display.ToString(); 438 return; 439 } 440 441 if (primary_display_id == new_primary_display.id() || 442 root_windows_.size() < 2) { 443 return; 444 } 445 446 aura::RootWindow* non_primary_root = root_windows_[new_primary_display.id()]; 447 LOG_IF(ERROR, !non_primary_root) 448 << "Unknown display is requested in SetPrimaryDisplay: id=" 449 << new_primary_display.id(); 450 if (!non_primary_root) 451 return; 452 453 gfx::Display old_primary_display = GetPrimaryDisplay(); 454 455 // Swap root windows between current and new primary display. 456 aura::RootWindow* primary_root = root_windows_[primary_display_id]; 457 DCHECK(primary_root); 458 DCHECK_NE(primary_root, non_primary_root); 459 460 root_windows_[new_primary_display.id()] = primary_root; 461 internal::GetRootWindowSettings(primary_root)->display_id = 462 new_primary_display.id(); 463 464 root_windows_[old_primary_display.id()] = non_primary_root; 465 internal::GetRootWindowSettings(non_primary_root)->display_id = 466 old_primary_display.id(); 467 468 primary_display_id = new_primary_display.id(); 469 GetDisplayManager()->layout_store()->UpdatePrimaryDisplayId( 470 display_manager->GetCurrentDisplayIdPair(), primary_display_id); 471 472 UpdateWorkAreaOfDisplayNearestWindow( 473 primary_root, old_primary_display.GetWorkAreaInsets()); 474 UpdateWorkAreaOfDisplayNearestWindow( 475 non_primary_root, new_primary_display.GetWorkAreaInsets()); 476 477 // Update the dispay manager with new display info. 478 std::vector<internal::DisplayInfo> display_info_list; 479 display_info_list.push_back(display_manager->GetDisplayInfo( 480 primary_display_id)); 481 display_info_list.push_back(display_manager->GetDisplayInfo( 482 ScreenAsh::GetSecondaryDisplay().id())); 483 GetDisplayManager()->set_force_bounds_changed(true); 484 GetDisplayManager()->UpdateDisplays(display_info_list); 485 GetDisplayManager()->set_force_bounds_changed(false); 486} 487 488void DisplayController::EnsurePointerInDisplays() { 489 // If the mouse is currently on a display in native location, 490 // use the same native location. Otherwise find the display closest 491 // to the current cursor location in screen coordinates. 492 493 gfx::Point point_in_screen = Shell::GetScreen()->GetCursorScreenPoint(); 494 gfx::Point target_location_in_native; 495 int64 closest_distance_squared = -1; 496 internal::DisplayManager* display_manager = GetDisplayManager(); 497 498 aura::RootWindow* dst_root_window = NULL; 499 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) { 500 const gfx::Display& display = display_manager->GetDisplayAt(i); 501 const internal::DisplayInfo display_info = 502 display_manager->GetDisplayInfo(display.id()); 503 aura::RootWindow* root_window = GetRootWindowForDisplayId(display.id()); 504 if (display_info.bounds_in_native().Contains( 505 cursor_location_in_native_coords_for_restore_)) { 506 dst_root_window = root_window; 507 target_location_in_native = cursor_location_in_native_coords_for_restore_; 508 break; 509 } 510 gfx::Point center = display.bounds().CenterPoint(); 511 // Use the distance squared from the center of the dislay. This is not 512 // exactly "closest" display, but good enough to pick one 513 // appropriate (and there are at most two displays). 514 // We don't care about actual distance, only relative to other displays, so 515 // using the LengthSquared() is cheaper than Length(). 516 517 int64 distance_squared = (center - point_in_screen).LengthSquared(); 518 if (closest_distance_squared < 0 || 519 closest_distance_squared > distance_squared) { 520 aura::RootWindow* root_window = GetRootWindowForDisplayId(display.id()); 521 aura::client::ScreenPositionClient* client = 522 aura::client::GetScreenPositionClient(root_window); 523 client->ConvertPointFromScreen(root_window, ¢er); 524 root_window->ConvertPointToNativeScreen(¢er); 525 dst_root_window = root_window; 526 target_location_in_native = center; 527 closest_distance_squared = distance_squared; 528 } 529 } 530 dst_root_window->ConvertPointFromNativeScreen(&target_location_in_native); 531 dst_root_window->MoveCursorTo(target_location_in_native); 532} 533 534bool DisplayController::UpdateWorkAreaOfDisplayNearestWindow( 535 const aura::Window* window, 536 const gfx::Insets& insets) { 537 const aura::RootWindow* root_window = window->GetRootWindow(); 538 int64 id = internal::GetRootWindowSettings(root_window)->display_id; 539 // if id is |kInvaildDisplayID|, it's being deleted. 540 DCHECK(id != gfx::Display::kInvalidDisplayID); 541 return GetDisplayManager()->UpdateWorkAreaOfDisplay(id, insets); 542} 543 544const gfx::Display& DisplayController::GetDisplayNearestWindow( 545 const aura::Window* window) const { 546 if (!window) 547 return GetPrimaryDisplay(); 548 const aura::RootWindow* root_window = window->GetRootWindow(); 549 if (!root_window) 550 return GetPrimaryDisplay(); 551 int64 id = internal::GetRootWindowSettings(root_window)->display_id; 552 // if id is |kInvaildDisplayID|, it's being deleted. 553 DCHECK(id != gfx::Display::kInvalidDisplayID); 554 555 internal::DisplayManager* display_manager = GetDisplayManager(); 556 // RootWindow needs Display to determine its device scale factor. 557 // TODO(oshima): We don't need full display info for mirror 558 // window. Refactor so that RootWindow doesn't use it. 559 if (display_manager->mirrored_display().id() == id) 560 return display_manager->mirrored_display(); 561 562 return display_manager->GetDisplayForId(id); 563} 564 565const gfx::Display& DisplayController::GetDisplayNearestPoint( 566 const gfx::Point& point) const { 567 // Fallback to the primary display if there is no root display containing 568 // the |point|. 569 const gfx::Display& display = 570 GetDisplayManager()->FindDisplayContainingPoint(point); 571 return display.is_valid() ? display : GetPrimaryDisplay(); 572} 573 574const gfx::Display& DisplayController::GetDisplayMatching( 575 const gfx::Rect& rect) const { 576 if (rect.IsEmpty()) 577 return GetDisplayNearestPoint(rect.origin()); 578 579 int max_area = 0; 580 const gfx::Display* matching = NULL; 581 for (size_t i = 0; i < GetDisplayManager()->GetNumDisplays(); ++i) { 582 const gfx::Display& display = GetDisplayManager()->GetDisplayAt(i); 583 gfx::Rect intersect = gfx::IntersectRects(display.bounds(), rect); 584 int area = intersect.width() * intersect.height(); 585 if (area > max_area) { 586 max_area = area; 587 matching = &display; 588 } 589 } 590 // Fallback to the primary display if there is no matching display. 591 return matching ? *matching : GetPrimaryDisplay(); 592} 593 594void DisplayController::OnDisplayBoundsChanged(const gfx::Display& display) { 595 const internal::DisplayInfo& display_info = 596 GetDisplayManager()->GetDisplayInfo(display.id()); 597 DCHECK(!display_info.bounds_in_native().IsEmpty()); 598 aura::RootWindow* root = root_windows_[display.id()]; 599 root->SetHostBounds(display_info.bounds_in_native()); 600 SetDisplayPropertiesOnHostWindow(root, display); 601} 602 603void DisplayController::OnDisplayAdded(const gfx::Display& display) { 604 if (primary_root_window_for_replace_) { 605 DCHECK(root_windows_.empty()); 606 primary_display_id = display.id(); 607 root_windows_[display.id()] = primary_root_window_for_replace_; 608 internal::GetRootWindowSettings(primary_root_window_for_replace_)-> 609 display_id = display.id(); 610 primary_root_window_for_replace_ = NULL; 611 const internal::DisplayInfo& display_info = 612 GetDisplayManager()->GetDisplayInfo(display.id()); 613 root_windows_[display.id()]->SetHostBounds( 614 display_info.bounds_in_native()); 615 } else { 616 if (primary_display_id == gfx::Display::kInvalidDisplayID) 617 primary_display_id = display.id(); 618 DCHECK(!root_windows_.empty()); 619 aura::RootWindow* root = AddRootWindowForDisplay(display); 620 internal::RootWindowController::CreateForSecondaryDisplay(root); 621 } 622} 623 624void DisplayController::OnDisplayRemoved(const gfx::Display& display) { 625 aura::RootWindow* root_to_delete = root_windows_[display.id()]; 626 DCHECK(root_to_delete) << display.ToString(); 627 628 // Display for root window will be deleted when the Primary RootWindow 629 // is deleted by the Shell. 630 root_windows_.erase(display.id()); 631 632 // When the primary root window's display is removed, move the primary 633 // root to the other display. 634 if (primary_display_id == display.id()) { 635 // Temporarily store the primary root window in 636 // |primary_root_window_for_replace_| when replacing the display. 637 if (root_windows_.size() == 0) { 638 primary_display_id = gfx::Display::kInvalidDisplayID; 639 primary_root_window_for_replace_ = root_to_delete; 640 return; 641 } 642 DCHECK_EQ(1U, root_windows_.size()); 643 primary_display_id = ScreenAsh::GetSecondaryDisplay().id(); 644 aura::RootWindow* primary_root = root_to_delete; 645 646 // Delete the other root instead. 647 root_to_delete = root_windows_[primary_display_id]; 648 internal::GetRootWindowSettings(root_to_delete)->display_id = display.id(); 649 650 // Setup primary root. 651 root_windows_[primary_display_id] = primary_root; 652 internal::GetRootWindowSettings(primary_root)->display_id = 653 primary_display_id; 654 655 OnDisplayBoundsChanged( 656 GetDisplayManager()->GetDisplayForId(primary_display_id)); 657 } 658 internal::RootWindowController* controller = 659 internal::GetRootWindowController(root_to_delete); 660 DCHECK(controller); 661 controller->MoveWindowsTo(GetPrimaryRootWindow()); 662 // Delete most of root window related objects, but don't delete 663 // root window itself yet because the stack may be using it. 664 controller->Shutdown(); 665 base::MessageLoop::current()->DeleteSoon(FROM_HERE, controller); 666} 667 668void DisplayController::OnRootWindowHostResized(const aura::RootWindow* root) { 669 internal::DisplayManager* display_manager = GetDisplayManager(); 670 gfx::Display display = GetDisplayNearestWindow(root); 671 if (display_manager->UpdateDisplayBounds( 672 display.id(), 673 gfx::Rect(root->GetHostOrigin(), root->GetHostSize()))) { 674 mirror_window_controller_->UpdateWindow(); 675 } 676} 677 678void DisplayController::CreateOrUpdateMirrorWindow( 679 const internal::DisplayInfo& info) { 680 mirror_window_controller_->UpdateWindow(info); 681} 682 683void DisplayController::CloseMirrorWindow() { 684 mirror_window_controller_->Close(); 685} 686 687void DisplayController::PreDisplayConfigurationChange(bool display_removed) { 688 FOR_EACH_OBSERVER(Observer, observers_, OnDisplayConfigurationChanging()); 689 focus_activation_store_->Store(display_removed); 690 691 gfx::Point point_in_screen = Shell::GetScreen()->GetCursorScreenPoint(); 692 gfx::Display display = 693 Shell::GetScreen()->GetDisplayNearestPoint(point_in_screen); 694 aura::RootWindow* root_window = GetRootWindowForDisplayId(display.id()); 695 696 aura::client::ScreenPositionClient* client = 697 aura::client::GetScreenPositionClient(root_window); 698 client->ConvertPointFromScreen(root_window, &point_in_screen); 699 root_window->ConvertPointToNativeScreen(&point_in_screen); 700 cursor_location_in_native_coords_for_restore_ = point_in_screen; 701} 702 703void DisplayController::PostDisplayConfigurationChange() { 704 if (limiter_) 705 limiter_->SetThrottleTimeout(kAfterDisplayChangeThrottleTimeoutMs); 706 707 focus_activation_store_->Restore(); 708 709 internal::DisplayManager* display_manager = GetDisplayManager(); 710 internal::DisplayLayoutStore* layout_store = display_manager->layout_store(); 711 if (display_manager->num_connected_displays() > 1) { 712 DisplayIdPair pair = display_manager->GetCurrentDisplayIdPair(); 713 layout_store->UpdateMirrorStatus(pair, display_manager->IsMirrored()); 714 DisplayLayout layout = layout_store->GetRegisteredDisplayLayout(pair); 715 716 if (Shell::GetScreen()->GetNumDisplays() > 1 ) { 717 int64 primary_id = layout.primary_id; 718 SetPrimaryDisplayId( 719 primary_id == gfx::Display::kInvalidDisplayID ? 720 pair.first : primary_id); 721 // Update the primary_id in case the above call is 722 // ignored. Happens when a) default layout's primary id 723 // doesn't exist, or b) the primary_id has already been 724 // set to the same and didn't update it. 725 layout_store->UpdatePrimaryDisplayId(pair, GetPrimaryDisplay().id()); 726 } 727 } 728 FOR_EACH_OBSERVER(Observer, observers_, OnDisplayConfigurationChanged()); 729 UpdateHostWindowNames(); 730 EnsurePointerInDisplays(); 731} 732 733aura::RootWindow* DisplayController::AddRootWindowForDisplay( 734 const gfx::Display& display) { 735 static int root_window_count = 0; 736 const internal::DisplayInfo& display_info = 737 GetDisplayManager()->GetDisplayInfo(display.id()); 738 const gfx::Rect& bounds_in_native = display_info.bounds_in_native(); 739 aura::RootWindow::CreateParams params(bounds_in_native); 740 params.host = Shell::GetInstance()->root_window_host_factory()-> 741 CreateRootWindowHost(bounds_in_native); 742 aura::RootWindow* root_window = new aura::RootWindow(params); 743 root_window->SetName( 744 base::StringPrintf("RootWindow-%d", root_window_count++)); 745 root_window->compositor()->SetBackgroundColor(SK_ColorBLACK); 746 // No need to remove RootWindowObserver because 747 // the DisplayController object outlives RootWindow objects. 748 root_window->AddRootWindowObserver(this); 749 internal::InitRootWindowSettings(root_window)->display_id = display.id(); 750 root_window->Init(); 751 752 root_windows_[display.id()] = root_window; 753 SetDisplayPropertiesOnHostWindow(root_window, display); 754 755#if defined(OS_CHROMEOS) 756 static bool force_constrain_pointer_to_root = 757 CommandLine::ForCurrentProcess()->HasSwitch( 758 switches::kAshConstrainPointerToRoot); 759 if (base::SysInfo::IsRunningOnChromeOS() || force_constrain_pointer_to_root) 760 root_window->ConfineCursorToWindow(); 761#endif 762 return root_window; 763} 764 765void DisplayController::OnFadeOutForSwapDisplayFinished() { 766#if defined(OS_CHROMEOS) && defined(USE_X11) 767 SetPrimaryDisplay(ScreenAsh::GetSecondaryDisplay()); 768 Shell::GetInstance()->output_configurator_animation()->StartFadeInAnimation(); 769#endif 770} 771 772void DisplayController::UpdateHostWindowNames() { 773#if defined(USE_X11) 774 // crbug.com/120229 - set the window title for the primary dislpay 775 // to "aura_root_0" so gtalk can find the primary root window to broadcast. 776 // TODO(jhorwich) Remove this once Chrome supports window-based broadcasting. 777 aura::RootWindow* primary = Shell::GetPrimaryRootWindow(); 778 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); 779 for (size_t i = 0; i < root_windows.size(); ++i) { 780 std::string name = 781 root_windows[i] == primary ? "aura_root_0" : "aura_root_x"; 782 gfx::AcceleratedWidget xwindow = root_windows[i]->GetAcceleratedWidget(); 783 XStoreName(gfx::GetXDisplay(), xwindow, name.c_str()); 784 } 785#endif 786} 787 788} // namespace ash 789