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