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"
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"
31 #include "ui/base/x/x11_util.h"
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"
41 #include "base/win/windows_version.h"
46 typedef std::vector
<gfx::Display
> DisplayList
;
47 typedef std::vector
<DisplayInfo
> DisplayInfoList
;
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
;
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
{
94 MirrorWindowCreator(DisplayManager::Delegate
* delegate
,
95 const DisplayInfo
& display_info
)
96 : delegate_(delegate
),
97 display_info_(display_info
) {
100 virtual ~MirrorWindowCreator() {
102 delegate_
->CreateOrUpdateMirrorWindow(display_info_
);
106 DisplayManager::Delegate
* delegate_
;
107 const DisplayInfo display_info_
;
108 DISALLOW_COPY_AND_ASSIGN(MirrorWindowCreator
);
111 class MirrorWindowCloser
{
113 explicit MirrorWindowCloser(DisplayManager::Delegate
* delegate
)
114 : delegate_(delegate
) {}
116 virtual ~MirrorWindowCloser() {
118 delegate_
->CloseMirrorWindow();
122 DisplayManager::Delegate
* delegate_
;
124 DISALLOW_COPY_AND_ASSIGN(MirrorWindowCloser
);
132 DisplayManager::DisplayManager()
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();
145 DisplayManager::~DisplayManager() {
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
));
156 switch (info
.bounds_in_pixel().width()) {
158 ret
.assign(kUIScalesFor1280
,
159 kUIScalesFor1280
+ arraysize(kUIScalesFor1280
));
162 ret
.assign(kUIScalesFor1366
,
163 kUIScalesFor1366
+ arraysize(kUIScalesFor1366
));
166 ret
.assign(kUIScalesFor1280
,
167 kUIScalesFor1280
+ arraysize(kUIScalesFor1280
));
168 #if defined(OS_CHROMEOS)
169 if (base::chromeos::IsRunningOnChromeOS())
170 NOTREACHED() << "Unknown resolution:" << info
.ToString();
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];
185 return scales
[i
- 1];
189 // Fallback to 1.0f if the |scale| wasn't in the list.
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
);
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())
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
))
253 return GetInvalidDisplay();
256 bool DisplayManager::UpdateWorkAreaOfDisplay(int64 display_id
,
257 const gfx::Insets
& insets
) {
258 gfx::Display
* display
= FindDisplayForId(display_id
);
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())
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
)
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
,
298 if (!IsDisplayUIScalingEnabled() ||
299 gfx::Display::InternalDisplayId() != display_id
) {
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
)
310 std::vector
<float> scales
= GetScalesForDisplay(info
);
311 ScaleComparator
comparator(ui_scale
);
312 if (std::find_if(scales
.begin(), scales
.end(), comparator
) ==
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(
326 gfx::Display::Rotation rotation
,
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
);
339 display_info_
[display_id
].SetOverscanInsets(*overscan_insets
);
342 bool DisplayManager::IsDisplayRotationEnabled() const {
343 static bool enabled
= !CommandLine::ForCurrentProcess()->
344 HasSwitch(switches::kAshDisableDisplayRotation
);
348 bool DisplayManager::IsDisplayUIScalingEnabled() const {
349 static bool enabled
= !CommandLine::ForCurrentProcess()->
350 HasSwitch(switches::kAshDisableUIScaling
);
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
369 if (displays_
.empty()) {
370 std::vector
<DisplayInfo
> init_displays
;
371 init_displays
.push_back(DisplayInfo::CreateFromSpec(std::string()));
372 OnNativeDisplaysChanged(init_displays
);
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
382 // The display will be updated when one of displays is turned on, and the
383 // display list will be updated correctly.
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();
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();
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());
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
) {
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()";
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
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()]));
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
);
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()));
503 } else if (new_info_iter
== new_display_info_list
.end()) {
504 // more displays in current list.
505 removed_displays
.push_back(*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
);
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
);
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()));
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()) {
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
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
]);
606 delegate_
->PostDisplayConfigurationChange();
608 #if defined(USE_X11) && defined(OS_CHROMEOS)
609 if (!changed_display_indices
.empty() && base::chromeos::IsRunningOnChromeOS())
610 ui::ClearX11DefaultRootWindow();
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
;
633 } else if (display_info
.bounds_in_pixel().y() < y
) {
634 primary_candidate
= display
;
635 y
= display_info
.bounds_in_pixel().y();
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
;
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();
673 display_id
= first_display_id();
678 void DisplayManager::SetMirrorMode(bool mirrored
) {
679 if (num_connected_displays() <= 1)
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
);
690 SetSoftwareMirroring(mirrored
);
691 DisplayInfoList display_info_list
;
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();
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(
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
)
751 gfx::Display
* display
= FindDisplayForId(display_id
);
752 display
->SetSize(display_info_
[display_id
].size_in_pixel());
753 Shell::GetInstance()->screen()->NotifyBoundsChanged(*display
);
759 gfx::Display
* DisplayManager::FindDisplayForId(int64 id
) {
760 for (DisplayList::iterator iter
= displays_
.begin();
761 iter
!= displays_
.end(); ++iter
) {
762 if ((*iter
).id() == id
)
765 DLOG(WARNING
) << "Could not find display:" << id
;
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
);
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());
803 bool DisplayManager::UpdateSecondaryDisplayBoundsForLayout(
804 DisplayList
* displays
,
805 size_t* updated_index
) const {
806 if (displays
->size() != 2U)
809 int64 id_at_zero
= displays
->at(0).id();
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
) {
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();
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
) {
857 offset
, primary_bounds
.width() - kMinimumOverlapForInvalidOffset
);
859 offset
, -secondary_bounds
.width() + kMinimumOverlapForInvalidOffset
);
862 offset
, primary_bounds
.height() - kMinimumOverlapForInvalidOffset
);
864 offset
, -secondary_bounds
.height() + kMinimumOverlapForInvalidOffset
);
867 case DisplayLayout::TOP
:
868 new_secondary_origin
.Offset(offset
, -secondary_bounds
.height());
870 case DisplayLayout::RIGHT
:
871 new_secondary_origin
.Offset(primary_bounds
.width(), offset
);
873 case DisplayLayout::BOTTOM
:
874 new_secondary_origin
.Offset(offset
, primary_bounds
.height());
876 case DisplayLayout::LEFT
:
877 new_secondary_origin
.Offset(-secondary_bounds
.width(), offset
);
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