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