Focus rings for checkboxes and radio buttons should not be shown in Sync setup overlay.
[chromium-blink-merge.git] / ash / display / display_manager.cc
blob48fb914d0f9de50b1228b3a8467502d72539366a
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.
5 #include "ash/display/display_manager.h"
7 #include <cmath>
8 #include <set>
9 #include <string>
10 #include <vector>
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"
30 #if defined(USE_X11)
31 #include "ui/base/x/x11_util.h"
32 #endif
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
40 #if defined(OS_WIN)
41 #include "base/win/windows_version.h"
42 #endif
44 namespace ash {
45 namespace internal {
46 typedef std::vector<gfx::Display> DisplayList;
47 typedef std::vector<DisplayInfo> DisplayInfoList;
49 namespace {
51 // The number of pixels to overlap between the primary and secondary displays,
52 // in case that the offset value is too large.
53 const int kMinimumOverlapForInvalidOffset = 100;
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.
59 const float kUIScalesFor2x[] = {0.5f, 0.625f, 0.8f, 1.0f, 1.125f, 1.25f, 1.5f};
60 const float kUIScalesFor1280[] = {0.5f, 0.625f, 0.8f, 1.0f, 1.125f };
61 const float kUIScalesFor1366[] = {0.5f, 0.6f, 0.75f, 1.0f, 1.125f };
63 struct DisplaySortFunctor {
64 bool operator()(const gfx::Display& a, const gfx::Display& b) {
65 return a.id() < b.id();
69 struct DisplayInfoSortFunctor {
70 bool operator()(const DisplayInfo& a, const DisplayInfo& b) {
71 return a.id() < b.id();
75 struct ScaleComparator {
76 ScaleComparator(float s) : scale(s) {}
78 bool operator()(float s) const {
79 const float kEpsilon = 0.0001f;
80 return std::abs(scale - s) < kEpsilon;
82 float scale;
85 gfx::Display& GetInvalidDisplay() {
86 static gfx::Display* invalid_display = new gfx::Display();
87 return *invalid_display;
90 // Scoped objects used to either create or close the mirror window
91 // at specific timing.
92 class MirrorWindowCreator {
93 public:
94 MirrorWindowCreator(DisplayManager::Delegate* delegate,
95 const DisplayInfo& display_info)
96 : delegate_(delegate),
97 display_info_(display_info) {
100 virtual ~MirrorWindowCreator() {
101 if (delegate_)
102 delegate_->CreateOrUpdateMirrorWindow(display_info_);
105 private:
106 DisplayManager::Delegate* delegate_;
107 const DisplayInfo display_info_;
108 DISALLOW_COPY_AND_ASSIGN(MirrorWindowCreator);
111 class MirrorWindowCloser {
112 public:
113 explicit MirrorWindowCloser(DisplayManager::Delegate* delegate)
114 : delegate_(delegate) {}
116 virtual ~MirrorWindowCloser() {
117 if (delegate_)
118 delegate_->CloseMirrorWindow();
121 private:
122 DisplayManager::Delegate* delegate_;
124 DISALLOW_COPY_AND_ASSIGN(MirrorWindowCloser);
127 } // namespace
129 using std::string;
130 using std::vector;
132 DisplayManager::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
145 DisplayManager::~DisplayManager() {
148 // static
149 std::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;
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
173 return ret;
176 // static
177 float 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];
189 // Fallback to 1.0f if the |scale| wasn't in the list.
190 return 1.0f;
193 void DisplayManager::InitFromCommandLine() {
194 DisplayInfoList info_list;
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));
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);
210 // static
211 void 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));
222 bool 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;
228 return false;
231 bool DisplayManager::HasInternalDisplay() const {
232 return gfx::Display::InternalDisplayId() != gfx::Display::kInvalidDisplayID;
235 bool DisplayManager::IsInternalDisplayId(int64 id) const {
236 return gfx::Display::InternalDisplayId() == id;
239 const gfx::Display& DisplayManager::GetDisplayForId(int64 id) const {
240 gfx::Display* display =
241 const_cast<DisplayManager*>(this)->FindDisplayForId(id);
242 return display ? *display : GetInvalidDisplay();
245 const 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;
253 return GetInvalidDisplay();
256 bool 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();
265 void 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()));
273 AddMirrorDisplayInfoIfAny(&display_info_list);
274 UpdateDisplays(display_info_list);
277 void 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);
290 display_info_list.push_back(info);
292 AddMirrorDisplayInfoIfAny(&display_info_list);
293 UpdateDisplays(display_info_list);
296 void DisplayManager::SetDisplayUIScale(int64 display_id,
297 float ui_scale) {
298 if (!IsDisplayUIScalingEnabled() ||
299 gfx::Display::InternalDisplayId() != display_id) {
300 return;
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;
316 info.set_ui_scale(ui_scale);
318 display_info_list.push_back(info);
320 AddMirrorDisplayInfoIfAny(&display_info_list);
321 UpdateDisplays(display_info_list);
324 void DisplayManager::RegisterDisplayProperty(
325 int64 display_id,
326 gfx::Display::Rotation rotation,
327 float ui_scale,
328 const gfx::Insets* overscan_insets) {
329 if (display_info_.find(display_id) == display_info_.end()) {
330 display_info_[display_id] =
331 DisplayInfo(display_id, std::string(""), false);
334 display_info_[display_id].set_rotation(rotation);
335 // Just in case the preference file was corrupted.
336 if (0.5f <= ui_scale && ui_scale <= 2.0f)
337 display_info_[display_id].set_ui_scale(ui_scale);
338 if (overscan_insets)
339 display_info_[display_id].SetOverscanInsets(*overscan_insets);
342 bool DisplayManager::IsDisplayRotationEnabled() const {
343 static bool enabled = !CommandLine::ForCurrentProcess()->
344 HasSwitch(switches::kAshDisableDisplayRotation);
345 return enabled;
348 bool DisplayManager::IsDisplayUIScalingEnabled() const {
349 static bool enabled = !CommandLine::ForCurrentProcess()->
350 HasSwitch(switches::kAshDisableUIScaling);
351 if (!enabled)
352 return false;
353 return GetDisplayIdForUIScaling() != gfx::Display::kInvalidDisplayID;
356 gfx::Insets DisplayManager::GetOverscanInsets(int64 display_id) const {
357 std::map<int64, DisplayInfo>::const_iterator it =
358 display_info_.find(display_id);
359 return (it != display_info_.end()) ?
360 it->second.overscan_insets_in_dip() : gfx::Insets();
363 void DisplayManager::OnNativeDisplaysChanged(
364 const std::vector<DisplayInfo>& updated_displays) {
365 if (updated_displays.empty()) {
366 // If the device is booted without display, or chrome is started
367 // without --ash-host-window-bounds on linux desktop, use the
368 // default display.
369 if (displays_.empty()) {
370 std::vector<DisplayInfo> init_displays;
371 init_displays.push_back(DisplayInfo::CreateFromSpec(std::string()));
372 OnNativeDisplaysChanged(init_displays);
373 } else {
374 // Otherwise don't update the displays when all displays are disconnected.
375 // This happens when:
376 // - the device is idle and powerd requested to turn off all displays.
377 // - the device is suspended. (kernel turns off all displays)
378 // - the internal display's brightness is set to 0 and no external
379 // display is connected.
380 // - the internal display's brightness is 0 and external display is
381 // disconnected.
382 // The display will be updated when one of displays is turned on, and the
383 // display list will be updated correctly.
385 return;
387 first_display_id_ = updated_displays[0].id();
388 std::set<gfx::Point> origins;
390 if (updated_displays.size() == 1) {
391 VLOG(1) << "OnNativeDisplaysChanged(1):" << updated_displays[0].ToString();
392 } else {
393 VLOG(1) << "OnNativeDisplaysChanged(" << updated_displays.size()
394 << ") [0]=" << updated_displays[0].ToString()
395 << ", [1]=" << updated_displays[1].ToString();
398 bool internal_display_connected = false;
399 num_connected_displays_ = updated_displays.size();
400 mirrored_display_ = gfx::Display();
401 DisplayInfoList new_display_info_list;
402 for (DisplayInfoList::const_iterator iter = updated_displays.begin();
403 iter != updated_displays.end();
404 ++iter) {
405 if (!internal_display_connected)
406 internal_display_connected = IsInternalDisplayId(iter->id());
407 // Mirrored monitors have the same origins.
408 gfx::Point origin = iter->bounds_in_pixel().origin();
409 if (origins.find(origin) != origins.end()) {
410 InsertAndUpdateDisplayInfo(*iter);
411 mirrored_display_ = CreateDisplayFromDisplayInfoById(iter->id());
412 } else {
413 origins.insert(origin);
414 new_display_info_list.push_back(*iter);
417 if (HasInternalDisplay() &&
418 !internal_display_connected &&
419 display_info_.find(gfx::Display::InternalDisplayId()) ==
420 display_info_.end()) {
421 DisplayInfo internal_display_info(
422 gfx::Display::InternalDisplayId(),
423 l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME),
424 false /*Internal display must not have overscan */);
425 internal_display_info.SetBounds(gfx::Rect(0, 0, 800, 600));
426 display_info_[gfx::Display::InternalDisplayId()] = internal_display_info;
428 UpdateDisplays(new_display_info_list);
431 void DisplayManager::UpdateDisplays() {
432 DisplayInfoList display_info_list;
433 for (DisplayList::const_iterator iter = displays_.begin();
434 iter != displays_.end(); ++iter) {
435 display_info_list.push_back(GetDisplayInfo(iter->id()));
437 AddMirrorDisplayInfoIfAny(&display_info_list);
438 UpdateDisplays(display_info_list);
441 void DisplayManager::UpdateDisplays(
442 const std::vector<DisplayInfo>& updated_display_info_list) {
443 #if defined(OS_WIN)
444 if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
445 DCHECK_EQ(1u, updated_display_info_list.size()) <<
446 "Multiple display test does not work on Win8 bots. Please "
447 "skip (don't disable) the test using SupportsMultipleDisplays()";
449 #endif
451 DisplayInfoList new_display_info_list = updated_display_info_list;
452 std::sort(displays_.begin(), displays_.end(), DisplaySortFunctor());
453 std::sort(new_display_info_list.begin(),
454 new_display_info_list.end(),
455 DisplayInfoSortFunctor());
456 DisplayList removed_displays;
457 std::vector<size_t> changed_display_indices;
458 std::vector<size_t> added_display_indices;
460 DisplayList::iterator curr_iter = displays_.begin();
461 DisplayInfoList::const_iterator new_info_iter = new_display_info_list.begin();
463 DisplayList new_displays;
465 scoped_ptr<MirrorWindowCreator> mirror_window_creater;
467 // Use the internal display or 1st as the mirror source, then scale
468 // the root window so that it matches the external display's
469 // resolution. This is necessary in order for scaling to work while
470 // mirrored.
471 int64 mirrored_display_id = gfx::Display::kInvalidDisplayID;
472 if (software_mirroring_enabled_ && new_display_info_list.size() == 2)
473 mirrored_display_id = new_display_info_list[1].id();
475 while (curr_iter != displays_.end() ||
476 new_info_iter != new_display_info_list.end()) {
477 if (new_info_iter != new_display_info_list.end() &&
478 mirrored_display_id == new_info_iter->id()) {
479 DisplayInfo info = *new_info_iter;
480 info.SetOverscanInsets(gfx::Insets());
481 InsertAndUpdateDisplayInfo(info);
483 mirrored_display_ = CreateDisplayFromDisplayInfoById(new_info_iter->id());
484 mirror_window_creater.reset(new MirrorWindowCreator(
485 delegate_, display_info_[new_info_iter->id()]));
486 ++new_info_iter;
487 // Remove existing external dispaly if it is going to be mirrored.
488 if (curr_iter != displays_.end() &&
489 curr_iter->id() == mirrored_display_id) {
490 removed_displays.push_back(*curr_iter);
491 ++curr_iter;
493 continue;
496 if (curr_iter == displays_.end()) {
497 // more displays in new list.
498 added_display_indices.push_back(new_displays.size());
499 InsertAndUpdateDisplayInfo(*new_info_iter);
500 new_displays.push_back(
501 CreateDisplayFromDisplayInfoById(new_info_iter->id()));
502 ++new_info_iter;
503 } else if (new_info_iter == new_display_info_list.end()) {
504 // more displays in current list.
505 removed_displays.push_back(*curr_iter);
506 ++curr_iter;
507 } else if (curr_iter->id() == new_info_iter->id()) {
508 const gfx::Display& current_display = *curr_iter;
509 // Copy the info because |CreateDisplayFromInfo| updates the instance.
510 const DisplayInfo current_display_info =
511 GetDisplayInfo(current_display.id());
512 InsertAndUpdateDisplayInfo(*new_info_iter);
513 gfx::Display new_display =
514 CreateDisplayFromDisplayInfoById(new_info_iter->id());
515 const DisplayInfo& new_display_info = GetDisplayInfo(new_display.id());
517 bool host_window_bounds_changed =
518 current_display_info.bounds_in_pixel() !=
519 new_display_info.bounds_in_pixel();
521 if (force_bounds_changed_ ||
522 host_window_bounds_changed ||
523 (current_display.device_scale_factor() !=
524 new_display.device_scale_factor()) ||
525 (current_display_info.size_in_pixel() !=
526 new_display.GetSizeInPixel()) ||
527 (current_display.rotation() != new_display.rotation())) {
529 changed_display_indices.push_back(new_displays.size());
532 new_display.UpdateWorkAreaFromInsets(current_display.GetWorkAreaInsets());
533 new_displays.push_back(new_display);
534 ++curr_iter;
535 ++new_info_iter;
536 } else if (curr_iter->id() < new_info_iter->id()) {
537 // more displays in current list between ids, which means it is deleted.
538 removed_displays.push_back(*curr_iter);
539 ++curr_iter;
540 } else {
541 // more displays in new list between ids, which means it is added.
542 added_display_indices.push_back(new_displays.size());
543 InsertAndUpdateDisplayInfo(*new_info_iter);
544 new_displays.push_back(
545 CreateDisplayFromDisplayInfoById(new_info_iter->id()));
546 ++new_info_iter;
550 scoped_ptr<MirrorWindowCloser> mirror_window_closer;
551 // Try to close mirror window unless mirror window is necessary.
552 if (!mirror_window_creater.get())
553 mirror_window_closer.reset(new MirrorWindowCloser(delegate_));
555 // Do not update |displays_| if there's nothing to be updated. Without this,
556 // it will not update the display layout, which causes the bug
557 // http://crbug.com/155948.
558 if (changed_display_indices.empty() && added_display_indices.empty() &&
559 removed_displays.empty()) {
560 return;
562 if (delegate_)
563 delegate_->PreDisplayConfigurationChange();
565 size_t updated_index;
566 if (UpdateSecondaryDisplayBoundsForLayout(&new_displays, &updated_index) &&
567 std::find(added_display_indices.begin(),
568 added_display_indices.end(),
569 updated_index) == added_display_indices.end() &&
570 std::find(changed_display_indices.begin(),
571 changed_display_indices.end(),
572 updated_index) == changed_display_indices.end()) {
573 changed_display_indices.push_back(updated_index);
576 displays_ = new_displays;
578 base::AutoReset<bool> resetter(&change_display_upon_host_resize_, false);
580 // Temporarily add displays to be removed because display object
581 // being removed are accessed during shutting down the root.
582 displays_.insert(displays_.end(), removed_displays.begin(),
583 removed_displays.end());
585 for (DisplayList::const_reverse_iterator iter = removed_displays.rbegin();
586 iter != removed_displays.rend(); ++iter) {
587 Shell::GetInstance()->screen()->NotifyDisplayRemoved(displays_.back());
588 displays_.pop_back();
590 // Close the mirror window here to avoid creating two compositor on
591 // one display.
592 mirror_window_closer.reset();
593 for (std::vector<size_t>::iterator iter = added_display_indices.begin();
594 iter != added_display_indices.end(); ++iter) {
595 Shell::GetInstance()->screen()->NotifyDisplayAdded(displays_[*iter]);
597 // Create the mirror window after all displays are added so that
598 // it can mirror the display newly added. This can happen when switching
599 // from dock mode to software mirror mode.
600 mirror_window_creater.reset();
601 for (std::vector<size_t>::iterator iter = changed_display_indices.begin();
602 iter != changed_display_indices.end(); ++iter) {
603 Shell::GetInstance()->screen()->NotifyBoundsChanged(displays_[*iter]);
605 if (delegate_)
606 delegate_->PostDisplayConfigurationChange();
608 #if defined(USE_X11) && defined(OS_CHROMEOS)
609 if (!changed_display_indices.empty() && base::chromeos::IsRunningOnChromeOS())
610 ui::ClearX11DefaultRootWindow();
611 #endif
614 const gfx::Display& DisplayManager::GetDisplayAt(size_t index) const {
615 DCHECK_LT(index, displays_.size());
616 return displays_[index];
619 const gfx::Display* DisplayManager::GetPrimaryDisplayCandidate() const {
620 const gfx::Display* primary_candidate = &displays_[0];
621 #if defined(OS_CHROMEOS)
622 if (base::chromeos::IsRunningOnChromeOS()) {
623 // On ChromeOS device, root windows are stacked vertically, and
624 // default primary is the one on top.
625 int count = GetNumDisplays();
626 int y = GetDisplayInfo(primary_candidate->id()).bounds_in_pixel().y();
627 for (int i = 1; i < count; ++i) {
628 const gfx::Display* display = &displays_[i];
629 const DisplayInfo& display_info = GetDisplayInfo(display->id());
630 if (display->IsInternal()) {
631 primary_candidate = display;
632 break;
633 } else if (display_info.bounds_in_pixel().y() < y) {
634 primary_candidate = display;
635 y = display_info.bounds_in_pixel().y();
639 #endif
640 return primary_candidate;
643 size_t DisplayManager::GetNumDisplays() const {
644 return displays_.size();
647 bool DisplayManager::IsMirrored() const {
648 return mirrored_display_.id() != gfx::Display::kInvalidDisplayID;
651 const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const {
652 std::map<int64, DisplayInfo>::const_iterator iter =
653 display_info_.find(display_id);
654 CHECK(iter != display_info_.end()) << display_id;
655 return iter->second;
658 std::string DisplayManager::GetDisplayNameForId(int64 id) {
659 if (id == gfx::Display::kInvalidDisplayID)
660 return l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME);
662 std::map<int64, DisplayInfo>::const_iterator iter = display_info_.find(id);
663 if (iter != display_info_.end() && !iter->second.name().empty())
664 return iter->second.name();
666 return base::StringPrintf("Display %d", static_cast<int>(id));
669 int64 DisplayManager::GetDisplayIdForUIScaling() const {
670 // UI Scaling is effective only on internal display.
671 int64 display_id = gfx::Display::InternalDisplayId();
672 #if defined(OS_WIN)
673 display_id = first_display_id();
674 #endif
675 return display_id;
678 void DisplayManager::SetMirrorMode(bool mirrored) {
679 if (num_connected_displays() <= 1)
680 return;
682 #if defined(OS_CHROMEOS)
683 if (base::chromeos::IsRunningOnChromeOS()) {
684 chromeos::OutputState new_state = mirrored ?
685 chromeos::STATE_DUAL_MIRROR : chromeos::STATE_DUAL_EXTENDED;
686 Shell::GetInstance()->output_configurator()->SetDisplayMode(new_state);
687 return;
689 #endif
690 SetSoftwareMirroring(mirrored);
691 DisplayInfoList display_info_list;
692 int count = 0;
693 for (std::map<int64, DisplayInfo>::const_iterator iter =
694 display_info_.begin();
695 count < 2; ++iter, ++count) {
696 display_info_list.push_back(GetDisplayInfo(iter->second.id()));
698 UpdateDisplays(display_info_list);
699 #if defined(OS_CHROMEOS)
700 if (Shell::GetInstance()->output_configurator_animation()) {
701 Shell::GetInstance()->output_configurator_animation()->
702 StartFadeInAnimation();
704 #endif
707 void DisplayManager::AddRemoveDisplay() {
708 DCHECK(!displays_.empty());
709 std::vector<DisplayInfo> new_display_info_list;
710 DisplayInfo first_display = GetDisplayInfo(displays_[0].id());
711 new_display_info_list.push_back(first_display);
712 // Add if there is only one display connected.
713 if (num_connected_displays() == 1) {
714 // Layout the 2nd display below the primary as with the real device.
715 gfx::Rect host_bounds = first_display.bounds_in_pixel();
716 new_display_info_list.push_back(DisplayInfo::CreateFromSpec(
717 base::StringPrintf(
718 "%d+%d-500x400", host_bounds.x(), host_bounds.bottom())));
720 num_connected_displays_ = new_display_info_list.size();
721 mirrored_display_ = gfx::Display();
722 UpdateDisplays(new_display_info_list);
725 void DisplayManager::ToggleDisplayScaleFactor() {
726 DCHECK(!displays_.empty());
727 std::vector<DisplayInfo> new_display_info_list;
728 for (DisplayList::const_iterator iter = displays_.begin();
729 iter != displays_.end(); ++iter) {
730 DisplayInfo display_info = GetDisplayInfo(iter->id());
731 display_info.set_device_scale_factor(
732 display_info.device_scale_factor() == 1.0f ? 2.0f : 1.0f);
733 new_display_info_list.push_back(display_info);
735 AddMirrorDisplayInfoIfAny(&new_display_info_list);
736 UpdateDisplays(new_display_info_list);
739 void DisplayManager::SetSoftwareMirroring(bool enabled) {
740 software_mirroring_enabled_ = enabled;
741 mirrored_display_ = gfx::Display();
744 bool DisplayManager::UpdateDisplayBounds(int64 display_id,
745 const gfx::Rect& new_bounds) {
746 if (change_display_upon_host_resize_) {
747 display_info_[display_id].SetBounds(new_bounds);
748 // Don't notify observers if the mirrored window has changed.
749 if (software_mirroring_enabled_ && mirrored_display_.id() == display_id)
750 return false;
751 gfx::Display* display = FindDisplayForId(display_id);
752 display->SetSize(display_info_[display_id].size_in_pixel());
753 Shell::GetInstance()->screen()->NotifyBoundsChanged(*display);
754 return true;
756 return false;
759 gfx::Display* DisplayManager::FindDisplayForId(int64 id) {
760 for (DisplayList::iterator iter = displays_.begin();
761 iter != displays_.end(); ++iter) {
762 if ((*iter).id() == id)
763 return &(*iter);
765 DLOG(WARNING) << "Could not find display:" << id;
766 return NULL;
769 void DisplayManager::AddMirrorDisplayInfoIfAny(
770 std::vector<DisplayInfo>* display_info_list) {
771 if (software_mirroring_enabled_ && mirrored_display_.is_valid())
772 display_info_list->push_back(GetDisplayInfo(mirrored_display_.id()));
775 void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo& new_info) {
776 std::map<int64, DisplayInfo>::iterator info =
777 display_info_.find(new_info.id());
778 if (info != display_info_.end())
779 info->second.Copy(new_info);
780 else {
781 display_info_[new_info.id()] = new_info;
782 display_info_[new_info.id()].set_native(false);
784 display_info_[new_info.id()].UpdateDisplaySize();
787 gfx::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64 id) {
788 DCHECK(display_info_.find(id) != display_info_.end());
789 const DisplayInfo& display_info = display_info_[id];
791 gfx::Display new_display(display_info.id());
792 gfx::Rect bounds_in_pixel(display_info.size_in_pixel());
794 // Simply set the origin to (0,0). The primary display's origin is
795 // always (0,0) and the secondary display's bounds will be updated
796 // in |UpdateSecondaryDisplayBoundsForLayout| called in |UpdateDisplay|.
797 new_display.SetScaleAndBounds(
798 display_info.device_scale_factor(), gfx::Rect(bounds_in_pixel.size()));
799 new_display.set_rotation(display_info.rotation());
800 return new_display;
803 bool DisplayManager::UpdateSecondaryDisplayBoundsForLayout(
804 DisplayList* displays,
805 size_t* updated_index) const {
806 if (displays->size() != 2U)
807 return false;
809 int64 id_at_zero = displays->at(0).id();
810 DisplayIdPair pair =
811 (id_at_zero == first_display_id_ ||
812 id_at_zero == gfx::Display::InternalDisplayId()) ?
813 std::make_pair(id_at_zero, displays->at(1).id()) :
814 std::make_pair(displays->at(1).id(), id_at_zero) ;
815 DisplayLayout layout =
816 layout_store_->ComputeDisplayLayoutForDisplayIdPair(pair);
818 // Ignore if a user has a old format (should be extremely rare)
819 // and this will be replaced with DCHECK.
820 if (layout.primary_id != gfx::Display::kInvalidDisplayID) {
821 size_t primary_index, secondary_index;
822 if (displays->at(0).id() == layout.primary_id) {
823 primary_index = 0;
824 secondary_index = 1;
825 } else {
826 primary_index = 1;
827 secondary_index = 0;
829 gfx::Rect bounds =
830 GetDisplayForId(displays->at(secondary_index).id()).bounds();
831 UpdateDisplayBoundsForLayout(
832 layout, displays->at(primary_index), &displays->at(secondary_index));
833 *updated_index = secondary_index;
834 return bounds != displays->at(secondary_index).bounds();
836 return false;
839 // static
840 void DisplayManager::UpdateDisplayBoundsForLayout(
841 const DisplayLayout& layout,
842 const gfx::Display& primary_display,
843 gfx::Display* secondary_display) {
844 DCHECK_EQ("0,0", primary_display.bounds().origin().ToString());
846 const gfx::Rect& primary_bounds = primary_display.bounds();
847 const gfx::Rect& secondary_bounds = secondary_display->bounds();
848 gfx::Point new_secondary_origin = primary_bounds.origin();
850 DisplayLayout::Position position = layout.position;
852 // Ignore the offset in case the secondary display doesn't share edges with
853 // the primary display.
854 int offset = layout.offset;
855 if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM) {
856 offset = std::min(
857 offset, primary_bounds.width() - kMinimumOverlapForInvalidOffset);
858 offset = std::max(
859 offset, -secondary_bounds.width() + kMinimumOverlapForInvalidOffset);
860 } else {
861 offset = std::min(
862 offset, primary_bounds.height() - kMinimumOverlapForInvalidOffset);
863 offset = std::max(
864 offset, -secondary_bounds.height() + kMinimumOverlapForInvalidOffset);
866 switch (position) {
867 case DisplayLayout::TOP:
868 new_secondary_origin.Offset(offset, -secondary_bounds.height());
869 break;
870 case DisplayLayout::RIGHT:
871 new_secondary_origin.Offset(primary_bounds.width(), offset);
872 break;
873 case DisplayLayout::BOTTOM:
874 new_secondary_origin.Offset(offset, primary_bounds.height());
875 break;
876 case DisplayLayout::LEFT:
877 new_secondary_origin.Offset(-secondary_bounds.width(), offset);
878 break;
880 gfx::Insets insets = secondary_display->GetWorkAreaInsets();
881 secondary_display->set_bounds(
882 gfx::Rect(new_secondary_origin, secondary_bounds.size()));
883 secondary_display->UpdateWorkAreaFromInsets(insets);
886 } // namespace internal
887 } // namespace ash