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