Introduce about flags for chrome hosted mode
[chromium-blink-merge.git] / ash / display / display_manager.cc
blob92c0f59f5966f78a81f058e788c52ed392615ba0
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 <algorithm>
8 #include <cmath>
9 #include <set>
10 #include <string>
11 #include <vector>
13 #include "ash/ash_switches.h"
14 #include "ash/display/display_layout_store.h"
15 #include "ash/display/display_util.h"
16 #include "ash/display/extended_mouse_warp_controller.h"
17 #include "ash/display/null_mouse_warp_controller.h"
18 #include "ash/display/screen_ash.h"
19 #include "ash/display/unified_mouse_warp_controller.h"
20 #include "ash/screen_util.h"
21 #include "ash/shell.h"
22 #include "base/auto_reset.h"
23 #include "base/command_line.h"
24 #include "base/logging.h"
25 #include "base/metrics/histogram.h"
26 #include "base/run_loop.h"
27 #include "base/strings/string_number_conversions.h"
28 #include "base/strings/string_split.h"
29 #include "base/strings/stringprintf.h"
30 #include "base/strings/utf_string_conversions.h"
31 #include "grit/ash_strings.h"
32 #include "ui/base/l10n/l10n_util.h"
33 #include "ui/gfx/display.h"
34 #include "ui/gfx/display_observer.h"
35 #include "ui/gfx/font_render_params.h"
36 #include "ui/gfx/geometry/rect.h"
37 #include "ui/gfx/geometry/size_conversions.h"
38 #include "ui/gfx/screen.h"
40 #if defined(USE_X11)
41 #include "ui/base/x/x11_util.h"
42 #endif
44 #if defined(OS_CHROMEOS)
45 #include "ash/display/display_configurator_animation.h"
46 #include "base/sys_info.h"
47 #endif
49 #if defined(OS_WIN)
50 #include "base/win/windows_version.h"
51 #endif
53 #include "base/debug/stack_trace.h"
55 namespace ash {
56 typedef std::vector<gfx::Display> DisplayList;
57 typedef std::vector<DisplayInfo> DisplayInfoList;
59 namespace {
61 // We need to keep this in order for unittests to tell if
62 // the object in gfx::Screen::GetScreenByType is for shutdown.
63 gfx::Screen* screen_for_shutdown = NULL;
65 // The number of pixels to overlap between the primary and secondary displays,
66 // in case that the offset value is too large.
67 const int kMinimumOverlapForInvalidOffset = 100;
69 struct DisplaySortFunctor {
70 bool operator()(const gfx::Display& a, const gfx::Display& b) {
71 return a.id() < b.id();
75 struct DisplayInfoSortFunctor {
76 bool operator()(const DisplayInfo& a, const DisplayInfo& b) {
77 return a.id() < b.id();
81 struct DisplayModeMatcher {
82 DisplayModeMatcher(const DisplayMode& target_mode)
83 : target_mode(target_mode) {}
84 bool operator()(const DisplayMode& mode) {
85 return target_mode.IsEquivalent(mode);
87 DisplayMode target_mode;
90 gfx::Display& GetInvalidDisplay() {
91 static gfx::Display* invalid_display = new gfx::Display();
92 return *invalid_display;
95 void SetInternalDisplayModeList(DisplayInfo* info) {
96 DisplayMode native_mode;
97 native_mode.size = info->bounds_in_native().size();
98 native_mode.device_scale_factor = info->device_scale_factor();
99 native_mode.ui_scale = 1.0f;
100 info->SetDisplayModes(CreateInternalDisplayModeList(native_mode));
103 void MaybeInitInternalDisplay(DisplayInfo* info) {
104 int64 id = info->id();
105 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
106 if (command_line->HasSwitch(switches::kAshUseFirstDisplayAsInternal)) {
107 gfx::Display::SetInternalDisplayId(id);
108 SetInternalDisplayModeList(info);
112 bool IsInternalDisplayId(int64 id) {
113 return gfx::Display::InternalDisplayId() == id;
116 } // namespace
118 using std::string;
119 using std::vector;
121 // static
122 int64 DisplayManager::kUnifiedDisplayId = -10;
124 DisplayManager::DisplayManager()
125 : delegate_(NULL),
126 screen_(new ScreenAsh),
127 layout_store_(new DisplayLayoutStore),
128 first_display_id_(gfx::Display::kInvalidDisplayID),
129 num_connected_displays_(0),
130 force_bounds_changed_(false),
131 change_display_upon_host_resize_(false),
132 multi_display_mode_(EXTENDED),
133 default_multi_display_mode_(EXTENDED),
134 mirroring_display_id_(gfx::Display::kInvalidDisplayID),
135 registered_internal_display_rotation_lock_(false),
136 registered_internal_display_rotation_(gfx::Display::ROTATE_0),
137 weak_ptr_factory_(this) {
138 #if defined(OS_CHROMEOS)
139 // Enable only on the device so that DisplayManagerFontTest passes.
140 if (base::SysInfo::IsRunningOnChromeOS())
141 DisplayInfo::SetUse125DSFForUIScaling(true);
143 if (switches::UnifiedDesktopEnabled())
144 default_multi_display_mode_ = UNIFIED;
146 change_display_upon_host_resize_ = !base::SysInfo::IsRunningOnChromeOS();
147 #endif
148 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE, screen_.get());
149 gfx::Screen* current_native =
150 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE);
151 // If there is no native, or the native was for shutdown,
152 // use ash's screen.
153 if (!current_native ||
154 current_native == screen_for_shutdown) {
155 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, screen_.get());
159 DisplayManager::~DisplayManager() {
160 #if defined(OS_CHROMEOS)
161 // Reset the font params.
162 gfx::SetFontRenderParamsDeviceScaleFactor(1.0f);
163 #endif
166 bool DisplayManager::InitFromCommandLine() {
167 DisplayInfoList info_list;
168 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
169 if (!command_line->HasSwitch(switches::kAshHostWindowBounds))
170 return false;
171 const string size_str =
172 command_line->GetSwitchValueASCII(switches::kAshHostWindowBounds);
173 vector<string> parts;
174 base::SplitString(size_str, ',', &parts);
175 for (vector<string>::const_iterator iter = parts.begin();
176 iter != parts.end(); ++iter) {
177 info_list.push_back(DisplayInfo::CreateFromSpec(*iter));
178 info_list.back().set_native(true);
180 MaybeInitInternalDisplay(&info_list[0]);
181 if (info_list.size() > 1 &&
182 command_line->HasSwitch(switches::kAshEnableSoftwareMirroring)) {
183 SetMultiDisplayMode(MIRRORING);
185 OnNativeDisplaysChanged(info_list);
186 return true;
189 void DisplayManager::InitDefaultDisplay() {
190 DisplayInfoList info_list;
191 info_list.push_back(DisplayInfo::CreateFromSpec(std::string()));
192 info_list.back().set_native(true);
193 MaybeInitInternalDisplay(&info_list[0]);
194 OnNativeDisplaysChanged(info_list);
197 void DisplayManager::RefreshFontParams() {
198 #if defined(OS_CHROMEOS)
199 // Use the largest device scale factor among currently active displays. Non
200 // internal display may have bigger scale factor in case the external display
201 // is an 4K display.
202 float largest_device_scale_factor = 1.0f;
203 for (const gfx::Display& display : active_display_list_) {
204 const ash::DisplayInfo& info = display_info_[display.id()];
205 largest_device_scale_factor = std::max(
206 largest_device_scale_factor, info.GetEffectiveDeviceScaleFactor());
208 gfx::SetFontRenderParamsDeviceScaleFactor(largest_device_scale_factor);
209 #endif // OS_CHROMEOS
212 DisplayLayout DisplayManager::GetCurrentDisplayLayout() {
213 DCHECK_LE(2U, num_connected_displays());
214 // Invert if the primary was swapped.
215 if (num_connected_displays() == 2) {
216 DisplayIdPair pair = GetCurrentDisplayIdPair();
217 return layout_store_->ComputeDisplayLayoutForDisplayIdPair(pair);
218 } else if (num_connected_displays() > 2) {
219 // Return fixed horizontal layout for >= 3 displays.
220 DisplayLayout layout(DisplayLayout::RIGHT, 0);
221 return layout;
223 NOTREACHED() << "DisplayLayout is requested for single display";
224 // On release build, just fallback to default instead of blowing up.
225 DisplayLayout layout =
226 layout_store_->default_display_layout();
227 layout.primary_id = active_display_list_[0].id();
228 return layout;
231 DisplayIdPair DisplayManager::GetCurrentDisplayIdPair() const {
232 if (IsInUnifiedMode()) {
233 return std::make_pair(software_mirroring_display_list_[0].id(),
234 software_mirroring_display_list_[1].id());
235 } else if (IsInMirrorMode()) {
236 if (software_mirroring_enabled()) {
237 CHECK_EQ(2u, num_connected_displays());
238 // This comment is to make it easy to distinguish the crash
239 // between two checks.
240 CHECK_EQ(1u, active_display_list_.size());
242 return std::make_pair(active_display_list_[0].id(), mirroring_display_id_);
243 } else {
244 CHECK_LE(2u, active_display_list_.size());
245 int64 id_at_zero = active_display_list_[0].id();
246 if (id_at_zero == gfx::Display::InternalDisplayId() ||
247 id_at_zero == first_display_id()) {
248 return std::make_pair(id_at_zero, active_display_list_[1].id());
249 } else {
250 return std::make_pair(active_display_list_[1].id(), id_at_zero);
255 void DisplayManager::SetLayoutForCurrentDisplays(
256 const DisplayLayout& layout_relative_to_primary) {
257 if (GetNumDisplays() != 2)
258 return;
259 const gfx::Display& primary = screen_->GetPrimaryDisplay();
260 const DisplayIdPair pair = GetCurrentDisplayIdPair();
261 // Invert if the primary was swapped.
262 DisplayLayout to_set = pair.first == primary.id() ?
263 layout_relative_to_primary : layout_relative_to_primary.Invert();
265 DisplayLayout current_layout =
266 layout_store_->GetRegisteredDisplayLayout(pair);
267 if (to_set.position != current_layout.position ||
268 to_set.offset != current_layout.offset) {
269 to_set.primary_id = primary.id();
270 layout_store_->RegisterLayoutForDisplayIdPair(
271 pair.first, pair.second, to_set);
272 if (delegate_)
273 delegate_->PreDisplayConfigurationChange(false);
274 // PreDisplayConfigurationChange(false);
275 // TODO(oshima): Call UpdateDisplays instead.
276 const DisplayLayout layout = GetCurrentDisplayLayout();
277 UpdateDisplayBoundsForLayout(
278 layout, primary,
279 FindDisplayForId(ScreenUtil::GetSecondaryDisplay().id()));
281 // Primary's bounds stay the same. Just notify bounds change
282 // on the secondary.
283 screen_->NotifyMetricsChanged(
284 ScreenUtil::GetSecondaryDisplay(),
285 gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
286 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
287 if (delegate_)
288 delegate_->PostDisplayConfigurationChange();
292 const gfx::Display& DisplayManager::GetDisplayForId(int64 id) const {
293 gfx::Display* display =
294 const_cast<DisplayManager*>(this)->FindDisplayForId(id);
295 return display ? *display : GetInvalidDisplay();
298 const gfx::Display& DisplayManager::FindDisplayContainingPoint(
299 const gfx::Point& point_in_screen) const {
300 int index =
301 FindDisplayIndexContainingPoint(active_display_list_, point_in_screen);
302 return index < 0 ? GetInvalidDisplay() : active_display_list_[index];
305 bool DisplayManager::UpdateWorkAreaOfDisplay(int64 display_id,
306 const gfx::Insets& insets) {
307 gfx::Display* display = FindDisplayForId(display_id);
308 DCHECK(display);
309 gfx::Rect old_work_area = display->work_area();
310 display->UpdateWorkAreaFromInsets(insets);
311 return old_work_area != display->work_area();
314 void DisplayManager::SetOverscanInsets(int64 display_id,
315 const gfx::Insets& insets_in_dip) {
316 bool update = false;
317 DisplayInfoList display_info_list;
318 for (const auto& display : active_display_list_) {
319 DisplayInfo info = GetDisplayInfo(display.id());
320 if (info.id() == display_id) {
321 if (insets_in_dip.empty()) {
322 info.set_clear_overscan_insets(true);
323 } else {
324 info.set_clear_overscan_insets(false);
325 info.SetOverscanInsets(insets_in_dip);
327 update = true;
329 display_info_list.push_back(info);
331 if (update) {
332 AddMirrorDisplayInfoIfAny(&display_info_list);
333 UpdateDisplays(display_info_list);
334 } else {
335 display_info_[display_id].SetOverscanInsets(insets_in_dip);
339 void DisplayManager::SetDisplayRotation(int64 display_id,
340 gfx::Display::Rotation rotation,
341 gfx::Display::RotationSource source) {
342 DisplayInfoList display_info_list;
343 for (const auto& display : active_display_list_) {
344 DisplayInfo info = GetDisplayInfo(display.id());
345 if (info.id() == display_id) {
346 if (info.GetRotation(source) == rotation &&
347 info.GetActiveRotation() == rotation) {
348 return;
350 info.SetRotation(rotation, source);
352 display_info_list.push_back(info);
354 AddMirrorDisplayInfoIfAny(&display_info_list);
355 UpdateDisplays(display_info_list);
358 bool DisplayManager::SetDisplayUIScale(int64 display_id,
359 float ui_scale) {
360 if (!IsDisplayUIScalingEnabled() ||
361 gfx::Display::InternalDisplayId() != display_id) {
362 return false;
364 bool found = false;
365 // TODO(mukai): merge this implementation into SetDisplayMode().
366 DisplayInfoList display_info_list;
367 for (const auto& display : active_display_list_) {
368 DisplayInfo info = GetDisplayInfo(display.id());
369 if (info.id() == display_id) {
370 found = true;
371 if (info.configured_ui_scale() == ui_scale)
372 return true;
373 if (!HasDisplayModeForUIScale(info, ui_scale))
374 return false;
375 info.set_configured_ui_scale(ui_scale);
377 display_info_list.push_back(info);
379 if (found) {
380 AddMirrorDisplayInfoIfAny(&display_info_list);
381 UpdateDisplays(display_info_list);
382 return true;
384 return false;
387 void DisplayManager::SetDisplayResolution(int64 display_id,
388 const gfx::Size& resolution) {
389 DCHECK_NE(gfx::Display::InternalDisplayId(), display_id);
390 if (gfx::Display::InternalDisplayId() == display_id)
391 return;
392 const DisplayInfo& display_info = GetDisplayInfo(display_id);
393 const std::vector<DisplayMode>& modes = display_info.display_modes();
394 DCHECK_NE(0u, modes.size());
395 DisplayMode target_mode;
396 target_mode.size = resolution;
397 std::vector<DisplayMode>::const_iterator iter =
398 std::find_if(modes.begin(), modes.end(), DisplayModeMatcher(target_mode));
399 if (iter == modes.end()) {
400 LOG(WARNING) << "Unsupported resolution was requested:"
401 << resolution.ToString();
402 return;
404 display_modes_[display_id] = *iter;
405 #if defined(OS_CHROMEOS)
406 if (base::SysInfo::IsRunningOnChromeOS())
407 Shell::GetInstance()->display_configurator()->OnConfigurationChanged();
408 #endif
411 bool DisplayManager::SetDisplayMode(int64 display_id,
412 const DisplayMode& display_mode) {
413 if (IsInternalDisplayId(display_id)) {
414 SetDisplayUIScale(display_id, display_mode.ui_scale);
415 return false;
418 DisplayInfoList display_info_list;
419 bool display_property_changed = false;
420 bool resolution_changed = false;
421 for (const auto& display : active_display_list_) {
422 DisplayInfo info = GetDisplayInfo(display.id());
423 if (info.id() == display_id) {
424 const std::vector<DisplayMode>& modes = info.display_modes();
425 std::vector<DisplayMode>::const_iterator iter =
426 std::find_if(modes.begin(),
427 modes.end(),
428 DisplayModeMatcher(display_mode));
429 if (iter == modes.end()) {
430 LOG(WARNING) << "Unsupported resolution was requested:"
431 << display_mode.size.ToString();
432 return false;
434 display_modes_[display_id] = *iter;
435 if (info.bounds_in_native().size() != display_mode.size)
436 resolution_changed = true;
437 if (info.device_scale_factor() != display_mode.device_scale_factor) {
438 info.set_device_scale_factor(display_mode.device_scale_factor);
439 display_property_changed = true;
442 display_info_list.push_back(info);
444 if (display_property_changed) {
445 AddMirrorDisplayInfoIfAny(&display_info_list);
446 UpdateDisplays(display_info_list);
448 #if defined(OS_CHROMEOS)
449 if (resolution_changed && base::SysInfo::IsRunningOnChromeOS())
450 Shell::GetInstance()->display_configurator()->OnConfigurationChanged();
451 #endif
452 return resolution_changed;
455 void DisplayManager::RegisterDisplayProperty(
456 int64 display_id,
457 gfx::Display::Rotation rotation,
458 float ui_scale,
459 const gfx::Insets* overscan_insets,
460 const gfx::Size& resolution_in_pixels,
461 float device_scale_factor,
462 ui::ColorCalibrationProfile color_profile) {
463 if (display_info_.find(display_id) == display_info_.end())
464 display_info_[display_id] = DisplayInfo(display_id, std::string(), false);
466 display_info_[display_id].SetRotation(rotation,
467 gfx::Display::ROTATION_SOURCE_ACTIVE);
468 display_info_[display_id].SetColorProfile(color_profile);
469 // Just in case the preference file was corrupted.
470 // TODO(mukai): register |display_modes_| here as well, so the lookup for the
471 // default mode in GetActiveModeForDisplayId() gets much simpler.
472 if (0.5f <= ui_scale && ui_scale <= 2.0f)
473 display_info_[display_id].set_configured_ui_scale(ui_scale);
474 if (overscan_insets)
475 display_info_[display_id].SetOverscanInsets(*overscan_insets);
476 if (!resolution_in_pixels.IsEmpty()) {
477 DCHECK(!IsInternalDisplayId(display_id));
478 // Default refresh rate, until OnNativeDisplaysChanged() updates us with the
479 // actual display info, is 60 Hz.
480 DisplayMode mode(resolution_in_pixels, 60.0f, false, false);
481 mode.device_scale_factor = device_scale_factor;
482 display_modes_[display_id] = mode;
486 DisplayMode DisplayManager::GetActiveModeForDisplayId(int64 display_id) const {
487 DisplayMode selected_mode;
488 if (GetSelectedModeForDisplayId(display_id, &selected_mode))
489 return selected_mode;
491 // If 'selected' mode is empty, it should return the default mode. This means
492 // the native mode for the external display. Unfortunately this is not true
493 // for the internal display because restoring UI-scale doesn't register the
494 // restored mode to |display_mode_|, so it needs to look up the mode whose
495 // UI-scale value matches. See the TODO in RegisterDisplayProperty().
496 const DisplayInfo& info = GetDisplayInfo(display_id);
497 const std::vector<DisplayMode>& display_modes = info.display_modes();
499 if (IsInternalDisplayId(display_id)) {
500 for (size_t i = 0; i < display_modes.size(); ++i) {
501 if (info.configured_ui_scale() == display_modes[i].ui_scale)
502 return display_modes[i];
504 } else {
505 for (size_t i = 0; i < display_modes.size(); ++i) {
506 if (display_modes[i].native)
507 return display_modes[i];
510 return selected_mode;
513 void DisplayManager::RegisterDisplayRotationProperties(bool rotation_lock,
514 gfx::Display::Rotation rotation) {
515 if (delegate_)
516 delegate_->PreDisplayConfigurationChange(false);
517 registered_internal_display_rotation_lock_ = rotation_lock;
518 registered_internal_display_rotation_ = rotation;
519 if (delegate_)
520 delegate_->PostDisplayConfigurationChange();
523 bool DisplayManager::GetSelectedModeForDisplayId(int64 id,
524 DisplayMode* mode_out) const {
525 std::map<int64, DisplayMode>::const_iterator iter = display_modes_.find(id);
526 if (iter == display_modes_.end())
527 return false;
528 *mode_out = iter->second;
529 return true;
532 bool DisplayManager::IsDisplayUIScalingEnabled() const {
533 return GetDisplayIdForUIScaling() != gfx::Display::kInvalidDisplayID;
536 gfx::Insets DisplayManager::GetOverscanInsets(int64 display_id) const {
537 std::map<int64, DisplayInfo>::const_iterator it =
538 display_info_.find(display_id);
539 return (it != display_info_.end()) ?
540 it->second.overscan_insets_in_dip() : gfx::Insets();
543 void DisplayManager::SetColorCalibrationProfile(
544 int64 display_id,
545 ui::ColorCalibrationProfile profile) {
546 #if defined(OS_CHROMEOS)
547 if (!display_info_[display_id].IsColorProfileAvailable(profile))
548 return;
550 if (delegate_)
551 delegate_->PreDisplayConfigurationChange(false);
552 // Just sets color profile if it's not running on ChromeOS (like tests).
553 if (!base::SysInfo::IsRunningOnChromeOS() ||
554 Shell::GetInstance()->display_configurator()->SetColorCalibrationProfile(
555 display_id, profile)) {
556 display_info_[display_id].SetColorProfile(profile);
557 UMA_HISTOGRAM_ENUMERATION(
558 "ChromeOS.Display.ColorProfile", profile, ui::NUM_COLOR_PROFILES);
560 if (delegate_)
561 delegate_->PostDisplayConfigurationChange();
562 #endif
565 void DisplayManager::OnNativeDisplaysChanged(
566 const std::vector<DisplayInfo>& updated_displays) {
567 if (updated_displays.empty()) {
568 VLOG(1) << "OnNativeDisplaysChanged(0): # of current displays="
569 << active_display_list_.size();
570 // If the device is booted without display, or chrome is started
571 // without --ash-host-window-bounds on linux desktop, use the
572 // default display.
573 if (active_display_list_.empty()) {
574 std::vector<DisplayInfo> init_displays;
575 init_displays.push_back(DisplayInfo::CreateFromSpec(std::string()));
576 MaybeInitInternalDisplay(&init_displays[0]);
577 OnNativeDisplaysChanged(init_displays);
578 } else {
579 // Otherwise don't update the displays when all displays are disconnected.
580 // This happens when:
581 // - the device is idle and powerd requested to turn off all displays.
582 // - the device is suspended. (kernel turns off all displays)
583 // - the internal display's brightness is set to 0 and no external
584 // display is connected.
585 // - the internal display's brightness is 0 and external display is
586 // disconnected.
587 // The display will be updated when one of displays is turned on, and the
588 // display list will be updated correctly.
590 return;
592 first_display_id_ = updated_displays[0].id();
593 std::set<gfx::Point> origins;
595 if (updated_displays.size() == 1) {
596 VLOG(1) << "OnNativeDisplaysChanged(1):" << updated_displays[0].ToString();
597 } else {
598 VLOG(1) << "OnNativeDisplaysChanged(" << updated_displays.size()
599 << ") [0]=" << updated_displays[0].ToString()
600 << ", [1]=" << updated_displays[1].ToString();
603 bool internal_display_connected = false;
604 num_connected_displays_ = updated_displays.size();
605 mirroring_display_id_ = gfx::Display::kInvalidDisplayID;
606 software_mirroring_display_list_.clear();
607 DisplayInfoList new_display_info_list;
608 for (DisplayInfoList::const_iterator iter = updated_displays.begin();
609 iter != updated_displays.end();
610 ++iter) {
611 if (!internal_display_connected)
612 internal_display_connected = IsInternalDisplayId(iter->id());
613 // Mirrored monitors have the same origins.
614 gfx::Point origin = iter->bounds_in_native().origin();
615 if (origins.find(origin) != origins.end()) {
616 InsertAndUpdateDisplayInfo(*iter);
617 mirroring_display_id_ = iter->id();
618 } else {
619 origins.insert(origin);
620 new_display_info_list.push_back(*iter);
623 DisplayMode new_mode;
624 new_mode.size = iter->bounds_in_native().size();
625 new_mode.device_scale_factor = iter->device_scale_factor();
626 new_mode.ui_scale = iter->configured_ui_scale();
627 const std::vector<DisplayMode>& display_modes = iter->display_modes();
628 // This is empty the displays are initialized from InitFromCommandLine.
629 if (!display_modes.size())
630 continue;
631 std::vector<DisplayMode>::const_iterator display_modes_iter =
632 std::find_if(display_modes.begin(),
633 display_modes.end(),
634 DisplayModeMatcher(new_mode));
635 // Update the actual resolution selected as the resolution request may fail.
636 if (display_modes_iter == display_modes.end())
637 display_modes_.erase(iter->id());
638 else if (display_modes_.find(iter->id()) != display_modes_.end())
639 display_modes_[iter->id()] = *display_modes_iter;
641 if (gfx::Display::HasInternalDisplay() && !internal_display_connected &&
642 display_info_.find(gfx::Display::InternalDisplayId()) ==
643 display_info_.end()) {
644 DisplayInfo internal_display_info(
645 gfx::Display::InternalDisplayId(),
646 l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME),
647 false /*Internal display must not have overscan */);
648 internal_display_info.SetBounds(gfx::Rect(0, 0, 800, 600));
649 display_info_[gfx::Display::InternalDisplayId()] = internal_display_info;
651 UpdateDisplays(new_display_info_list);
654 void DisplayManager::UpdateDisplays() {
655 DisplayInfoList display_info_list;
656 for (const auto& display : active_display_list_)
657 display_info_list.push_back(GetDisplayInfo(display.id()));
658 AddMirrorDisplayInfoIfAny(&display_info_list);
659 UpdateDisplays(display_info_list);
662 void DisplayManager::UpdateDisplays(
663 const std::vector<DisplayInfo>& updated_display_info_list) {
664 #if defined(OS_WIN)
665 DCHECK_EQ(1u, updated_display_info_list.size()) <<
666 ": Multiple display test does not work on Windows bots. Please "
667 "skip (don't disable) the test using SupportsMultipleDisplays()";
668 #endif
670 DisplayInfoList new_display_info_list = updated_display_info_list;
671 std::sort(active_display_list_.begin(), active_display_list_.end(),
672 DisplaySortFunctor());
673 std::sort(new_display_info_list.begin(),
674 new_display_info_list.end(),
675 DisplayInfoSortFunctor());
677 if (multi_display_mode_ != MIRRORING)
678 multi_display_mode_ = default_multi_display_mode_;
680 CreateSoftwareMirroringDisplayInfo(&new_display_info_list);
682 // Close the mirroring window if any here to avoid creating two compositor on
683 // one display.
684 if (delegate_)
685 delegate_->CloseMirroringDisplayIfNotNecessary();
687 DisplayList new_displays;
688 DisplayList removed_displays;
689 std::map<size_t, uint32_t> display_changes;
690 std::vector<size_t> added_display_indices;
692 DisplayList::iterator curr_iter = active_display_list_.begin();
693 DisplayInfoList::const_iterator new_info_iter = new_display_info_list.begin();
695 while (curr_iter != active_display_list_.end() ||
696 new_info_iter != new_display_info_list.end()) {
697 if (curr_iter == active_display_list_.end()) {
698 // more displays in new list.
699 added_display_indices.push_back(new_displays.size());
700 InsertAndUpdateDisplayInfo(*new_info_iter);
701 new_displays.push_back(
702 CreateDisplayFromDisplayInfoById(new_info_iter->id()));
703 ++new_info_iter;
704 } else if (new_info_iter == new_display_info_list.end()) {
705 // more displays in current list.
706 removed_displays.push_back(*curr_iter);
707 ++curr_iter;
708 } else if (curr_iter->id() == new_info_iter->id()) {
709 const gfx::Display& current_display = *curr_iter;
710 // Copy the info because |CreateDisplayFromInfo| updates the instance.
711 const DisplayInfo current_display_info =
712 GetDisplayInfo(current_display.id());
713 InsertAndUpdateDisplayInfo(*new_info_iter);
714 gfx::Display new_display =
715 CreateDisplayFromDisplayInfoById(new_info_iter->id());
716 const DisplayInfo& new_display_info = GetDisplayInfo(new_display.id());
718 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_NONE;
720 // At that point the new Display objects we have are not entirely updated,
721 // they are missing the translation related to the Display disposition in
722 // the layout.
723 // Using display.bounds() and display.work_area() would fail most of the
724 // time.
725 if (force_bounds_changed_ ||
726 (current_display_info.bounds_in_native() !=
727 new_display_info.bounds_in_native()) ||
728 (current_display_info.GetOverscanInsetsInPixel() !=
729 new_display_info.GetOverscanInsetsInPixel()) ||
730 current_display.size() != new_display.size()) {
731 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
732 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
735 if (current_display.device_scale_factor() !=
736 new_display.device_scale_factor()) {
737 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
740 if (current_display.rotation() != new_display.rotation())
741 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_ROTATION;
743 if (metrics != gfx::DisplayObserver::DISPLAY_METRIC_NONE) {
744 display_changes.insert(
745 std::pair<size_t, uint32_t>(new_displays.size(), metrics));
748 new_display.UpdateWorkAreaFromInsets(current_display.GetWorkAreaInsets());
749 new_displays.push_back(new_display);
750 ++curr_iter;
751 ++new_info_iter;
752 } else if (curr_iter->id() < new_info_iter->id()) {
753 // more displays in current list between ids, which means it is deleted.
754 removed_displays.push_back(*curr_iter);
755 ++curr_iter;
756 } else {
757 // more displays in new list between ids, which means it is added.
758 added_display_indices.push_back(new_displays.size());
759 InsertAndUpdateDisplayInfo(*new_info_iter);
760 new_displays.push_back(
761 CreateDisplayFromDisplayInfoById(new_info_iter->id()));
762 ++new_info_iter;
765 gfx::Display old_primary;
766 if (delegate_)
767 old_primary = screen_->GetPrimaryDisplay();
769 // Clear focus if the display has been removed, but don't clear focus if
770 // the destkop has been moved from one display to another
771 // (mirror -> docked, docked -> single internal).
772 bool clear_focus =
773 !removed_displays.empty() &&
774 !(removed_displays.size() == 1 && added_display_indices.size() == 1);
775 if (delegate_)
776 delegate_->PreDisplayConfigurationChange(clear_focus);
778 std::vector<size_t> updated_indices;
779 if (UpdateNonPrimaryDisplayBoundsForLayout(&new_displays, &updated_indices)) {
780 for (std::vector<size_t>::iterator it = updated_indices.begin();
781 it != updated_indices.end(); ++it) {
782 size_t updated_index = *it;
783 if (std::find(added_display_indices.begin(),
784 added_display_indices.end(),
785 updated_index) == added_display_indices.end()) {
786 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
787 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
788 if (display_changes.find(updated_index) != display_changes.end())
789 metrics |= display_changes[updated_index];
791 display_changes[updated_index] = metrics;
796 active_display_list_ = new_displays;
798 RefreshFontParams();
799 base::AutoReset<bool> resetter(&change_display_upon_host_resize_, false);
801 int active_display_list_size = active_display_list_.size();
802 // Temporarily add displays to be removed because display object
803 // being removed are accessed during shutting down the root.
804 active_display_list_.insert(active_display_list_.end(),
805 removed_displays.begin(), removed_displays.end());
807 for (const auto& display : removed_displays)
808 screen_->NotifyDisplayRemoved(display);
810 for (size_t index : added_display_indices)
811 screen_->NotifyDisplayAdded(active_display_list_[index]);
813 active_display_list_.resize(active_display_list_size);
815 bool notify_primary_change =
816 delegate_ ? old_primary.id() != screen_->GetPrimaryDisplay().id() : false;
818 for (std::map<size_t, uint32_t>::iterator iter = display_changes.begin();
819 iter != display_changes.end();
820 ++iter) {
821 uint32_t metrics = iter->second;
822 const gfx::Display& updated_display = active_display_list_[iter->first];
824 if (notify_primary_change &&
825 updated_display.id() == screen_->GetPrimaryDisplay().id()) {
826 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_PRIMARY;
827 notify_primary_change = false;
829 screen_->NotifyMetricsChanged(updated_display, metrics);
832 if (notify_primary_change) {
833 // This happens when a primary display has moved to anther display without
834 // bounds change.
835 const gfx::Display& primary = screen_->GetPrimaryDisplay();
836 if (primary.id() != old_primary.id()) {
837 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_PRIMARY;
838 if (primary.size() != old_primary.size()) {
839 metrics |= (gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
840 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
842 if (primary.device_scale_factor() != old_primary.device_scale_factor())
843 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
845 screen_->NotifyMetricsChanged(primary, metrics);
849 if (delegate_)
850 delegate_->PostDisplayConfigurationChange();
852 #if defined(USE_X11) && defined(OS_CHROMEOS)
853 if (!display_changes.empty() && base::SysInfo::IsRunningOnChromeOS())
854 ui::ClearX11DefaultRootWindow();
855 #endif
857 // Create the mirroring window asynchronously after all displays
858 // are added so that it can mirror the display newly added. This can
859 // happen when switching from dock mode to software mirror mode.
860 CreateMirrorWindowAsyncIfAny();
863 const gfx::Display& DisplayManager::GetDisplayAt(size_t index) const {
864 DCHECK_LT(index, active_display_list_.size());
865 return active_display_list_[index];
868 const gfx::Display& DisplayManager::GetPrimaryDisplayCandidate() const {
869 if (GetNumDisplays() != 2)
870 return active_display_list_[0];
871 DisplayLayout layout = layout_store_->GetRegisteredDisplayLayout(
872 GetCurrentDisplayIdPair());
873 return GetDisplayForId(layout.primary_id);
876 size_t DisplayManager::GetNumDisplays() const {
877 return active_display_list_.size();
880 bool DisplayManager::IsInMirrorMode() const {
881 return mirroring_display_id_ != gfx::Display::kInvalidDisplayID;
884 bool DisplayManager::IsInUnifiedMode() const {
885 return multi_display_mode_ == UNIFIED &&
886 !software_mirroring_display_list_.empty();
889 const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const {
890 DCHECK_NE(gfx::Display::kInvalidDisplayID, display_id);
892 std::map<int64, DisplayInfo>::const_iterator iter =
893 display_info_.find(display_id);
894 CHECK(iter != display_info_.end()) << display_id;
895 return iter->second;
898 const gfx::Display DisplayManager::GetMirroringDisplayById(
899 int64 display_id) const {
900 auto iter = std::find_if(software_mirroring_display_list_.begin(),
901 software_mirroring_display_list_.end(),
902 [display_id](const gfx::Display& display) {
903 return display.id() == display_id;
905 return iter == software_mirroring_display_list_.end() ? gfx::Display()
906 : *iter;
909 std::string DisplayManager::GetDisplayNameForId(int64 id) {
910 if (id == gfx::Display::kInvalidDisplayID)
911 return l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME);
913 std::map<int64, DisplayInfo>::const_iterator iter = display_info_.find(id);
914 if (iter != display_info_.end() && !iter->second.name().empty())
915 return iter->second.name();
917 return base::StringPrintf("Display %d", static_cast<int>(id));
920 int64 DisplayManager::GetDisplayIdForUIScaling() const {
921 // UI Scaling is effective only on internal display.
922 int64 display_id = gfx::Display::InternalDisplayId();
923 #if defined(OS_WIN)
924 display_id = first_display_id();
925 #endif
926 return display_id;
929 void DisplayManager::SetMirrorMode(bool mirror) {
930 #if defined(OS_CHROMEOS)
931 if (num_connected_displays() <= 1)
932 return;
934 if (base::SysInfo::IsRunningOnChromeOS()) {
935 ui::MultipleDisplayState new_state =
936 mirror ? ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR
937 : ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
938 Shell::GetInstance()->display_configurator()->SetDisplayMode(new_state);
939 return;
942 // This is fallback path to emulate mirroroing on desktop and unit test.
943 DisplayInfoList display_info_list;
944 for (DisplayList::const_iterator iter = active_display_list_.begin();
945 (display_info_list.size() < 2 && iter != active_display_list_.end());
946 ++iter) {
947 if (iter->id() == kUnifiedDisplayId)
948 continue;
949 display_info_list.push_back(GetDisplayInfo(iter->id()));
951 for (auto iter = software_mirroring_display_list_.begin();
952 (display_info_list.size() < 2 &&
953 iter != software_mirroring_display_list_.end());
954 ++iter) {
955 display_info_list.push_back(GetDisplayInfo(iter->id()));
957 multi_display_mode_ = mirror ? MIRRORING : default_multi_display_mode_;
958 ReconfigureDisplays();
959 if (Shell::GetInstance()->display_configurator_animation()) {
960 Shell::GetInstance()->display_configurator_animation()->
961 StartFadeInAnimation();
963 RunPendingTasksForTest();
964 #endif
967 void DisplayManager::AddRemoveDisplay() {
968 DCHECK(!active_display_list_.empty());
969 std::vector<DisplayInfo> new_display_info_list;
970 const DisplayInfo& first_display =
971 IsInUnifiedMode()
972 ? GetDisplayInfo(software_mirroring_display_list_[0].id())
973 : GetDisplayInfo(active_display_list_[0].id());
974 new_display_info_list.push_back(first_display);
975 // Add if there is only one display connected.
976 if (num_connected_displays() == 1) {
977 const int kVerticalOffsetPx = 100;
978 // Layout the 2nd display below the primary as with the real device.
979 gfx::Rect host_bounds = first_display.bounds_in_native();
980 new_display_info_list.push_back(
981 DisplayInfo::CreateFromSpec(base::StringPrintf(
982 "%d+%d-600x%d", host_bounds.x(),
983 host_bounds.bottom() + kVerticalOffsetPx, host_bounds.height())));
985 num_connected_displays_ = new_display_info_list.size();
986 mirroring_display_id_ = gfx::Display::kInvalidDisplayID;
987 software_mirroring_display_list_.clear();
988 UpdateDisplays(new_display_info_list);
991 void DisplayManager::ToggleDisplayScaleFactor() {
992 DCHECK(!active_display_list_.empty());
993 std::vector<DisplayInfo> new_display_info_list;
994 for (DisplayList::const_iterator iter = active_display_list_.begin();
995 iter != active_display_list_.end(); ++iter) {
996 DisplayInfo display_info = GetDisplayInfo(iter->id());
997 display_info.set_device_scale_factor(
998 display_info.device_scale_factor() == 1.0f ? 2.0f : 1.0f);
999 new_display_info_list.push_back(display_info);
1001 AddMirrorDisplayInfoIfAny(&new_display_info_list);
1002 UpdateDisplays(new_display_info_list);
1005 #if defined(OS_CHROMEOS)
1006 void DisplayManager::SetSoftwareMirroring(bool enabled) {
1007 SetMultiDisplayMode(enabled ? MIRRORING : default_multi_display_mode_);
1010 bool DisplayManager::SoftwareMirroringEnabled() const {
1011 return software_mirroring_enabled();
1013 #endif
1015 void DisplayManager::SetMultiDisplayMode(MultiDisplayMode mode) {
1016 multi_display_mode_ = mode;
1017 mirroring_display_id_ = gfx::Display::kInvalidDisplayID;
1018 software_mirroring_display_list_.clear();
1021 void DisplayManager::SetDefaultMultiDisplayMode(MultiDisplayMode mode) {
1022 DCHECK_NE(mode, MIRRORING);
1023 default_multi_display_mode_ = mode;
1026 void DisplayManager::ReconfigureDisplays() {
1027 DisplayInfoList display_info_list;
1028 for (DisplayList::const_iterator iter = active_display_list_.begin();
1029 (display_info_list.size() < 2 && iter != active_display_list_.end());
1030 ++iter) {
1031 if (iter->id() == kUnifiedDisplayId)
1032 continue;
1033 display_info_list.push_back(GetDisplayInfo(iter->id()));
1035 for (auto iter = software_mirroring_display_list_.begin();
1036 (display_info_list.size() < 2 &&
1037 iter != software_mirroring_display_list_.end());
1038 ++iter) {
1039 display_info_list.push_back(GetDisplayInfo(iter->id()));
1041 mirroring_display_id_ = gfx::Display::kInvalidDisplayID;
1042 software_mirroring_display_list_.clear();
1043 UpdateDisplays(display_info_list);
1046 bool DisplayManager::UpdateDisplayBounds(int64 display_id,
1047 const gfx::Rect& new_bounds) {
1048 if (change_display_upon_host_resize_) {
1049 display_info_[display_id].SetBounds(new_bounds);
1050 // Don't notify observers if the mirrored window has changed.
1051 if (software_mirroring_enabled() && mirroring_display_id_ == display_id)
1052 return false;
1053 gfx::Display* display = FindDisplayForId(display_id);
1054 display->SetSize(display_info_[display_id].size_in_pixel());
1055 screen_->NotifyMetricsChanged(*display,
1056 gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS);
1057 return true;
1059 return false;
1062 void DisplayManager::CreateMirrorWindowAsyncIfAny() {
1063 // Do not post a task if the software mirroring doesn't exist, or
1064 // during initialization when compositor's init task isn't posted yet.
1065 // ash::Shell::Init() will call this after the compositor is initialized.
1066 if (software_mirroring_display_list_.empty() || !delegate_)
1067 return;
1068 base::MessageLoopForUI::current()->PostTask(
1069 FROM_HERE,
1070 base::Bind(&DisplayManager::CreateMirrorWindowIfAny,
1071 weak_ptr_factory_.GetWeakPtr()));
1074 scoped_ptr<MouseWarpController> DisplayManager::CreateMouseWarpController(
1075 aura::Window* drag_source) const {
1076 if (IsInUnifiedMode() && num_connected_displays() >= 2)
1077 return make_scoped_ptr(new UnifiedMouseWarpController());
1078 // Extra check for |num_connected_displays()| is for SystemDisplayApiTest
1079 // that injects MockScreen.
1080 if (GetNumDisplays() < 2 || num_connected_displays() < 2)
1081 return make_scoped_ptr(new NullMouseWarpController());
1082 return make_scoped_ptr(new ExtendedMouseWarpController(drag_source));
1085 void DisplayManager::CreateScreenForShutdown() const {
1086 bool native_is_ash =
1087 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE) == screen_.get();
1088 delete screen_for_shutdown;
1089 screen_for_shutdown = screen_->CloneForShutdown();
1090 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE,
1091 screen_for_shutdown);
1092 if (native_is_ash) {
1093 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE,
1094 screen_for_shutdown);
1098 void DisplayManager::UpdateInternalDisplayModeListForTest() {
1099 if (display_info_.count(gfx::Display::InternalDisplayId()) == 0)
1100 return;
1101 DisplayInfo* info = &display_info_[gfx::Display::InternalDisplayId()];
1102 SetInternalDisplayModeList(info);
1105 void DisplayManager::CreateSoftwareMirroringDisplayInfo(
1106 DisplayInfoList* display_info_list) {
1107 // Use the internal display or 1st as the mirror source, then scale
1108 // the root window so that it matches the external display's
1109 // resolution. This is necessary in order for scaling to work while
1110 // mirrored.
1111 if (display_info_list->size() == 2) {
1112 switch (multi_display_mode_) {
1113 case MIRRORING: {
1114 bool zero_is_source =
1115 first_display_id_ == (*display_info_list)[0].id() ||
1116 gfx::Display::InternalDisplayId() == (*display_info_list)[0].id();
1117 DCHECK_EQ(MIRRORING, multi_display_mode_);
1118 mirroring_display_id_ =
1119 (*display_info_list)[zero_is_source ? 1 : 0].id();
1121 int64 display_id = mirroring_display_id_;
1122 auto iter =
1123 std::find_if(display_info_list->begin(), display_info_list->end(),
1124 [display_id](const DisplayInfo& info) {
1125 return info.id() == display_id;
1127 DCHECK(iter != display_info_list->end());
1129 DisplayInfo info = *iter;
1130 info.SetOverscanInsets(gfx::Insets());
1131 InsertAndUpdateDisplayInfo(info);
1132 software_mirroring_display_list_.push_back(
1133 CreateDisplayFromDisplayInfoById(mirroring_display_id_));
1134 display_info_list->erase(iter);
1135 break;
1137 case UNIFIED: {
1138 // TODO(oshima): Suport displays that have different heights.
1139 // TODO(oshima): Currently, all displays are laid out horizontally,
1140 // from left to right. Allow more flexible layouts, such as
1141 // right to left, or vertical layouts.
1142 gfx::Rect unified_bounds;
1143 software_mirroring_display_list_.clear();
1144 for (auto& info : *display_info_list) {
1145 InsertAndUpdateDisplayInfo(info);
1146 gfx::Display display = CreateDisplayFromDisplayInfoById(info.id());
1147 gfx::Point origin(unified_bounds.right(), 0);
1148 display.set_bounds(gfx::Rect(origin, info.size_in_pixel()));
1149 display.UpdateWorkAreaFromInsets(gfx::Insets());
1150 unified_bounds.Union(display.bounds());
1151 software_mirroring_display_list_.push_back(display);
1153 DisplayInfo info(kUnifiedDisplayId, "Unified Desktop", false);
1154 info.SetBounds(unified_bounds);
1155 display_info_list->clear();
1156 display_info_list->push_back(info);
1157 break;
1159 case EXTENDED:
1160 break;
1165 gfx::Display* DisplayManager::FindDisplayForId(int64 id) {
1166 auto iter = std::find_if(
1167 active_display_list_.begin(), active_display_list_.end(),
1168 [id](const gfx::Display& display) { return display.id() == id; });
1169 if (iter != active_display_list_.end())
1170 return &(*iter);
1171 // TODO(oshima): This happens when a windows in unified desktop have
1172 // been moved to normal window. Fix this.
1173 if (id != kUnifiedDisplayId)
1174 DLOG(WARNING) << "Could not find display:" << id;
1175 return NULL;
1178 void DisplayManager::AddMirrorDisplayInfoIfAny(
1179 std::vector<DisplayInfo>* display_info_list) {
1180 if (software_mirroring_enabled() && IsInMirrorMode())
1181 display_info_list->push_back(GetDisplayInfo(mirroring_display_id_));
1184 void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo& new_info) {
1185 std::map<int64, DisplayInfo>::iterator info =
1186 display_info_.find(new_info.id());
1187 if (info != display_info_.end()) {
1188 info->second.Copy(new_info);
1189 } else {
1190 display_info_[new_info.id()] = new_info;
1191 display_info_[new_info.id()].set_native(false);
1193 display_info_[new_info.id()].UpdateDisplaySize();
1194 OnDisplayInfoUpdated(display_info_[new_info.id()]);
1197 void DisplayManager::OnDisplayInfoUpdated(const DisplayInfo& display_info) {
1198 #if defined(OS_CHROMEOS)
1199 ui::ColorCalibrationProfile color_profile = display_info.color_profile();
1200 if (color_profile != ui::COLOR_PROFILE_STANDARD) {
1201 Shell::GetInstance()->display_configurator()->SetColorCalibrationProfile(
1202 display_info.id(), color_profile);
1204 #endif
1207 gfx::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64 id) {
1208 DCHECK(display_info_.find(id) != display_info_.end()) << "id=" << id;
1209 const DisplayInfo& display_info = display_info_[id];
1211 gfx::Display new_display(display_info.id());
1212 gfx::Rect bounds_in_native(display_info.size_in_pixel());
1213 float device_scale_factor = display_info.GetEffectiveDeviceScaleFactor();
1215 // Simply set the origin to (0,0). The primary display's origin is
1216 // always (0,0) and the bounds of non-primary display(s) will be updated
1217 // in |UpdateNonPrimaryDisplayBoundsForLayout| called in |UpdateDisplay|.
1218 new_display.SetScaleAndBounds(
1219 device_scale_factor, gfx::Rect(bounds_in_native.size()));
1220 new_display.set_rotation(display_info.GetActiveRotation());
1221 new_display.set_touch_support(display_info.touch_support());
1222 return new_display;
1225 bool DisplayManager::UpdateNonPrimaryDisplayBoundsForLayout(
1226 DisplayList* displays,
1227 std::vector<size_t>* updated_indices) const {
1229 if (displays->size() < 2U)
1230 return false;
1232 if (displays->size() > 2U) {
1233 // For more than 2 displays, always use horizontal layout.
1234 int x_offset = displays->at(0).bounds().width();
1235 for (size_t i = 1; i < displays->size(); ++i) {
1236 gfx::Display& display = displays->at(i);
1237 const gfx::Rect& bounds = display.bounds();
1238 gfx::Point origin = gfx::Point(x_offset, 0);
1239 gfx::Insets insets = display.GetWorkAreaInsets();
1240 display.set_bounds(gfx::Rect(origin, bounds.size()));
1241 display.UpdateWorkAreaFromInsets(insets);
1242 x_offset += bounds.width();
1243 updated_indices->push_back(i);
1245 return true;
1248 int64 id_at_zero = displays->at(0).id();
1249 DisplayIdPair pair =
1250 (id_at_zero == first_display_id_ ||
1251 id_at_zero == gfx::Display::InternalDisplayId()) ?
1252 std::make_pair(id_at_zero, displays->at(1).id()) :
1253 std::make_pair(displays->at(1).id(), id_at_zero);
1254 DisplayLayout layout =
1255 layout_store_->ComputeDisplayLayoutForDisplayIdPair(pair);
1257 // Ignore if a user has a old format (should be extremely rare)
1258 // and this will be replaced with DCHECK.
1259 if (layout.primary_id != gfx::Display::kInvalidDisplayID) {
1260 size_t primary_index, secondary_index;
1261 if (displays->at(0).id() == layout.primary_id) {
1262 primary_index = 0;
1263 secondary_index = 1;
1264 } else {
1265 primary_index = 1;
1266 secondary_index = 0;
1268 // This function may be called before the secondary display is
1269 // registered. The bounds is empty in that case and will
1270 // return true.
1271 gfx::Rect bounds =
1272 GetDisplayForId(displays->at(secondary_index).id()).bounds();
1273 UpdateDisplayBoundsForLayout(
1274 layout, displays->at(primary_index), &displays->at(secondary_index));
1275 updated_indices->push_back(secondary_index);
1276 return bounds != displays->at(secondary_index).bounds();
1278 return false;
1281 void DisplayManager::CreateMirrorWindowIfAny() {
1282 if (software_mirroring_display_list_.empty() || !delegate_)
1283 return;
1284 DisplayInfoList list;
1285 for (auto& display : software_mirroring_display_list_)
1286 list.push_back(GetDisplayInfo(display.id()));
1287 delegate_->CreateOrUpdateMirroringDisplay(list);
1290 // static
1291 void DisplayManager::UpdateDisplayBoundsForLayout(
1292 const DisplayLayout& layout,
1293 const gfx::Display& primary_display,
1294 gfx::Display* secondary_display) {
1295 DCHECK_EQ("0,0", primary_display.bounds().origin().ToString());
1297 const gfx::Rect& primary_bounds = primary_display.bounds();
1298 const gfx::Rect& secondary_bounds = secondary_display->bounds();
1299 gfx::Point new_secondary_origin = primary_bounds.origin();
1301 DisplayLayout::Position position = layout.position;
1303 // Ignore the offset in case the secondary display doesn't share edges with
1304 // the primary display.
1305 int offset = layout.offset;
1306 if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM) {
1307 offset = std::min(
1308 offset, primary_bounds.width() - kMinimumOverlapForInvalidOffset);
1309 offset = std::max(
1310 offset, -secondary_bounds.width() + kMinimumOverlapForInvalidOffset);
1311 } else {
1312 offset = std::min(
1313 offset, primary_bounds.height() - kMinimumOverlapForInvalidOffset);
1314 offset = std::max(
1315 offset, -secondary_bounds.height() + kMinimumOverlapForInvalidOffset);
1317 switch (position) {
1318 case DisplayLayout::TOP:
1319 new_secondary_origin.Offset(offset, -secondary_bounds.height());
1320 break;
1321 case DisplayLayout::RIGHT:
1322 new_secondary_origin.Offset(primary_bounds.width(), offset);
1323 break;
1324 case DisplayLayout::BOTTOM:
1325 new_secondary_origin.Offset(offset, primary_bounds.height());
1326 break;
1327 case DisplayLayout::LEFT:
1328 new_secondary_origin.Offset(-secondary_bounds.width(), offset);
1329 break;
1331 gfx::Insets insets = secondary_display->GetWorkAreaInsets();
1332 secondary_display->set_bounds(
1333 gfx::Rect(new_secondary_origin, secondary_bounds.size()));
1334 secondary_display->UpdateWorkAreaFromInsets(insets);
1337 void DisplayManager::RunPendingTasksForTest() {
1338 if (!software_mirroring_display_list_.empty())
1339 base::RunLoop().RunUntilIdle();
1342 } // namespace ash