display_manager.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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_manager.h" 6 7#include <cmath> 8#include <set> 9#include <string> 10#include <vector> 11 12#include "ash/ash_switches.h" 13#include "ash/display/display_controller.h" 14#include "ash/display/mirror_window_controller.h" 15#include "ash/screen_ash.h" 16#include "ash/shell.h" 17#include "base/auto_reset.h" 18#include "base/command_line.h" 19#include "base/logging.h" 20#include "base/stl_util.h" 21#include "base/strings/string_number_conversions.h" 22#include "base/strings/string_split.h" 23#include "base/strings/stringprintf.h" 24#include "base/strings/utf_string_conversions.h" 25#include "grit/ash_strings.h" 26#include "ui/aura/client/screen_position_client.h" 27#include "ui/aura/env.h" 28#include "ui/aura/root_window.h" 29#include "ui/aura/root_window_host.h" 30#include "ui/aura/window_property.h" 31#include "ui/base/l10n/l10n_util.h" 32#include "ui/gfx/display.h" 33#include "ui/gfx/rect.h" 34#include "ui/gfx/screen.h" 35#include "ui/gfx/size_conversions.h" 36 37#if defined(USE_X11) 38#include "ui/base/x/x11_util.h" 39#endif 40 41#if defined(OS_CHROMEOS) 42#include "ash/display/output_configurator_animation.h" 43#include "base/chromeos/chromeos_version.h" 44#include "chromeos/display/output_configurator.h" 45#endif 46 47#if defined(OS_WIN) 48#include "base/win/windows_version.h" 49#include "ui/aura/remote_root_window_host_win.h" 50#endif 51 52DECLARE_WINDOW_PROPERTY_TYPE(int64); 53 54namespace ash { 55namespace internal { 56typedef std::vector<gfx::Display> DisplayList; 57typedef std::vector<DisplayInfo> DisplayInfoList; 58 59namespace { 60 61// The number of pixels to overlap between the primary and secondary displays, 62// in case that the offset value is too large. 63const int kMinimumOverlapForInvalidOffset = 100; 64 65// List of value UI Scale values. Scales for 2x are equivalent to 640, 66// 800, 1024, 1280, 1440, 1600 and 1920 pixel width respectively on 67// 2560 pixel width 2x density display. Please see crbug.com/233375 68// for the full list of resolutions. 69const float kUIScalesFor2x[] = {0.5f, 0.625f, 0.8f, 1.0f, 1.125f, 1.25f, 1.5f}; 70const float kUIScalesFor1280[] = {0.5f, 0.625f, 0.8f, 1.0f, 1.125f }; 71const float kUIScalesFor1366[] = {0.5f, 0.6f, 0.75f, 1.0f, 1.125f }; 72 73struct DisplaySortFunctor { 74 bool operator()(const gfx::Display& a, const gfx::Display& b) { 75 return a.id() < b.id(); 76 } 77}; 78 79struct DisplayInfoSortFunctor { 80 bool operator()(const DisplayInfo& a, const DisplayInfo& b) { 81 return a.id() < b.id(); 82 } 83}; 84 85struct ScaleComparator { 86 ScaleComparator(float s) : scale(s) {} 87 88 bool operator()(float s) const { 89 const float kEpsilon = 0.0001f; 90 return std::abs(scale - s) < kEpsilon; 91 } 92 float scale; 93}; 94 95gfx::Display& GetInvalidDisplay() { 96 static gfx::Display* invalid_display = new gfx::Display(); 97 return *invalid_display; 98} 99 100// Scoped objects used to either create or close the mirror window 101// at specific timing. 102class MirrorWindowCreator { 103 public: 104 explicit MirrorWindowCreator(const DisplayInfo& display_info) 105 : display_info_(display_info) { 106 } 107 108 virtual ~MirrorWindowCreator() { 109 Shell::GetInstance()->mirror_window_controller()-> 110 UpdateWindow(display_info_); 111 } 112 113 private: 114 const DisplayInfo display_info_; 115 DISALLOW_COPY_AND_ASSIGN(MirrorWindowCreator); 116}; 117 118class MirrorWindowCloser { 119 public: 120 MirrorWindowCloser() {} 121 virtual ~MirrorWindowCloser() { 122 Shell::GetInstance()->mirror_window_controller()->Close(); 123 } 124 125 private: 126 DISALLOW_COPY_AND_ASSIGN(MirrorWindowCloser); 127}; 128 129} // namespace 130 131using aura::RootWindow; 132using aura::Window; 133using std::string; 134using std::vector; 135 136DEFINE_WINDOW_PROPERTY_KEY(int64, kDisplayIdKey, 137 gfx::Display::kInvalidDisplayID); 138 139DisplayManager::DisplayManager() 140 : first_display_id_(gfx::Display::kInvalidDisplayID), 141 num_connected_displays_(0), 142 force_bounds_changed_(false), 143 change_display_upon_host_resize_(false), 144 software_mirroring_enabled_(false) { 145#if defined(OS_CHROMEOS) 146 change_display_upon_host_resize_ = !base::chromeos::IsRunningOnChromeOS(); 147#endif 148 Init(); 149} 150 151DisplayManager::~DisplayManager() { 152} 153 154// static 155std::vector<float> DisplayManager::GetScalesForDisplay( 156 const DisplayInfo& info) { 157 std::vector<float> ret; 158 if (info.device_scale_factor() == 2.0f) { 159 ret.assign(kUIScalesFor2x, kUIScalesFor2x + arraysize(kUIScalesFor2x)); 160 return ret; 161 } 162 switch (info.bounds_in_pixel().width()) { 163 case 1280: 164 ret.assign(kUIScalesFor1280, 165 kUIScalesFor1280 + arraysize(kUIScalesFor1280)); 166 break; 167 case 1366: 168 ret.assign(kUIScalesFor1366, 169 kUIScalesFor1366 + arraysize(kUIScalesFor1366)); 170 break; 171 default: 172 ret.assign(kUIScalesFor1280, 173 kUIScalesFor1280 + arraysize(kUIScalesFor1280)); 174#if defined(OS_CHROMEOS) 175 if (base::chromeos::IsRunningOnChromeOS()) 176 NOTREACHED() << "Unknown resolution:" << info.ToString(); 177#endif 178 } 179 return ret; 180} 181 182// static 183float DisplayManager::GetNextUIScale(const DisplayInfo& info, bool up) { 184 float scale = info.ui_scale(); 185 std::vector<float> scales = GetScalesForDisplay(info); 186 for (size_t i = 0; i < scales.size(); ++i) { 187 if (ScaleComparator(scales[i])(scale)) { 188 if (up && i != scales.size() - 1) 189 return scales[i + 1]; 190 if (!up && i != 0) 191 return scales[i - 1]; 192 return scales[i]; 193 } 194 } 195 // Fallback to 1.0f if the |scale| wasn't in the list. 196 return 1.0f; 197} 198 199void DisplayManager::UpdateDisplayBoundsForLayout( 200 const DisplayLayout& layout, 201 const gfx::Display& primary_display, 202 gfx::Display* secondary_display) { 203 DCHECK_EQ("0,0", primary_display.bounds().origin().ToString()); 204 205 const gfx::Rect& primary_bounds = primary_display.bounds(); 206 DisplayController::GetPrimaryDisplay().bounds(); 207 208 const gfx::Rect& secondary_bounds = secondary_display->bounds(); 209 gfx::Point new_secondary_origin = primary_bounds.origin(); 210 211 DisplayLayout::Position position = layout.position; 212 213 // Ignore the offset in case the secondary display doesn't share edges with 214 // the primary display. 215 int offset = layout.offset; 216 if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM) { 217 offset = std::min( 218 offset, primary_bounds.width() - kMinimumOverlapForInvalidOffset); 219 offset = std::max( 220 offset, -secondary_bounds.width() + kMinimumOverlapForInvalidOffset); 221 } else { 222 offset = std::min( 223 offset, primary_bounds.height() - kMinimumOverlapForInvalidOffset); 224 offset = std::max( 225 offset, -secondary_bounds.height() + kMinimumOverlapForInvalidOffset); 226 } 227 switch (position) { 228 case DisplayLayout::TOP: 229 new_secondary_origin.Offset(offset, -secondary_bounds.height()); 230 break; 231 case DisplayLayout::RIGHT: 232 new_secondary_origin.Offset(primary_bounds.width(), offset); 233 break; 234 case DisplayLayout::BOTTOM: 235 new_secondary_origin.Offset(offset, primary_bounds.height()); 236 break; 237 case DisplayLayout::LEFT: 238 new_secondary_origin.Offset(-secondary_bounds.width(), offset); 239 break; 240 } 241 gfx::Insets insets = secondary_display->GetWorkAreaInsets(); 242 secondary_display->set_bounds( 243 gfx::Rect(new_secondary_origin, secondary_bounds.size())); 244 secondary_display->UpdateWorkAreaFromInsets(insets); 245} 246 247bool DisplayManager::IsActiveDisplay(const gfx::Display& display) const { 248 for (DisplayList::const_iterator iter = displays_.begin(); 249 iter != displays_.end(); ++iter) { 250 if ((*iter).id() == display.id()) 251 return true; 252 } 253 return false; 254} 255 256bool DisplayManager::HasInternalDisplay() const { 257 return gfx::Display::InternalDisplayId() != gfx::Display::kInvalidDisplayID; 258} 259 260bool DisplayManager::IsInternalDisplayId(int64 id) const { 261 return gfx::Display::InternalDisplayId() == id; 262} 263 264bool DisplayManager::UpdateWorkAreaOfDisplayNearestWindow( 265 const aura::Window* window, 266 const gfx::Insets& insets) { 267 const RootWindow* root = window->GetRootWindow(); 268 gfx::Display& display = FindDisplayForRootWindow(root); 269 gfx::Rect old_work_area = display.work_area(); 270 display.UpdateWorkAreaFromInsets(insets); 271 return old_work_area != display.work_area(); 272} 273 274const gfx::Display& DisplayManager::GetDisplayForId(int64 id) const { 275 return const_cast<DisplayManager*>(this)->FindDisplayForId(id); 276} 277 278const gfx::Display& DisplayManager::FindDisplayContainingPoint( 279 const gfx::Point& point_in_screen) const { 280 for (DisplayList::const_iterator iter = displays_.begin(); 281 iter != displays_.end(); ++iter) { 282 const gfx::Display& display = *iter; 283 if (display.bounds().Contains(point_in_screen)) 284 return display; 285 } 286 return GetInvalidDisplay(); 287} 288 289void DisplayManager::SetOverscanInsets(int64 display_id, 290 const gfx::Insets& insets_in_dip) { 291 display_info_[display_id].SetOverscanInsets(insets_in_dip); 292 DisplayInfoList display_info_list; 293 for (DisplayList::const_iterator iter = displays_.begin(); 294 iter != displays_.end(); ++iter) { 295 display_info_list.push_back(GetDisplayInfo(iter->id())); 296 } 297 AddMirrorDisplayInfoIfAny(&display_info_list); 298 UpdateDisplays(display_info_list); 299} 300 301void DisplayManager::SetDisplayRotation(int64 display_id, 302 gfx::Display::Rotation rotation) { 303 if (!IsDisplayRotationEnabled()) 304 return; 305 DisplayInfoList display_info_list; 306 for (DisplayList::const_iterator iter = displays_.begin(); 307 iter != displays_.end(); ++iter) { 308 DisplayInfo info = GetDisplayInfo(iter->id()); 309 if (info.id() == display_id) { 310 if (info.rotation() == rotation) 311 return; 312 info.set_rotation(rotation); 313 } 314 display_info_list.push_back(info); 315 } 316 AddMirrorDisplayInfoIfAny(&display_info_list); 317 UpdateDisplays(display_info_list); 318} 319 320void DisplayManager::SetDisplayUIScale(int64 display_id, 321 float ui_scale) { 322 if (!IsDisplayUIScalingEnabled() || 323 gfx::Display::InternalDisplayId() != display_id) { 324 return; 325 } 326 327 DisplayInfoList display_info_list; 328 for (DisplayList::const_iterator iter = displays_.begin(); 329 iter != displays_.end(); ++iter) { 330 DisplayInfo info = GetDisplayInfo(iter->id()); 331 if (info.id() == display_id) { 332 if (info.ui_scale() == ui_scale) 333 return; 334 std::vector<float> scales = GetScalesForDisplay(info); 335 ScaleComparator comparator(ui_scale); 336 if (std::find_if(scales.begin(), scales.end(), comparator) == 337 scales.end()) { 338 return; 339 } 340 info.set_ui_scale(ui_scale); 341 } 342 display_info_list.push_back(info); 343 } 344 AddMirrorDisplayInfoIfAny(&display_info_list); 345 UpdateDisplays(display_info_list); 346} 347 348void DisplayManager::RegisterDisplayProperty( 349 int64 display_id, 350 gfx::Display::Rotation rotation, 351 float ui_scale, 352 const gfx::Insets* overscan_insets) { 353 if (display_info_.find(display_id) == display_info_.end()) { 354 display_info_[display_id] = 355 DisplayInfo(display_id, std::string(""), false); 356 } 357 358 display_info_[display_id].set_rotation(rotation); 359 // Just in case the preference file was corrupted. 360 if (0.5f <= ui_scale && ui_scale <= 2.0f) 361 display_info_[display_id].set_ui_scale(ui_scale); 362 if (overscan_insets) 363 display_info_[display_id].SetOverscanInsets(*overscan_insets); 364} 365 366bool DisplayManager::IsDisplayRotationEnabled() const { 367 static bool enabled = !CommandLine::ForCurrentProcess()-> 368 HasSwitch(switches::kAshDisableDisplayRotation); 369 return enabled; 370} 371 372bool DisplayManager::IsDisplayUIScalingEnabled() const { 373 static bool enabled = !CommandLine::ForCurrentProcess()-> 374 HasSwitch(switches::kAshDisableUIScaling); 375 if (!enabled) 376 return false; 377 return GetDisplayIdForUIScaling() != gfx::Display::kInvalidDisplayID; 378} 379 380gfx::Insets DisplayManager::GetOverscanInsets(int64 display_id) const { 381 std::map<int64, DisplayInfo>::const_iterator it = 382 display_info_.find(display_id); 383 return (it != display_info_.end()) ? 384 it->second.overscan_insets_in_dip() : gfx::Insets(); 385} 386 387void DisplayManager::OnNativeDisplaysChanged( 388 const std::vector<DisplayInfo>& updated_displays) { 389 if (updated_displays.empty()) { 390 // Don't update the displays when all displays are disconnected. 391 // This happens when: 392 // - the device is idle and powerd requested to turn off all displays. 393 // - the device is suspended. (kernel turns off all displays) 394 // - the internal display's brightness is set to 0 and no external 395 // display is connected. 396 // - the internal display's brightness is 0 and external display is 397 // disconnected. 398 // The display will be updated when one of displays is turned on, and the 399 // display list will be updated correctly. 400 return; 401 } 402 first_display_id_ = updated_displays[0].id(); 403 std::set<int> y_coords; 404 if (updated_displays.size() == 1) { 405 VLOG(1) << "OnNativeDisplaysChanged(1):" << updated_displays[0].ToString(); 406 } else { 407 VLOG(1) << "OnNativeDisplaysChanged(" << updated_displays.size() 408 << ") [0]=" << updated_displays[0].ToString() 409 << ", [1]=" << updated_displays[1].ToString(); 410 } 411 412 bool internal_display_connected = false; 413 num_connected_displays_ = updated_displays.size(); 414 mirrored_display_ = gfx::Display(); 415 DisplayInfoList new_display_info_list; 416 for (DisplayInfoList::const_iterator iter = updated_displays.begin(); 417 iter != updated_displays.end(); 418 ++iter) { 419 if (!internal_display_connected) 420 internal_display_connected = IsInternalDisplayId(iter->id()); 421 // Mirrored monitors have the same y coordinates. 422 int y = iter->bounds_in_pixel().y(); 423 if (y_coords.find(y) != y_coords.end()) { 424 InsertAndUpdateDisplayInfo(*iter); 425 mirrored_display_ = CreateDisplayFromDisplayInfoById(iter->id()); 426 } else { 427 y_coords.insert(y); 428 new_display_info_list.push_back(*iter); 429 } 430 } 431 if (HasInternalDisplay() && 432 !internal_display_connected && 433 display_info_.find(gfx::Display::InternalDisplayId()) == 434 display_info_.end()) { 435 DisplayInfo internal_display_info( 436 gfx::Display::InternalDisplayId(), 437 l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME), 438 false /*Internal display must not have overscan */); 439 internal_display_info.SetBounds(gfx::Rect(0, 0, 800, 600)); 440 display_info_[gfx::Display::InternalDisplayId()] = internal_display_info; 441 } 442 UpdateDisplays(new_display_info_list); 443} 444 445void DisplayManager::UpdateDisplays() { 446 DisplayInfoList display_info_list; 447 for (DisplayList::const_iterator iter = displays_.begin(); 448 iter != displays_.end(); ++iter) { 449 display_info_list.push_back(GetDisplayInfo(iter->id())); 450 } 451 AddMirrorDisplayInfoIfAny(&display_info_list); 452 UpdateDisplays(display_info_list); 453} 454 455void DisplayManager::UpdateDisplays( 456 const std::vector<DisplayInfo>& updated_display_info_list) { 457#if defined(OS_WIN) 458 if (base::win::GetVersion() >= base::win::VERSION_WIN8) { 459 DCHECK_EQ(1u, updated_display_info_list.size()) << 460 "Multiple display test does not work on Win8 bots. Please " 461 "skip (don't disable) the test using SupportsMultipleDisplays()"; 462 } 463#endif 464 465 DisplayInfoList new_display_info_list = updated_display_info_list; 466 std::sort(displays_.begin(), displays_.end(), DisplaySortFunctor()); 467 std::sort(new_display_info_list.begin(), 468 new_display_info_list.end(), 469 DisplayInfoSortFunctor()); 470 DisplayList removed_displays; 471 std::vector<size_t> changed_display_indices; 472 std::vector<size_t> added_display_indices; 473 474 DisplayList::iterator curr_iter = displays_.begin(); 475 DisplayInfoList::const_iterator new_info_iter = new_display_info_list.begin(); 476 477 DisplayList new_displays; 478 bool update_mouse_location = false; 479 480 scoped_ptr<MirrorWindowCreator> mirror_window_creater; 481 482 // Use the internal display or 1st as the mirror source, then scale 483 // the root window so that it matches the external display's 484 // resolution. This is necessary in order for scaling to work while 485 // mirrored. 486 int64 mirrored_display_id = gfx::Display::kInvalidDisplayID; 487 if (software_mirroring_enabled_ && new_display_info_list.size() == 2) 488 mirrored_display_id = new_display_info_list[1].id(); 489 490 while (curr_iter != displays_.end() || 491 new_info_iter != new_display_info_list.end()) { 492 if (new_info_iter != new_display_info_list.end() && 493 mirrored_display_id == new_info_iter->id()) { 494 DisplayInfo info = *new_info_iter; 495 info.SetOverscanInsets(gfx::Insets()); 496 InsertAndUpdateDisplayInfo(info); 497 498 mirrored_display_ = CreateDisplayFromDisplayInfoById(new_info_iter->id()); 499 mirror_window_creater.reset( 500 new MirrorWindowCreator(display_info_[new_info_iter->id()])); 501 ++new_info_iter; 502 // Remove existing external dispaly if it is going to be mirrored. 503 if (curr_iter != displays_.end() && 504 curr_iter->id() == mirrored_display_id) { 505 removed_displays.push_back(*curr_iter); 506 ++curr_iter; 507 } 508 update_mouse_location = true; 509 continue; 510 } 511 512 if (curr_iter == displays_.end()) { 513 // more displays in new list. 514 added_display_indices.push_back(new_displays.size()); 515 InsertAndUpdateDisplayInfo(*new_info_iter); 516 new_displays.push_back( 517 CreateDisplayFromDisplayInfoById(new_info_iter->id())); 518 ++new_info_iter; 519 } else if (new_info_iter == new_display_info_list.end()) { 520 // more displays in current list. 521 removed_displays.push_back(*curr_iter); 522 ++curr_iter; 523 update_mouse_location = true; 524 } else if (curr_iter->id() == new_info_iter->id()) { 525 const gfx::Display& current_display = *curr_iter; 526 // Copy the info because |CreateDisplayFromInfo| updates the instance. 527 const DisplayInfo current_display_info = 528 GetDisplayInfo(current_display.id()); 529 InsertAndUpdateDisplayInfo(*new_info_iter); 530 gfx::Display new_display = 531 CreateDisplayFromDisplayInfoById(new_info_iter->id()); 532 const DisplayInfo& new_display_info = GetDisplayInfo(new_display.id()); 533 534 bool host_window_bounds_changed = 535 current_display_info.bounds_in_pixel() != 536 new_display_info.bounds_in_pixel(); 537 538 if (force_bounds_changed_ || 539 host_window_bounds_changed || 540 (current_display.device_scale_factor() != 541 new_display.device_scale_factor()) || 542 (current_display_info.size_in_pixel() != 543 new_display.GetSizeInPixel()) || 544 (current_display.rotation() != new_display.rotation())) { 545 546 // Don't update mouse location if the display size has 547 // changed due to rotation or zooming. 548 if (host_window_bounds_changed) 549 update_mouse_location = true; 550 551 changed_display_indices.push_back(new_displays.size()); 552 } 553 554 new_display.UpdateWorkAreaFromInsets(current_display.GetWorkAreaInsets()); 555 new_displays.push_back(new_display); 556 ++curr_iter; 557 ++new_info_iter; 558 } else if (curr_iter->id() < new_info_iter->id()) { 559 // more displays in current list between ids, which means it is deleted. 560 removed_displays.push_back(*curr_iter); 561 ++curr_iter; 562 update_mouse_location = true; 563 } else { 564 // more displays in new list between ids, which means it is added. 565 added_display_indices.push_back(new_displays.size()); 566 InsertAndUpdateDisplayInfo(*new_info_iter); 567 new_displays.push_back( 568 CreateDisplayFromDisplayInfoById(new_info_iter->id())); 569 ++new_info_iter; 570 } 571 } 572 573 scoped_ptr<MirrorWindowCloser> mirror_window_closer; 574 // Try to close mirror window unless mirror window is necessary. 575 if (!mirror_window_creater.get()) 576 mirror_window_closer.reset(new MirrorWindowCloser); 577 578 // Do not update |displays_| if there's nothing to be updated. Without this, 579 // it will not update the display layout, which causes the bug 580 // http://crbug.com/155948. 581 if (changed_display_indices.empty() && added_display_indices.empty() && 582 removed_displays.empty()) { 583 return; 584 } 585 586 DisplayController* display_controller = 587 Shell::GetInstance()->display_controller(); 588 gfx::Point mouse_location_in_native; 589 display_controller->NotifyDisplayConfigurationChanging(); 590 mouse_location_in_native = display_controller->GetNativeMouseCursorLocation(); 591 592 size_t updated_index; 593 if (UpdateSecondaryDisplayBoundsForLayout(&new_displays, &updated_index) && 594 std::find(added_display_indices.begin(), 595 added_display_indices.end(), 596 updated_index) == added_display_indices.end() && 597 std::find(changed_display_indices.begin(), 598 changed_display_indices.end(), 599 updated_index) == changed_display_indices.end()) { 600 changed_display_indices.push_back(updated_index); 601 } 602 603 displays_ = new_displays; 604 605 base::AutoReset<bool> resetter(&change_display_upon_host_resize_, false); 606 607 // Temporarily add displays to be removed because display object 608 // being removed are accessed during shutting down the root. 609 displays_.insert(displays_.end(), removed_displays.begin(), 610 removed_displays.end()); 611 612 for (DisplayList::const_reverse_iterator iter = removed_displays.rbegin(); 613 iter != removed_displays.rend(); ++iter) { 614 Shell::GetInstance()->screen()->NotifyDisplayRemoved(displays_.back()); 615 displays_.pop_back(); 616 } 617 // Close the mirror window here to avoid creating two compositor on 618 // one display. 619 mirror_window_closer.reset(); 620 for (std::vector<size_t>::iterator iter = added_display_indices.begin(); 621 iter != added_display_indices.end(); ++iter) { 622 Shell::GetInstance()->screen()->NotifyDisplayAdded(displays_[*iter]); 623 } 624 // Create the mirror window after all displays are added so that 625 // it can mirror the display newly added. This can happen when switching 626 // from dock mode to software mirror mode. 627 mirror_window_creater.reset(); 628 for (std::vector<size_t>::iterator iter = changed_display_indices.begin(); 629 iter != changed_display_indices.end(); ++iter) { 630 Shell::GetInstance()->screen()->NotifyBoundsChanged(displays_[*iter]); 631 } 632 display_controller->NotifyDisplayConfigurationChanged(); 633 if (update_mouse_location) 634 display_controller->EnsurePointerInDisplays(); 635 else 636 display_controller->UpdateMouseCursor(mouse_location_in_native); 637 638#if defined(USE_X11) && defined(OS_CHROMEOS) 639 if (!changed_display_indices.empty() && base::chromeos::IsRunningOnChromeOS()) 640 ui::ClearX11DefaultRootWindow(); 641#endif 642} 643 644gfx::Display* DisplayManager::GetDisplayAt(size_t index) { 645 return index < displays_.size() ? &displays_[index] : NULL; 646} 647 648const gfx::Display* DisplayManager::GetPrimaryDisplayCandidate() const { 649 const gfx::Display* primary_candidate = &displays_[0]; 650#if defined(OS_CHROMEOS) 651 if (base::chromeos::IsRunningOnChromeOS()) { 652 // On ChromeOS device, root windows are stacked vertically, and 653 // default primary is the one on top. 654 int count = GetNumDisplays(); 655 int y = GetDisplayInfo(primary_candidate->id()).bounds_in_pixel().y(); 656 for (int i = 1; i < count; ++i) { 657 const gfx::Display* display = &displays_[i]; 658 const DisplayInfo& display_info = GetDisplayInfo(display->id()); 659 if (display->IsInternal()) { 660 primary_candidate = display; 661 break; 662 } else if (display_info.bounds_in_pixel().y() < y) { 663 primary_candidate = display; 664 y = display_info.bounds_in_pixel().y(); 665 } 666 } 667 } 668#endif 669 return primary_candidate; 670} 671 672size_t DisplayManager::GetNumDisplays() const { 673 return displays_.size(); 674} 675 676bool DisplayManager::IsMirrored() const { 677 return mirrored_display_.id() != gfx::Display::kInvalidDisplayID; 678} 679 680const gfx::Display& DisplayManager::GetDisplayNearestWindow( 681 const Window* window) const { 682 if (!window) 683 return DisplayController::GetPrimaryDisplay(); 684 const RootWindow* root = window->GetRootWindow(); 685 DisplayManager* manager = const_cast<DisplayManager*>(this); 686 return root ? 687 manager->FindDisplayForRootWindow(root) : 688 DisplayController::GetPrimaryDisplay(); 689} 690 691const gfx::Display& DisplayManager::GetDisplayNearestPoint( 692 const gfx::Point& point) const { 693 // Fallback to the primary display if there is no root display containing 694 // the |point|. 695 const gfx::Display& display = FindDisplayContainingPoint(point); 696 return display.is_valid() ? display : DisplayController::GetPrimaryDisplay(); 697} 698 699const gfx::Display& DisplayManager::GetDisplayMatching( 700 const gfx::Rect& rect) const { 701 if (rect.IsEmpty()) 702 return GetDisplayNearestPoint(rect.origin()); 703 704 int max = 0; 705 const gfx::Display* matching = 0; 706 for (std::vector<gfx::Display>::const_iterator iter = displays_.begin(); 707 iter != displays_.end(); ++iter) { 708 const gfx::Display& display = *iter; 709 gfx::Rect intersect = gfx::IntersectRects(display.bounds(), rect); 710 int area = intersect.width() * intersect.height(); 711 if (area > max) { 712 max = area; 713 matching = &(*iter); 714 } 715 } 716 // Fallback to the primary display if there is no matching display. 717 return matching ? *matching : DisplayController::GetPrimaryDisplay(); 718} 719 720const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const { 721 std::map<int64, DisplayInfo>::const_iterator iter = 722 display_info_.find(display_id); 723 CHECK(iter != display_info_.end()) << display_id; 724 return iter->second; 725} 726 727std::string DisplayManager::GetDisplayNameForId(int64 id) { 728 if (id == gfx::Display::kInvalidDisplayID) 729 return l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME); 730 731 std::map<int64, DisplayInfo>::const_iterator iter = display_info_.find(id); 732 if (iter != display_info_.end() && !iter->second.name().empty()) 733 return iter->second.name(); 734 735 return base::StringPrintf("Display %d", static_cast<int>(id)); 736} 737 738int64 DisplayManager::GetDisplayIdForUIScaling() const { 739 // UI Scaling is effective only on internal display. 740 int64 display_id = gfx::Display::InternalDisplayId(); 741#if defined(OS_WIN) 742 display_id = first_display_id(); 743#endif 744 return display_id; 745} 746 747void DisplayManager::SetMirrorMode(bool mirrored) { 748 if (num_connected_displays() <= 1) 749 return; 750 751#if defined(OS_CHROMEOS) 752 if (base::chromeos::IsRunningOnChromeOS()) { 753 chromeos::OutputState new_state = mirrored ? 754 chromeos::STATE_DUAL_MIRROR : chromeos::STATE_DUAL_EXTENDED; 755 Shell::GetInstance()->output_configurator()->SetDisplayMode(new_state); 756 return; 757 } 758#endif 759 SetSoftwareMirroring(mirrored); 760 DisplayInfoList display_info_list; 761 int count = 0; 762 for (std::map<int64, DisplayInfo>::const_iterator iter = 763 display_info_.begin(); 764 count < 2; ++iter, ++count) { 765 display_info_list.push_back(GetDisplayInfo(iter->second.id())); 766 } 767 UpdateDisplays(display_info_list); 768#if defined(OS_CHROMEOS) 769 if (Shell::GetInstance()->output_configurator_animation()) { 770 Shell::GetInstance()->output_configurator_animation()-> 771 StartFadeInAnimation(); 772 } 773#endif 774} 775 776void DisplayManager::AddRemoveDisplay() { 777 DCHECK(!displays_.empty()); 778 std::vector<DisplayInfo> new_display_info_list; 779 new_display_info_list.push_back( 780 GetDisplayInfo(DisplayController::GetPrimaryDisplay().id())); 781 // Add if there is only one display connected. 782 if (num_connected_displays() == 1) { 783 // Layout the 2nd display below the primary as with the real device. 784 aura::RootWindow* primary = Shell::GetPrimaryRootWindow(); 785 gfx::Rect host_bounds = 786 gfx::Rect(primary->GetHostOrigin(), primary->GetHostSize()); 787 new_display_info_list.push_back(DisplayInfo::CreateFromSpec( 788 base::StringPrintf( 789 "%d+%d-500x400", host_bounds.x(), host_bounds.bottom()))); 790 } 791 num_connected_displays_ = new_display_info_list.size(); 792 mirrored_display_ = gfx::Display(); 793 UpdateDisplays(new_display_info_list); 794} 795 796void DisplayManager::ToggleDisplayScaleFactor() { 797 DCHECK(!displays_.empty()); 798 std::vector<DisplayInfo> new_display_info_list; 799 for (DisplayList::const_iterator iter = displays_.begin(); 800 iter != displays_.end(); ++iter) { 801 DisplayInfo display_info = GetDisplayInfo(iter->id()); 802 display_info.set_device_scale_factor( 803 display_info.device_scale_factor() == 1.0f ? 2.0f : 1.0f); 804 new_display_info_list.push_back(display_info); 805 } 806 AddMirrorDisplayInfoIfAny(&new_display_info_list); 807 UpdateDisplays(new_display_info_list); 808} 809 810void DisplayManager::OnRootWindowHostResized(const aura::RootWindow* root) { 811 if (change_display_upon_host_resize_) { 812 gfx::Display& display = FindDisplayForRootWindow(root); 813 gfx::Size old_display_size_in_pixel = display.GetSizeInPixel(); 814 display_info_[display.id()].SetBounds( 815 gfx::Rect(root->GetHostOrigin(), root->GetHostSize())); 816 // It's tricky to support resizing mirror window on desktop. 817 if (software_mirroring_enabled_ && mirrored_display_.id() == display.id()) 818 return; 819 display.SetSize(display_info_[display.id()].size_in_pixel()); 820 Shell::GetInstance()->screen()->NotifyBoundsChanged(display); 821 Shell::GetInstance()->mirror_window_controller()->UpdateWindow(); 822 } 823} 824 825void DisplayManager::SetSoftwareMirroring(bool enabled) { 826 software_mirroring_enabled_ = enabled; 827 mirrored_display_ = gfx::Display(); 828} 829 830void DisplayManager::Init() { 831 // TODO(oshima): Move this logic to DisplayChangeObserver. 832 const string size_str = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 833 switches::kAshHostWindowBounds); 834 vector<string> parts; 835 base::SplitString(size_str, ',', &parts); 836 for (vector<string>::const_iterator iter = parts.begin(); 837 iter != parts.end(); ++iter) { 838 AddDisplayFromSpec(*iter); 839 } 840 if (displays_.empty()) 841 AddDisplayFromSpec(std::string() /* default */); 842 first_display_id_ = displays_[0].id(); 843 CommandLine* command_line = CommandLine::ForCurrentProcess(); 844 if (command_line->HasSwitch(switches::kAshUseFirstDisplayAsInternal)) 845 gfx::Display::SetInternalDisplayId(first_display_id_); 846 num_connected_displays_ = displays_.size(); 847} 848 849gfx::Display& DisplayManager::FindDisplayForRootWindow( 850 const aura::RootWindow* root_window) { 851 int64 id = root_window->GetProperty(kDisplayIdKey); 852 // RootWindow needs Display to determine it's device scale factor. 853 // TODO(oshima): We don't need full display info for mirror 854 // window. Refactor so that RootWindow doesn't use it. 855 if (mirrored_display_.id() == id) 856 return mirrored_display_; 857 858 // if id is |kInvaildDisplayID|, it's being deleted. 859 DCHECK(id != gfx::Display::kInvalidDisplayID); 860 gfx::Display& display = FindDisplayForId(id); 861 DCHECK(display.is_valid()); 862 return display; 863} 864 865gfx::Display& DisplayManager::FindDisplayForId(int64 id) { 866 for (DisplayList::iterator iter = displays_.begin(); 867 iter != displays_.end(); ++iter) { 868 if ((*iter).id() == id) 869 return *iter; 870 } 871 DLOG(WARNING) << "Could not find display:" << id; 872 return GetInvalidDisplay(); 873} 874 875void DisplayManager::AddMirrorDisplayInfoIfAny( 876 std::vector<DisplayInfo>* display_info_list) { 877 if (software_mirroring_enabled_ && mirrored_display_.is_valid()) 878 display_info_list->push_back(GetDisplayInfo(mirrored_display_.id())); 879} 880 881void DisplayManager::AddDisplayFromSpec(const std::string& spec) { 882 DisplayInfo display_info = DisplayInfo::CreateFromSpec(spec); 883 InsertAndUpdateDisplayInfo(display_info); 884 gfx::Display display = CreateDisplayFromDisplayInfoById(display_info.id()); 885 displays_.push_back(display); 886} 887 888void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo& new_info) { 889 std::map<int64, DisplayInfo>::iterator info = 890 display_info_.find(new_info.id()); 891 if (info != display_info_.end()) 892 info->second.Copy(new_info); 893 else { 894 display_info_[new_info.id()] = new_info; 895 display_info_[new_info.id()].set_native(false); 896 } 897 display_info_[new_info.id()].UpdateDisplaySize(); 898} 899 900gfx::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64 id) { 901 DCHECK(display_info_.find(id) != display_info_.end()); 902 const DisplayInfo& display_info = display_info_[id]; 903 904 gfx::Display new_display(display_info.id()); 905 gfx::Rect bounds_in_pixel(display_info.size_in_pixel()); 906 907 // Simply set the origin to (0,0). The primary display's origin is 908 // always (0,0) and the secondary display's bounds will be updated 909 // in |UpdateSecondaryDisplayBoundsForLayout| called in |UpdateDisplay|. 910 new_display.SetScaleAndBounds( 911 display_info.device_scale_factor(), gfx::Rect(bounds_in_pixel.size())); 912 new_display.set_rotation(display_info.rotation()); 913 return new_display; 914} 915 916bool DisplayManager::UpdateSecondaryDisplayBoundsForLayout( 917 DisplayList* displays, 918 size_t* updated_index) const { 919 if (displays->size() != 2U) 920 return false; 921 922 DisplayController* controller = Shell::GetInstance()->display_controller(); 923 int64 id_at_zero = displays->at(0).id(); 924 DisplayIdPair pair = 925 (id_at_zero == first_display_id_ || 926 id_at_zero == gfx::Display::InternalDisplayId()) ? 927 std::make_pair(id_at_zero, displays->at(1).id()) : 928 std::make_pair(displays->at(1).id(), id_at_zero) ; 929 DisplayLayout layout = 930 controller->ComputeDisplayLayoutForDisplayIdPair(pair); 931 932 // Ignore if a user has a old format (should be extremely rare) 933 // and this will be replaced with DCHECK. 934 if (layout.primary_id != gfx::Display::kInvalidDisplayID) { 935 size_t primary_index, secondary_index; 936 if (displays->at(0).id() == layout.primary_id) { 937 primary_index = 0; 938 secondary_index = 1; 939 } else { 940 primary_index = 1; 941 secondary_index = 0; 942 } 943 gfx::Rect bounds = 944 GetDisplayForId(displays->at(secondary_index).id()).bounds(); 945 UpdateDisplayBoundsForLayout( 946 layout, displays->at(primary_index), &displays->at(secondary_index)); 947 *updated_index = secondary_index; 948 return bounds != displays->at(secondary_index).bounds(); 949 } 950 return false; 951} 952 953} // namespace internal 954} // namespace ash 955