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