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