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/display/screen_ash.h"
15 #include "ash/screen_util.h"
16 #include "ash/shell.h"
17 #include "base/auto_reset.h"
18 #include "base/command_line.h"
19 #include "base/logging.h"
20 #include "base/metrics/histogram.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/string_split.h"
23 #include "base/strings/stringprintf.h"
24 #include "base/strings/utf_string_conversions.h"
25 #include "grit/ash_strings.h"
26 #include "ui/base/l10n/l10n_util.h"
27 #include "ui/base/layout.h"
28 #include "ui/base/resource/resource_bundle.h"
29 #include "ui/gfx/display.h"
30 #include "ui/gfx/display_observer.h"
31 #include "ui/gfx/rect.h"
32 #include "ui/gfx/screen.h"
33 #include "ui/gfx/size_conversions.h"
36 #include "ui/base/x/x11_util.h"
39 #if defined(OS_CHROMEOS)
40 #include "ash/display/display_configurator_animation.h"
41 #include "base/sys_info.h"
45 #include "base/win/windows_version.h"
49 typedef std::vector
<gfx::Display
> DisplayList
;
50 typedef std::vector
<DisplayInfo
> DisplayInfoList
;
54 // We need to keep this in order for unittests to tell if
55 // the object in gfx::Screen::GetScreenByType is for shutdown.
56 gfx::Screen
* screen_for_shutdown
= NULL
;
58 // The number of pixels to overlap between the primary and secondary displays,
59 // in case that the offset value is too large.
60 const int kMinimumOverlapForInvalidOffset
= 100;
62 // List of value UI Scale values. Scales for 2x are equivalent to 640,
63 // 800, 1024, 1280, 1440, 1600 and 1920 pixel width respectively on
64 // 2560 pixel width 2x density display. Please see crbug.com/233375
65 // for the full list of resolutions.
66 const float kUIScalesFor2x
[] =
67 {0.5f
, 0.625f
, 0.8f
, 1.0f
, 1.125f
, 1.25f
, 1.5f
, 2.0f
};
68 const float kUIScalesFor1280
[] = {0.5f
, 0.625f
, 0.8f
, 1.0f
, 1.125f
};
69 const float kUIScalesFor1366
[] = {0.5f
, 0.6f
, 0.75f
, 1.0f
, 1.125f
};
71 struct DisplaySortFunctor
{
72 bool operator()(const gfx::Display
& a
, const gfx::Display
& b
) {
73 return a
.id() < b
.id();
77 struct DisplayInfoSortFunctor
{
78 bool operator()(const DisplayInfo
& a
, const DisplayInfo
& b
) {
79 return a
.id() < b
.id();
83 struct DisplayModeMatcher
{
84 DisplayModeMatcher(const gfx::Size
& size
) : size(size
) {}
85 bool operator()(const DisplayMode
& mode
) { return mode
.size
== size
; }
89 struct ScaleComparator
{
90 explicit ScaleComparator(float s
) : scale(s
) {}
92 bool operator()(float s
) const {
93 const float kEpsilon
= 0.0001f
;
94 return std::abs(scale
- s
) < kEpsilon
;
99 gfx::Display
& GetInvalidDisplay() {
100 static gfx::Display
* invalid_display
= new gfx::Display();
101 return *invalid_display
;
104 void MaybeInitInternalDisplay(int64 id
) {
105 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
106 if (command_line
->HasSwitch(switches::kAshUseFirstDisplayAsInternal
))
107 gfx::Display::SetInternalDisplayId(id
);
110 // Scoped objects used to either create or close the non desktop window
111 // at specific timing.
112 class NonDesktopDisplayUpdater
{
114 NonDesktopDisplayUpdater(DisplayManager
* manager
,
115 DisplayManager::Delegate
* delegate
)
118 enabled_(manager_
->second_display_mode() != DisplayManager::EXTENDED
&&
119 manager_
->non_desktop_display().is_valid()) {
122 ~NonDesktopDisplayUpdater() {
127 DisplayInfo display_info
= manager_
->GetDisplayInfo(
128 manager_
->non_desktop_display().id());
129 delegate_
->CreateOrUpdateNonDesktopDisplay(display_info
);
131 delegate_
->CloseNonDesktopDisplay();
135 bool enabled() const { return enabled_
; }
138 DisplayManager
* manager_
;
139 DisplayManager::Delegate
* delegate_
;
141 DISALLOW_COPY_AND_ASSIGN(NonDesktopDisplayUpdater
);
149 DisplayManager::DisplayManager()
151 screen_ash_(new ScreenAsh
),
152 screen_(screen_ash_
.get()),
153 layout_store_(new DisplayLayoutStore
),
154 first_display_id_(gfx::Display::kInvalidDisplayID
),
155 num_connected_displays_(0),
156 force_bounds_changed_(false),
157 change_display_upon_host_resize_(false),
158 second_display_mode_(EXTENDED
),
159 mirrored_display_id_(gfx::Display::kInvalidDisplayID
) {
160 #if defined(OS_CHROMEOS)
161 change_display_upon_host_resize_
= !base::SysInfo::IsRunningOnChromeOS();
163 DisplayInfo::SetAllowUpgradeToHighDPI(
164 ui::ResourceBundle::GetSharedInstance().GetMaxScaleFactor() ==
165 ui::SCALE_FACTOR_200P
);
167 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE
,
169 gfx::Screen
* current_native
=
170 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE
);
171 // If there is no native, or the native was for shutdown,
173 if (!current_native
||
174 current_native
== screen_for_shutdown
) {
175 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE
,
180 DisplayManager::~DisplayManager() {
184 std::vector
<float> DisplayManager::GetScalesForDisplay(
185 const DisplayInfo
& info
) {
186 std::vector
<float> ret
;
187 if (info
.device_scale_factor() == 2.0f
) {
188 ret
.assign(kUIScalesFor2x
, kUIScalesFor2x
+ arraysize(kUIScalesFor2x
));
191 switch (info
.bounds_in_native().width()) {
193 ret
.assign(kUIScalesFor1280
,
194 kUIScalesFor1280
+ arraysize(kUIScalesFor1280
));
197 ret
.assign(kUIScalesFor1366
,
198 kUIScalesFor1366
+ arraysize(kUIScalesFor1366
));
201 ret
.assign(kUIScalesFor1280
,
202 kUIScalesFor1280
+ arraysize(kUIScalesFor1280
));
203 #if defined(OS_CHROMEOS)
204 if (base::SysInfo::IsRunningOnChromeOS())
205 NOTREACHED() << "Unknown resolution:" << info
.ToString();
212 float DisplayManager::GetNextUIScale(const DisplayInfo
& info
, bool up
) {
213 float scale
= info
.configured_ui_scale();
214 std::vector
<float> scales
= GetScalesForDisplay(info
);
215 for (size_t i
= 0; i
< scales
.size(); ++i
) {
216 if (ScaleComparator(scales
[i
])(scale
)) {
217 if (up
&& i
!= scales
.size() - 1)
218 return scales
[i
+ 1];
220 return scales
[i
- 1];
224 // Fallback to 1.0f if the |scale| wasn't in the list.
228 bool DisplayManager::InitFromCommandLine() {
229 DisplayInfoList info_list
;
230 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
231 if (!command_line
->HasSwitch(switches::kAshHostWindowBounds
))
233 const string size_str
=
234 command_line
->GetSwitchValueASCII(switches::kAshHostWindowBounds
);
235 vector
<string
> parts
;
236 base::SplitString(size_str
, ',', &parts
);
237 for (vector
<string
>::const_iterator iter
= parts
.begin();
238 iter
!= parts
.end(); ++iter
) {
239 info_list
.push_back(DisplayInfo::CreateFromSpec(*iter
));
241 MaybeInitInternalDisplay(info_list
[0].id());
242 if (info_list
.size() > 1 &&
243 command_line
->HasSwitch(switches::kAshEnableSoftwareMirroring
)) {
244 SetSecondDisplayMode(MIRRORING
);
246 OnNativeDisplaysChanged(info_list
);
250 void DisplayManager::InitDefaultDisplay() {
251 DisplayInfoList info_list
;
252 info_list
.push_back(DisplayInfo::CreateFromSpec(std::string()));
253 MaybeInitInternalDisplay(info_list
[0].id());
254 OnNativeDisplaysChanged(info_list
);
258 void DisplayManager::UpdateDisplayBoundsForLayoutById(
259 const DisplayLayout
& layout
,
260 const gfx::Display
& primary_display
,
261 int64 secondary_display_id
) {
262 DCHECK_NE(gfx::Display::kInvalidDisplayID
, secondary_display_id
);
263 UpdateDisplayBoundsForLayout(
264 layout
, primary_display
,
265 Shell::GetInstance()->display_manager()->
266 FindDisplayForId(secondary_display_id
));
269 bool DisplayManager::IsActiveDisplay(const gfx::Display
& display
) const {
270 for (DisplayList::const_iterator iter
= displays_
.begin();
271 iter
!= displays_
.end(); ++iter
) {
272 if ((*iter
).id() == display
.id())
278 bool DisplayManager::HasInternalDisplay() const {
279 return gfx::Display::InternalDisplayId() != gfx::Display::kInvalidDisplayID
;
282 bool DisplayManager::IsInternalDisplayId(int64 id
) const {
283 return gfx::Display::InternalDisplayId() == id
;
286 DisplayLayout
DisplayManager::GetCurrentDisplayLayout() {
287 DCHECK_EQ(2U, num_connected_displays());
288 // Invert if the primary was swapped.
289 if (num_connected_displays() > 1) {
290 DisplayIdPair pair
= GetCurrentDisplayIdPair();
291 return layout_store_
->ComputeDisplayLayoutForDisplayIdPair(pair
);
293 NOTREACHED() << "DisplayLayout is requested for single display";
294 // On release build, just fallback to default instead of blowing up.
295 DisplayLayout layout
=
296 layout_store_
->default_display_layout();
297 layout
.primary_id
= displays_
[0].id();
301 DisplayIdPair
DisplayManager::GetCurrentDisplayIdPair() const {
303 if (software_mirroring_enabled()) {
304 CHECK_EQ(2u, num_connected_displays());
305 // This comment is to make it easy to distinguish the crash
306 // between two checks.
307 CHECK_EQ(1u, displays_
.size());
309 return std::make_pair(displays_
[0].id(), mirrored_display_id_
);
311 CHECK_GE(2u, displays_
.size());
312 int64 id_at_zero
= displays_
[0].id();
313 if (id_at_zero
== gfx::Display::InternalDisplayId() ||
314 id_at_zero
== first_display_id()) {
315 return std::make_pair(id_at_zero
, displays_
[1].id());
317 return std::make_pair(displays_
[1].id(), id_at_zero
);
322 void DisplayManager::SetLayoutForCurrentDisplays(
323 const DisplayLayout
& layout_relative_to_primary
) {
324 DCHECK_EQ(2U, GetNumDisplays());
325 if (GetNumDisplays() < 2)
327 const gfx::Display
& primary
= screen_
->GetPrimaryDisplay();
328 const DisplayIdPair pair
= GetCurrentDisplayIdPair();
329 // Invert if the primary was swapped.
330 DisplayLayout to_set
= pair
.first
== primary
.id() ?
331 layout_relative_to_primary
: layout_relative_to_primary
.Invert();
333 DisplayLayout current_layout
=
334 layout_store_
->GetRegisteredDisplayLayout(pair
);
335 if (to_set
.position
!= current_layout
.position
||
336 to_set
.offset
!= current_layout
.offset
) {
337 to_set
.primary_id
= primary
.id();
338 layout_store_
->RegisterLayoutForDisplayIdPair(
339 pair
.first
, pair
.second
, to_set
);
341 delegate_
->PreDisplayConfigurationChange(false);
342 // PreDisplayConfigurationChange(false);
343 // TODO(oshima): Call UpdateDisplays instead.
344 const DisplayLayout layout
= GetCurrentDisplayLayout();
345 UpdateDisplayBoundsForLayoutById(
347 ScreenUtil::GetSecondaryDisplay().id());
349 // Primary's bounds stay the same. Just notify bounds change
351 screen_ash_
->NotifyMetricsChanged(
352 ScreenUtil::GetSecondaryDisplay(),
353 gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS
|
354 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA
);
356 delegate_
->PostDisplayConfigurationChange();
360 const gfx::Display
& DisplayManager::GetDisplayForId(int64 id
) const {
361 gfx::Display
* display
=
362 const_cast<DisplayManager
*>(this)->FindDisplayForId(id
);
363 return display
? *display
: GetInvalidDisplay();
366 const gfx::Display
& DisplayManager::FindDisplayContainingPoint(
367 const gfx::Point
& point_in_screen
) const {
368 for (DisplayList::const_iterator iter
= displays_
.begin();
369 iter
!= displays_
.end(); ++iter
) {
370 const gfx::Display
& display
= *iter
;
371 if (display
.bounds().Contains(point_in_screen
))
374 return GetInvalidDisplay();
377 bool DisplayManager::UpdateWorkAreaOfDisplay(int64 display_id
,
378 const gfx::Insets
& insets
) {
379 gfx::Display
* display
= FindDisplayForId(display_id
);
381 gfx::Rect old_work_area
= display
->work_area();
382 display
->UpdateWorkAreaFromInsets(insets
);
383 return old_work_area
!= display
->work_area();
386 void DisplayManager::SetOverscanInsets(int64 display_id
,
387 const gfx::Insets
& insets_in_dip
) {
388 display_info_
[display_id
].SetOverscanInsets(insets_in_dip
);
389 DisplayInfoList display_info_list
;
390 for (DisplayList::const_iterator iter
= displays_
.begin();
391 iter
!= displays_
.end(); ++iter
) {
392 display_info_list
.push_back(GetDisplayInfo(iter
->id()));
394 AddMirrorDisplayInfoIfAny(&display_info_list
);
395 UpdateDisplays(display_info_list
);
398 void DisplayManager::SetDisplayRotation(int64 display_id
,
399 gfx::Display::Rotation rotation
) {
400 DisplayInfoList display_info_list
;
401 for (DisplayList::const_iterator iter
= displays_
.begin();
402 iter
!= displays_
.end(); ++iter
) {
403 DisplayInfo info
= GetDisplayInfo(iter
->id());
404 if (info
.id() == display_id
) {
405 if (info
.rotation() == rotation
)
407 info
.set_rotation(rotation
);
409 display_info_list
.push_back(info
);
411 AddMirrorDisplayInfoIfAny(&display_info_list
);
412 if (virtual_keyboard_root_window_enabled() &&
413 display_id
== non_desktop_display_
.id()) {
414 DisplayInfo info
= GetDisplayInfo(display_id
);
415 info
.set_rotation(rotation
);
416 display_info_list
.push_back(info
);
418 UpdateDisplays(display_info_list
);
421 void DisplayManager::SetDisplayUIScale(int64 display_id
,
423 if (!IsDisplayUIScalingEnabled() ||
424 gfx::Display::InternalDisplayId() != display_id
) {
428 DisplayInfoList display_info_list
;
429 for (DisplayList::const_iterator iter
= displays_
.begin();
430 iter
!= displays_
.end(); ++iter
) {
431 DisplayInfo info
= GetDisplayInfo(iter
->id());
432 if (info
.id() == display_id
) {
433 if (info
.configured_ui_scale() == ui_scale
)
435 std::vector
<float> scales
= GetScalesForDisplay(info
);
436 ScaleComparator
comparator(ui_scale
);
437 if (std::find_if(scales
.begin(), scales
.end(), comparator
) ==
441 info
.set_configured_ui_scale(ui_scale
);
443 display_info_list
.push_back(info
);
445 AddMirrorDisplayInfoIfAny(&display_info_list
);
446 UpdateDisplays(display_info_list
);
449 void DisplayManager::SetDisplayResolution(int64 display_id
,
450 const gfx::Size
& resolution
) {
451 DCHECK_NE(gfx::Display::InternalDisplayId(), display_id
);
452 if (gfx::Display::InternalDisplayId() == display_id
)
454 const DisplayInfo
& display_info
= GetDisplayInfo(display_id
);
455 const std::vector
<DisplayMode
>& modes
= display_info
.display_modes();
456 DCHECK_NE(0u, modes
.size());
457 std::vector
<DisplayMode
>::const_iterator iter
=
458 std::find_if(modes
.begin(), modes
.end(), DisplayModeMatcher(resolution
));
459 if (iter
== modes
.end()) {
460 LOG(WARNING
) << "Unsupported resolution was requested:"
461 << resolution
.ToString();
464 display_modes_
[display_id
] = *iter
;
465 #if defined(OS_CHROMEOS)
466 if (base::SysInfo::IsRunningOnChromeOS())
467 Shell::GetInstance()->display_configurator()->OnConfigurationChanged();
471 void DisplayManager::RegisterDisplayProperty(
473 gfx::Display::Rotation rotation
,
475 const gfx::Insets
* overscan_insets
,
476 const gfx::Size
& resolution_in_pixels
,
477 ui::ColorCalibrationProfile color_profile
) {
478 if (display_info_
.find(display_id
) == display_info_
.end())
479 display_info_
[display_id
] = DisplayInfo(display_id
, std::string(), false);
481 display_info_
[display_id
].set_rotation(rotation
);
482 display_info_
[display_id
].SetColorProfile(color_profile
);
483 // Just in case the preference file was corrupted.
484 if (0.5f
<= ui_scale
&& ui_scale
<= 2.0f
)
485 display_info_
[display_id
].set_configured_ui_scale(ui_scale
);
487 display_info_
[display_id
].SetOverscanInsets(*overscan_insets
);
488 if (!resolution_in_pixels
.IsEmpty()) {
489 // Default refresh rate, until OnNativeDisplaysChanged() updates us with the
490 // actual display info, is 60 Hz.
491 display_modes_
[display_id
] =
492 DisplayMode(resolution_in_pixels
, 60.0f
, false, false);
496 bool DisplayManager::GetSelectedModeForDisplayId(int64 id
,
497 DisplayMode
* mode_out
) const {
498 std::map
<int64
, DisplayMode
>::const_iterator iter
= display_modes_
.find(id
);
499 if (iter
== display_modes_
.end())
501 *mode_out
= iter
->second
;
505 bool DisplayManager::IsDisplayUIScalingEnabled() const {
506 return GetDisplayIdForUIScaling() != gfx::Display::kInvalidDisplayID
;
509 gfx::Insets
DisplayManager::GetOverscanInsets(int64 display_id
) const {
510 std::map
<int64
, DisplayInfo
>::const_iterator it
=
511 display_info_
.find(display_id
);
512 return (it
!= display_info_
.end()) ?
513 it
->second
.overscan_insets_in_dip() : gfx::Insets();
516 void DisplayManager::SetColorCalibrationProfile(
518 ui::ColorCalibrationProfile profile
) {
519 #if defined(OS_CHROMEOS)
520 if (!display_info_
[display_id
].IsColorProfileAvailable(profile
))
524 delegate_
->PreDisplayConfigurationChange(false);
525 // Just sets color profile if it's not running on ChromeOS (like tests).
526 if (!base::SysInfo::IsRunningOnChromeOS() ||
527 Shell::GetInstance()->display_configurator()->SetColorCalibrationProfile(
528 display_id
, profile
)) {
529 display_info_
[display_id
].SetColorProfile(profile
);
530 UMA_HISTOGRAM_ENUMERATION(
531 "ChromeOS.Display.ColorProfile", profile
, ui::NUM_COLOR_PROFILES
);
534 delegate_
->PostDisplayConfigurationChange();
538 void DisplayManager::OnNativeDisplaysChanged(
539 const std::vector
<DisplayInfo
>& updated_displays
) {
540 if (updated_displays
.empty()) {
541 VLOG(1) << "OnNativeDisplayChanged(0): # of current displays="
543 // If the device is booted without display, or chrome is started
544 // without --ash-host-window-bounds on linux desktop, use the
546 if (displays_
.empty()) {
547 std::vector
<DisplayInfo
> init_displays
;
548 init_displays
.push_back(DisplayInfo::CreateFromSpec(std::string()));
549 MaybeInitInternalDisplay(init_displays
[0].id());
550 OnNativeDisplaysChanged(init_displays
);
552 // Otherwise don't update the displays when all displays are disconnected.
553 // This happens when:
554 // - the device is idle and powerd requested to turn off all displays.
555 // - the device is suspended. (kernel turns off all displays)
556 // - the internal display's brightness is set to 0 and no external
557 // display is connected.
558 // - the internal display's brightness is 0 and external display is
560 // The display will be updated when one of displays is turned on, and the
561 // display list will be updated correctly.
565 first_display_id_
= updated_displays
[0].id();
566 std::set
<gfx::Point
> origins
;
568 if (updated_displays
.size() == 1) {
569 VLOG(1) << "OnNativeDisplaysChanged(1):" << updated_displays
[0].ToString();
571 VLOG(1) << "OnNativeDisplaysChanged(" << updated_displays
.size()
572 << ") [0]=" << updated_displays
[0].ToString()
573 << ", [1]=" << updated_displays
[1].ToString();
576 bool internal_display_connected
= false;
577 num_connected_displays_
= updated_displays
.size();
578 mirrored_display_id_
= gfx::Display::kInvalidDisplayID
;
579 non_desktop_display_
= gfx::Display();
580 DisplayInfoList new_display_info_list
;
581 for (DisplayInfoList::const_iterator iter
= updated_displays
.begin();
582 iter
!= updated_displays
.end();
584 if (!internal_display_connected
)
585 internal_display_connected
= IsInternalDisplayId(iter
->id());
586 // Mirrored monitors have the same origins.
587 gfx::Point origin
= iter
->bounds_in_native().origin();
588 if (origins
.find(origin
) != origins
.end()) {
589 InsertAndUpdateDisplayInfo(*iter
);
590 mirrored_display_id_
= iter
->id();
592 origins
.insert(origin
);
593 new_display_info_list
.push_back(*iter
);
596 const gfx::Size
& resolution
= iter
->bounds_in_native().size();
597 const std::vector
<DisplayMode
>& display_modes
= iter
->display_modes();
598 // This is empty the displays are initialized from InitFromCommandLine.
599 if (!display_modes
.size())
601 std::vector
<DisplayMode
>::const_iterator display_modes_iter
=
602 std::find_if(display_modes
.begin(),
604 DisplayModeMatcher(resolution
));
605 // Update the actual resolution selected as the resolution request may fail.
606 if (display_modes_iter
== display_modes
.end())
607 display_modes_
.erase(iter
->id());
608 else if (display_modes_
.find(iter
->id()) != display_modes_
.end())
609 display_modes_
[iter
->id()] = *display_modes_iter
;
611 if (HasInternalDisplay() &&
612 !internal_display_connected
&&
613 display_info_
.find(gfx::Display::InternalDisplayId()) ==
614 display_info_
.end()) {
615 DisplayInfo
internal_display_info(
616 gfx::Display::InternalDisplayId(),
617 l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME
),
618 false /*Internal display must not have overscan */);
619 internal_display_info
.SetBounds(gfx::Rect(0, 0, 800, 600));
620 display_info_
[gfx::Display::InternalDisplayId()] = internal_display_info
;
622 UpdateDisplays(new_display_info_list
);
625 void DisplayManager::UpdateDisplays() {
626 DisplayInfoList display_info_list
;
627 for (DisplayList::const_iterator iter
= displays_
.begin();
628 iter
!= displays_
.end(); ++iter
) {
629 display_info_list
.push_back(GetDisplayInfo(iter
->id()));
631 AddMirrorDisplayInfoIfAny(&display_info_list
);
632 UpdateDisplays(display_info_list
);
635 void DisplayManager::UpdateDisplays(
636 const std::vector
<DisplayInfo
>& updated_display_info_list
) {
638 DCHECK_EQ(1u, updated_display_info_list
.size()) <<
639 ": Multiple display test does not work on Windows bots. Please "
640 "skip (don't disable) the test using SupportsMultipleDisplays()";
643 DisplayInfoList new_display_info_list
= updated_display_info_list
;
644 std::sort(displays_
.begin(), displays_
.end(), DisplaySortFunctor());
645 std::sort(new_display_info_list
.begin(),
646 new_display_info_list
.end(),
647 DisplayInfoSortFunctor());
648 DisplayList removed_displays
;
649 std::map
<size_t, uint32_t> display_changes
;
650 std::vector
<size_t> added_display_indices
;
652 DisplayList::iterator curr_iter
= displays_
.begin();
653 DisplayInfoList::const_iterator new_info_iter
= new_display_info_list
.begin();
655 DisplayList new_displays
;
657 // Use the internal display or 1st as the mirror source, then scale
658 // the root window so that it matches the external display's
659 // resolution. This is necessary in order for scaling to work while
661 int64 non_desktop_display_id
= gfx::Display::kInvalidDisplayID
;
663 if (second_display_mode_
!= EXTENDED
&& new_display_info_list
.size() == 2) {
664 bool zero_is_source
=
665 first_display_id_
== new_display_info_list
[0].id() ||
666 gfx::Display::InternalDisplayId() == new_display_info_list
[0].id();
667 if (second_display_mode_
== MIRRORING
) {
668 mirrored_display_id_
= new_display_info_list
[zero_is_source
? 1 : 0].id();
669 non_desktop_display_id
= mirrored_display_id_
;
671 // TODO(oshima|bshe): The virtual keyboard is currently assigned to
673 non_desktop_display_id
=
674 new_display_info_list
[zero_is_source
? 0 : 1].id();
678 while (curr_iter
!= displays_
.end() ||
679 new_info_iter
!= new_display_info_list
.end()) {
680 if (new_info_iter
!= new_display_info_list
.end() &&
681 non_desktop_display_id
== new_info_iter
->id()) {
682 DisplayInfo info
= *new_info_iter
;
683 info
.SetOverscanInsets(gfx::Insets());
684 InsertAndUpdateDisplayInfo(info
);
685 non_desktop_display_
=
686 CreateDisplayFromDisplayInfoById(non_desktop_display_id
);
688 // Remove existing external display if it is going to be used as
690 if (curr_iter
!= displays_
.end() &&
691 curr_iter
->id() == non_desktop_display_id
) {
692 removed_displays
.push_back(*curr_iter
);
698 if (curr_iter
== displays_
.end()) {
699 // more displays in new list.
700 added_display_indices
.push_back(new_displays
.size());
701 InsertAndUpdateDisplayInfo(*new_info_iter
);
702 new_displays
.push_back(
703 CreateDisplayFromDisplayInfoById(new_info_iter
->id()));
705 } else if (new_info_iter
== new_display_info_list
.end()) {
706 // more displays in current list.
707 removed_displays
.push_back(*curr_iter
);
709 } else if (curr_iter
->id() == new_info_iter
->id()) {
710 const gfx::Display
& current_display
= *curr_iter
;
711 // Copy the info because |CreateDisplayFromInfo| updates the instance.
712 const DisplayInfo current_display_info
=
713 GetDisplayInfo(current_display
.id());
714 InsertAndUpdateDisplayInfo(*new_info_iter
);
715 gfx::Display new_display
=
716 CreateDisplayFromDisplayInfoById(new_info_iter
->id());
717 const DisplayInfo
& new_display_info
= GetDisplayInfo(new_display
.id());
719 uint32_t metrics
= gfx::DisplayObserver::DISPLAY_METRIC_NONE
;
721 // At that point the new Display objects we have are not entirely updated,
722 // they are missing the translation related to the Display disposition in
724 // Using display.bounds() and display.work_area() would fail most of the
726 if (force_bounds_changed_
|| (current_display_info
.bounds_in_native() !=
727 new_display_info
.bounds_in_native()) ||
728 (current_display_info
.size_in_pixel() !=
729 new_display
.GetSizeInPixel())) {
730 metrics
|= gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS
|
731 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA
;
734 if (current_display
.device_scale_factor() !=
735 new_display
.device_scale_factor()) {
736 metrics
|= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR
;
739 if (current_display
.rotation() != new_display
.rotation())
740 metrics
|= gfx::DisplayObserver::DISPLAY_METRIC_ROTATION
;
742 if (metrics
!= gfx::DisplayObserver::DISPLAY_METRIC_NONE
) {
743 display_changes
.insert(
744 std::pair
<size_t, uint32_t>(new_displays
.size(), metrics
));
747 new_display
.UpdateWorkAreaFromInsets(current_display
.GetWorkAreaInsets());
748 new_displays
.push_back(new_display
);
751 } else if (curr_iter
->id() < new_info_iter
->id()) {
752 // more displays in current list between ids, which means it is deleted.
753 removed_displays
.push_back(*curr_iter
);
756 // more displays in new list between ids, which means it is added.
757 added_display_indices
.push_back(new_displays
.size());
758 InsertAndUpdateDisplayInfo(*new_info_iter
);
759 new_displays
.push_back(
760 CreateDisplayFromDisplayInfoById(new_info_iter
->id()));
765 scoped_ptr
<NonDesktopDisplayUpdater
> non_desktop_display_updater(
766 new NonDesktopDisplayUpdater(this, delegate_
));
768 // Do not update |displays_| if there's nothing to be updated. Without this,
769 // it will not update the display layout, which causes the bug
770 // http://crbug.com/155948.
771 if (display_changes
.empty() && added_display_indices
.empty() &&
772 removed_displays
.empty()) {
775 // Clear focus if the display has been removed, but don't clear focus if
776 // the destkop has been moved from one display to another
777 // (mirror -> docked, docked -> single internal).
779 !removed_displays
.empty() &&
780 !(removed_displays
.size() == 1 && added_display_indices
.size() == 1);
782 delegate_
->PreDisplayConfigurationChange(clear_focus
);
784 size_t updated_index
;
785 if (UpdateSecondaryDisplayBoundsForLayout(&new_displays
, &updated_index
) &&
786 std::find(added_display_indices
.begin(),
787 added_display_indices
.end(),
788 updated_index
) == added_display_indices
.end()) {
789 uint32_t metrics
= gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS
|
790 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA
;
791 if (display_changes
.find(updated_index
) != display_changes
.end())
792 metrics
|= display_changes
[updated_index
];
794 display_changes
[updated_index
] = metrics
;
797 displays_
= new_displays
;
799 base::AutoReset
<bool> resetter(&change_display_upon_host_resize_
, false);
801 // Temporarily add displays to be removed because display object
802 // being removed are accessed during shutting down the root.
803 displays_
.insert(displays_
.end(), removed_displays
.begin(),
804 removed_displays
.end());
806 for (DisplayList::const_reverse_iterator iter
= removed_displays
.rbegin();
807 iter
!= removed_displays
.rend(); ++iter
) {
808 screen_ash_
->NotifyDisplayRemoved(displays_
.back());
809 displays_
.pop_back();
811 // Close the non desktop window here to avoid creating two compositor on
813 if (!non_desktop_display_updater
->enabled())
814 non_desktop_display_updater
.reset();
815 for (std::vector
<size_t>::iterator iter
= added_display_indices
.begin();
816 iter
!= added_display_indices
.end(); ++iter
) {
817 screen_ash_
->NotifyDisplayAdded(displays_
[*iter
]);
819 // Create the non destkop window after all displays are added so that
820 // it can mirror the display newly added. This can happen when switching
821 // from dock mode to software mirror mode.
822 non_desktop_display_updater
.reset();
823 for (std::map
<size_t, uint32_t>::iterator iter
= display_changes
.begin();
824 iter
!= display_changes
.end();
826 screen_ash_
->NotifyMetricsChanged(displays_
[iter
->first
], iter
->second
);
829 delegate_
->PostDisplayConfigurationChange();
831 #if defined(USE_X11) && defined(OS_CHROMEOS)
832 if (!display_changes
.empty() && base::SysInfo::IsRunningOnChromeOS())
833 ui::ClearX11DefaultRootWindow();
837 const gfx::Display
& DisplayManager::GetDisplayAt(size_t index
) const {
838 DCHECK_LT(index
, displays_
.size());
839 return displays_
[index
];
842 const gfx::Display
& DisplayManager::GetPrimaryDisplayCandidate() const {
843 if (GetNumDisplays() == 1)
845 DisplayLayout layout
= layout_store_
->GetRegisteredDisplayLayout(
846 GetCurrentDisplayIdPair());
847 return GetDisplayForId(layout
.primary_id
);
850 size_t DisplayManager::GetNumDisplays() const {
851 return displays_
.size();
854 bool DisplayManager::IsMirrored() const {
855 return mirrored_display_id_
!= gfx::Display::kInvalidDisplayID
;
858 const DisplayInfo
& DisplayManager::GetDisplayInfo(int64 display_id
) const {
859 DCHECK_NE(gfx::Display::kInvalidDisplayID
, display_id
);
861 std::map
<int64
, DisplayInfo
>::const_iterator iter
=
862 display_info_
.find(display_id
);
863 CHECK(iter
!= display_info_
.end()) << display_id
;
867 std::string
DisplayManager::GetDisplayNameForId(int64 id
) {
868 if (id
== gfx::Display::kInvalidDisplayID
)
869 return l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME
);
871 std::map
<int64
, DisplayInfo
>::const_iterator iter
= display_info_
.find(id
);
872 if (iter
!= display_info_
.end() && !iter
->second
.name().empty())
873 return iter
->second
.name();
875 return base::StringPrintf("Display %d", static_cast<int>(id
));
878 int64
DisplayManager::GetDisplayIdForUIScaling() const {
879 // UI Scaling is effective only on internal display.
880 int64 display_id
= gfx::Display::InternalDisplayId();
882 display_id
= first_display_id();
887 void DisplayManager::SetMirrorMode(bool mirrored
) {
888 if (num_connected_displays() <= 1)
891 #if defined(OS_CHROMEOS)
892 if (base::SysInfo::IsRunningOnChromeOS()) {
893 ui::MultipleDisplayState new_state
=
894 mirrored
? ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR
:
895 ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED
;
896 Shell::GetInstance()->display_configurator()->SetDisplayMode(new_state
);
900 // This is fallback path to emulate mirroroing on desktop.
901 SetSecondDisplayMode(mirrored
? MIRRORING
: EXTENDED
);
902 DisplayInfoList display_info_list
;
904 for (std::map
<int64
, DisplayInfo
>::const_iterator iter
=
905 display_info_
.begin();
906 count
< 2; ++iter
, ++count
) {
907 display_info_list
.push_back(GetDisplayInfo(iter
->second
.id()));
909 UpdateDisplays(display_info_list
);
910 #if defined(OS_CHROMEOS)
911 if (Shell::GetInstance()->display_configurator_animation()) {
912 Shell::GetInstance()->display_configurator_animation()->
913 StartFadeInAnimation();
918 void DisplayManager::AddRemoveDisplay() {
919 DCHECK(!displays_
.empty());
920 std::vector
<DisplayInfo
> new_display_info_list
;
921 const DisplayInfo
& first_display
= GetDisplayInfo(displays_
[0].id());
922 new_display_info_list
.push_back(first_display
);
923 // Add if there is only one display connected.
924 if (num_connected_displays() == 1) {
925 // Layout the 2nd display below the primary as with the real device.
926 gfx::Rect host_bounds
= first_display
.bounds_in_native();
927 new_display_info_list
.push_back(DisplayInfo::CreateFromSpec(
929 "%d+%d-500x400", host_bounds
.x(), host_bounds
.bottom())));
931 num_connected_displays_
= new_display_info_list
.size();
932 mirrored_display_id_
= gfx::Display::kInvalidDisplayID
;
933 non_desktop_display_
= gfx::Display();
934 UpdateDisplays(new_display_info_list
);
937 void DisplayManager::ToggleDisplayScaleFactor() {
938 DCHECK(!displays_
.empty());
939 std::vector
<DisplayInfo
> new_display_info_list
;
940 for (DisplayList::const_iterator iter
= displays_
.begin();
941 iter
!= displays_
.end(); ++iter
) {
942 DisplayInfo display_info
= GetDisplayInfo(iter
->id());
943 display_info
.set_device_scale_factor(
944 display_info
.device_scale_factor() == 1.0f
? 2.0f
: 1.0f
);
945 new_display_info_list
.push_back(display_info
);
947 AddMirrorDisplayInfoIfAny(&new_display_info_list
);
948 UpdateDisplays(new_display_info_list
);
951 #if defined(OS_CHROMEOS)
952 void DisplayManager::SetSoftwareMirroring(bool enabled
) {
953 // TODO(oshima|bshe): Support external display on the system
954 // that has virtual keyboard display.
955 if (second_display_mode_
== VIRTUAL_KEYBOARD
)
957 SetSecondDisplayMode(enabled
? MIRRORING
: EXTENDED
);
960 bool DisplayManager::SoftwareMirroringEnabled() const {
961 return software_mirroring_enabled();
965 void DisplayManager::SetSecondDisplayMode(SecondDisplayMode mode
) {
966 second_display_mode_
= mode
;
967 mirrored_display_id_
= gfx::Display::kInvalidDisplayID
;
968 non_desktop_display_
= gfx::Display();
971 bool DisplayManager::UpdateDisplayBounds(int64 display_id
,
972 const gfx::Rect
& new_bounds
) {
973 if (change_display_upon_host_resize_
) {
974 display_info_
[display_id
].SetBounds(new_bounds
);
975 // Don't notify observers if the mirrored window has changed.
976 if (software_mirroring_enabled() && mirrored_display_id_
== display_id
)
978 gfx::Display
* display
= FindDisplayForId(display_id
);
979 display
->SetSize(display_info_
[display_id
].size_in_pixel());
980 screen_ash_
->NotifyMetricsChanged(
981 *display
, gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS
);
987 void DisplayManager::CreateMirrorWindowIfAny() {
988 NonDesktopDisplayUpdater
updater(this, delegate_
);
991 void DisplayManager::CreateScreenForShutdown() const {
993 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE
) ==
995 delete screen_for_shutdown
;
996 screen_for_shutdown
= screen_ash_
->CloneForShutdown();
997 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE
,
998 screen_for_shutdown
);
1000 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE
,
1001 screen_for_shutdown
);
1005 gfx::Display
* DisplayManager::FindDisplayForId(int64 id
) {
1006 for (DisplayList::iterator iter
= displays_
.begin();
1007 iter
!= displays_
.end(); ++iter
) {
1008 if ((*iter
).id() == id
)
1011 DLOG(WARNING
) << "Could not find display:" << id
;
1015 void DisplayManager::AddMirrorDisplayInfoIfAny(
1016 std::vector
<DisplayInfo
>* display_info_list
) {
1017 if (software_mirroring_enabled() && IsMirrored())
1018 display_info_list
->push_back(GetDisplayInfo(mirrored_display_id_
));
1021 void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo
& new_info
) {
1022 std::map
<int64
, DisplayInfo
>::iterator info
=
1023 display_info_
.find(new_info
.id());
1024 if (info
!= display_info_
.end()) {
1025 info
->second
.Copy(new_info
);
1027 display_info_
[new_info
.id()] = new_info
;
1028 display_info_
[new_info
.id()].set_native(false);
1030 display_info_
[new_info
.id()].UpdateDisplaySize();
1032 OnDisplayInfoUpdated(display_info_
[new_info
.id()]);
1035 void DisplayManager::OnDisplayInfoUpdated(const DisplayInfo
& display_info
) {
1036 #if defined(OS_CHROMEOS)
1037 ui::ColorCalibrationProfile color_profile
= display_info
.color_profile();
1038 if (color_profile
!= ui::COLOR_PROFILE_STANDARD
) {
1039 Shell::GetInstance()->display_configurator()->SetColorCalibrationProfile(
1040 display_info
.id(), color_profile
);
1045 gfx::Display
DisplayManager::CreateDisplayFromDisplayInfoById(int64 id
) {
1046 DCHECK(display_info_
.find(id
) != display_info_
.end());
1047 const DisplayInfo
& display_info
= display_info_
[id
];
1049 gfx::Display
new_display(display_info
.id());
1050 gfx::Rect
bounds_in_native(display_info
.size_in_pixel());
1051 float device_scale_factor
= display_info
.GetEffectiveDeviceScaleFactor();
1053 // Simply set the origin to (0,0). The primary display's origin is
1054 // always (0,0) and the secondary display's bounds will be updated
1055 // in |UpdateSecondaryDisplayBoundsForLayout| called in |UpdateDisplay|.
1056 new_display
.SetScaleAndBounds(
1057 device_scale_factor
, gfx::Rect(bounds_in_native
.size()));
1058 new_display
.set_rotation(display_info
.rotation());
1059 new_display
.set_touch_support(display_info
.touch_support());
1063 bool DisplayManager::UpdateSecondaryDisplayBoundsForLayout(
1064 DisplayList
* displays
,
1065 size_t* updated_index
) const {
1066 if (displays
->size() != 2U)
1069 int64 id_at_zero
= displays
->at(0).id();
1070 DisplayIdPair pair
=
1071 (id_at_zero
== first_display_id_
||
1072 id_at_zero
== gfx::Display::InternalDisplayId()) ?
1073 std::make_pair(id_at_zero
, displays
->at(1).id()) :
1074 std::make_pair(displays
->at(1).id(), id_at_zero
);
1075 DisplayLayout layout
=
1076 layout_store_
->ComputeDisplayLayoutForDisplayIdPair(pair
);
1078 // Ignore if a user has a old format (should be extremely rare)
1079 // and this will be replaced with DCHECK.
1080 if (layout
.primary_id
!= gfx::Display::kInvalidDisplayID
) {
1081 size_t primary_index
, secondary_index
;
1082 if (displays
->at(0).id() == layout
.primary_id
) {
1084 secondary_index
= 1;
1087 secondary_index
= 0;
1089 // This function may be called before the secondary display is
1090 // registered. The bounds is empty in that case and will
1093 GetDisplayForId(displays
->at(secondary_index
).id()).bounds();
1094 UpdateDisplayBoundsForLayout(
1095 layout
, displays
->at(primary_index
), &displays
->at(secondary_index
));
1096 *updated_index
= secondary_index
;
1097 return bounds
!= displays
->at(secondary_index
).bounds();
1103 void DisplayManager::UpdateDisplayBoundsForLayout(
1104 const DisplayLayout
& layout
,
1105 const gfx::Display
& primary_display
,
1106 gfx::Display
* secondary_display
) {
1107 DCHECK_EQ("0,0", primary_display
.bounds().origin().ToString());
1109 const gfx::Rect
& primary_bounds
= primary_display
.bounds();
1110 const gfx::Rect
& secondary_bounds
= secondary_display
->bounds();
1111 gfx::Point new_secondary_origin
= primary_bounds
.origin();
1113 DisplayLayout::Position position
= layout
.position
;
1115 // Ignore the offset in case the secondary display doesn't share edges with
1116 // the primary display.
1117 int offset
= layout
.offset
;
1118 if (position
== DisplayLayout::TOP
|| position
== DisplayLayout::BOTTOM
) {
1120 offset
, primary_bounds
.width() - kMinimumOverlapForInvalidOffset
);
1122 offset
, -secondary_bounds
.width() + kMinimumOverlapForInvalidOffset
);
1125 offset
, primary_bounds
.height() - kMinimumOverlapForInvalidOffset
);
1127 offset
, -secondary_bounds
.height() + kMinimumOverlapForInvalidOffset
);
1130 case DisplayLayout::TOP
:
1131 new_secondary_origin
.Offset(offset
, -secondary_bounds
.height());
1133 case DisplayLayout::RIGHT
:
1134 new_secondary_origin
.Offset(primary_bounds
.width(), offset
);
1136 case DisplayLayout::BOTTOM
:
1137 new_secondary_origin
.Offset(offset
, primary_bounds
.height());
1139 case DisplayLayout::LEFT
:
1140 new_secondary_origin
.Offset(-secondary_bounds
.width(), offset
);
1143 gfx::Insets insets
= secondary_display
->GetWorkAreaInsets();
1144 secondary_display
->set_bounds(
1145 gfx::Rect(new_secondary_origin
, secondary_bounds
.size()));
1146 secondary_display
->UpdateWorkAreaFromInsets(insets
);