cc: Send BeginFrame to VideoFrameController when added.
[chromium-blink-merge.git] / ash / display / display_manager.cc
bloba38a6975efecf2a317e646f6b837f2b121e1e88a
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 multi_display_mode_ = 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());
676 // Close the mirroring window if any here to avoid creating two compositor on
677 // one display.
678 if (delegate_)
679 delegate_->CloseMirroringDisplay();
681 CreateSoftwareMirroringDisplay(&new_display_info_list);
683 DisplayList new_displays;
684 DisplayList removed_displays;
685 std::map<size_t, uint32_t> display_changes;
686 std::vector<size_t> added_display_indices;
688 DisplayList::iterator curr_iter = active_display_list_.begin();
689 DisplayInfoList::const_iterator new_info_iter = new_display_info_list.begin();
691 while (curr_iter != active_display_list_.end() ||
692 new_info_iter != new_display_info_list.end()) {
693 if (curr_iter == active_display_list_.end()) {
694 // more displays in new list.
695 added_display_indices.push_back(new_displays.size());
696 InsertAndUpdateDisplayInfo(*new_info_iter);
697 new_displays.push_back(
698 CreateDisplayFromDisplayInfoById(new_info_iter->id()));
699 ++new_info_iter;
700 } else if (new_info_iter == new_display_info_list.end()) {
701 // more displays in current list.
702 removed_displays.push_back(*curr_iter);
703 ++curr_iter;
704 } else if (curr_iter->id() == new_info_iter->id()) {
705 const gfx::Display& current_display = *curr_iter;
706 // Copy the info because |CreateDisplayFromInfo| updates the instance.
707 const DisplayInfo current_display_info =
708 GetDisplayInfo(current_display.id());
709 InsertAndUpdateDisplayInfo(*new_info_iter);
710 gfx::Display new_display =
711 CreateDisplayFromDisplayInfoById(new_info_iter->id());
712 const DisplayInfo& new_display_info = GetDisplayInfo(new_display.id());
714 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_NONE;
716 // At that point the new Display objects we have are not entirely updated,
717 // they are missing the translation related to the Display disposition in
718 // the layout.
719 // Using display.bounds() and display.work_area() would fail most of the
720 // time.
721 if (force_bounds_changed_ ||
722 (current_display_info.bounds_in_native() !=
723 new_display_info.bounds_in_native()) ||
724 (current_display_info.GetOverscanInsetsInPixel() !=
725 new_display_info.GetOverscanInsetsInPixel()) ||
726 current_display.size() != new_display.size()) {
727 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
728 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
731 if (current_display.device_scale_factor() !=
732 new_display.device_scale_factor()) {
733 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
736 if (current_display.rotation() != new_display.rotation())
737 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_ROTATION;
739 if (metrics != gfx::DisplayObserver::DISPLAY_METRIC_NONE) {
740 display_changes.insert(
741 std::pair<size_t, uint32_t>(new_displays.size(), metrics));
744 new_display.UpdateWorkAreaFromInsets(current_display.GetWorkAreaInsets());
745 new_displays.push_back(new_display);
746 ++curr_iter;
747 ++new_info_iter;
748 } else if (curr_iter->id() < new_info_iter->id()) {
749 // more displays in current list between ids, which means it is deleted.
750 removed_displays.push_back(*curr_iter);
751 ++curr_iter;
752 } else {
753 // more displays in new list between ids, which means it is added.
754 added_display_indices.push_back(new_displays.size());
755 InsertAndUpdateDisplayInfo(*new_info_iter);
756 new_displays.push_back(
757 CreateDisplayFromDisplayInfoById(new_info_iter->id()));
758 ++new_info_iter;
761 gfx::Display old_primary;
762 if (delegate_)
763 old_primary = screen_->GetPrimaryDisplay();
765 // Clear focus if the display has been removed, but don't clear focus if
766 // the destkop has been moved from one display to another
767 // (mirror -> docked, docked -> single internal).
768 bool clear_focus =
769 !removed_displays.empty() &&
770 !(removed_displays.size() == 1 && added_display_indices.size() == 1);
771 if (delegate_)
772 delegate_->PreDisplayConfigurationChange(clear_focus);
774 std::vector<size_t> updated_indices;
775 if (UpdateNonPrimaryDisplayBoundsForLayout(&new_displays, &updated_indices)) {
776 for (std::vector<size_t>::iterator it = updated_indices.begin();
777 it != updated_indices.end(); ++it) {
778 size_t updated_index = *it;
779 if (std::find(added_display_indices.begin(),
780 added_display_indices.end(),
781 updated_index) == added_display_indices.end()) {
782 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
783 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
784 if (display_changes.find(updated_index) != display_changes.end())
785 metrics |= display_changes[updated_index];
787 display_changes[updated_index] = metrics;
792 active_display_list_ = new_displays;
794 RefreshFontParams();
795 base::AutoReset<bool> resetter(&change_display_upon_host_resize_, false);
797 // Temporarily add displays to be removed because display object
798 // being removed are accessed during shutting down the root.
799 active_display_list_.insert(active_display_list_.end(),
800 removed_displays.begin(), removed_displays.end());
802 for (DisplayList::const_reverse_iterator iter = removed_displays.rbegin();
803 iter != removed_displays.rend(); ++iter) {
804 screen_->NotifyDisplayRemoved(active_display_list_.back());
805 active_display_list_.pop_back();
808 for (std::vector<size_t>::iterator iter = added_display_indices.begin();
809 iter != added_display_indices.end(); ++iter) {
810 screen_->NotifyDisplayAdded(active_display_list_[*iter]);
813 bool notify_primary_change =
814 delegate_ ? old_primary.id() != screen_->GetPrimaryDisplay().id() : false;
816 for (std::map<size_t, uint32_t>::iterator iter = display_changes.begin();
817 iter != display_changes.end();
818 ++iter) {
819 uint32_t metrics = iter->second;
820 const gfx::Display& updated_display = active_display_list_[iter->first];
822 if (notify_primary_change &&
823 updated_display.id() == screen_->GetPrimaryDisplay().id()) {
824 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_PRIMARY;
825 notify_primary_change = false;
827 screen_->NotifyMetricsChanged(updated_display, metrics);
830 if (notify_primary_change) {
831 // This happens when a primary display has moved to anther display without
832 // bounds change.
833 const gfx::Display& primary = screen_->GetPrimaryDisplay();
834 if (primary.id() != old_primary.id()) {
835 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_PRIMARY;
836 if (primary.size() != old_primary.size()) {
837 metrics |= (gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
838 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
840 if (primary.device_scale_factor() != old_primary.device_scale_factor())
841 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
843 screen_->NotifyMetricsChanged(primary, metrics);
847 if (delegate_)
848 delegate_->PostDisplayConfigurationChange();
850 #if defined(USE_X11) && defined(OS_CHROMEOS)
851 if (!display_changes.empty() && base::SysInfo::IsRunningOnChromeOS())
852 ui::ClearX11DefaultRootWindow();
853 #endif
855 // Create the mirroring window asynchronously after all displays
856 // are added so that it can mirror the display newly added. This can
857 // happen when switching from dock mode to software mirror mode.
858 CreateMirrorWindowAsyncIfAny();
861 const gfx::Display& DisplayManager::GetDisplayAt(size_t index) const {
862 DCHECK_LT(index, active_display_list_.size());
863 return active_display_list_[index];
866 const gfx::Display& DisplayManager::GetPrimaryDisplayCandidate() const {
867 if (GetNumDisplays() != 2)
868 return active_display_list_[0];
869 DisplayLayout layout = layout_store_->GetRegisteredDisplayLayout(
870 GetCurrentDisplayIdPair());
871 return GetDisplayForId(layout.primary_id);
874 size_t DisplayManager::GetNumDisplays() const {
875 return active_display_list_.size();
878 bool DisplayManager::IsInMirrorMode() const {
879 return mirroring_display_id_ != gfx::Display::kInvalidDisplayID;
882 bool DisplayManager::IsInUnifiedMode() const {
883 return multi_display_mode_ == UNIFIED &&
884 !software_mirroring_display_list_.empty();
887 const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const {
888 DCHECK_NE(gfx::Display::kInvalidDisplayID, display_id);
890 std::map<int64, DisplayInfo>::const_iterator iter =
891 display_info_.find(display_id);
892 CHECK(iter != display_info_.end()) << display_id;
893 return iter->second;
896 const gfx::Display DisplayManager::GetMirroringDisplayById(
897 int64 display_id) const {
898 auto iter = std::find_if(software_mirroring_display_list_.begin(),
899 software_mirroring_display_list_.end(),
900 [display_id](const gfx::Display& display) {
901 return display.id() == display_id;
903 return iter == software_mirroring_display_list_.end() ? gfx::Display()
904 : *iter;
907 std::string DisplayManager::GetDisplayNameForId(int64 id) {
908 if (id == gfx::Display::kInvalidDisplayID)
909 return l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME);
911 std::map<int64, DisplayInfo>::const_iterator iter = display_info_.find(id);
912 if (iter != display_info_.end() && !iter->second.name().empty())
913 return iter->second.name();
915 return base::StringPrintf("Display %d", static_cast<int>(id));
918 int64 DisplayManager::GetDisplayIdForUIScaling() const {
919 // UI Scaling is effective only on internal display.
920 int64 display_id = gfx::Display::InternalDisplayId();
921 #if defined(OS_WIN)
922 display_id = first_display_id();
923 #endif
924 return display_id;
927 void DisplayManager::SetMirrorMode(bool mirror) {
928 #if defined(OS_CHROMEOS)
929 if (num_connected_displays() <= 1)
930 return;
932 if (base::SysInfo::IsRunningOnChromeOS()) {
933 ui::MultipleDisplayState new_state =
934 mirror ? ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR
935 : ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
936 Shell::GetInstance()->display_configurator()->SetDisplayMode(new_state);
937 return;
940 // This is fallback path to emulate mirroroing on desktop and unit test.
941 DisplayInfoList display_info_list;
942 for (DisplayList::const_iterator iter = active_display_list_.begin();
943 (display_info_list.size() < 2 && iter != active_display_list_.end());
944 ++iter) {
945 if (iter->id() == kUnifiedDisplayId)
946 continue;
947 display_info_list.push_back(GetDisplayInfo(iter->id()));
949 for (auto iter = software_mirroring_display_list_.begin();
950 (display_info_list.size() < 2 &&
951 iter != software_mirroring_display_list_.end());
952 ++iter) {
953 display_info_list.push_back(GetDisplayInfo(iter->id()));
956 SetSoftwareMirroring(mirror);
957 UpdateDisplays(display_info_list);
958 if (Shell::GetInstance()->display_configurator_animation()) {
959 Shell::GetInstance()->display_configurator_animation()->
960 StartFadeInAnimation();
962 RunPendingTasksForTest();
963 #endif
966 void DisplayManager::AddRemoveDisplay() {
967 DCHECK(!active_display_list_.empty());
968 std::vector<DisplayInfo> new_display_info_list;
969 const DisplayInfo& first_display =
970 IsInUnifiedMode()
971 ? GetDisplayInfo(software_mirroring_display_list_[0].id())
972 : GetDisplayInfo(active_display_list_[0].id());
973 new_display_info_list.push_back(first_display);
974 // Add if there is only one display connected.
975 if (num_connected_displays() == 1) {
976 const int kVerticalOffsetPx = 100;
977 // Layout the 2nd display below the primary as with the real device.
978 gfx::Rect host_bounds = first_display.bounds_in_native();
979 new_display_info_list.push_back(
980 DisplayInfo::CreateFromSpec(base::StringPrintf(
981 "%d+%d-600x%d", host_bounds.x(),
982 host_bounds.bottom() + kVerticalOffsetPx, host_bounds.height())));
984 num_connected_displays_ = new_display_info_list.size();
985 mirroring_display_id_ = gfx::Display::kInvalidDisplayID;
986 software_mirroring_display_list_.clear();
987 UpdateDisplays(new_display_info_list);
990 void DisplayManager::ToggleDisplayScaleFactor() {
991 DCHECK(!active_display_list_.empty());
992 std::vector<DisplayInfo> new_display_info_list;
993 for (DisplayList::const_iterator iter = active_display_list_.begin();
994 iter != active_display_list_.end(); ++iter) {
995 DisplayInfo display_info = GetDisplayInfo(iter->id());
996 display_info.set_device_scale_factor(
997 display_info.device_scale_factor() == 1.0f ? 2.0f : 1.0f);
998 new_display_info_list.push_back(display_info);
1000 AddMirrorDisplayInfoIfAny(&new_display_info_list);
1001 UpdateDisplays(new_display_info_list);
1004 #if defined(OS_CHROMEOS)
1005 void DisplayManager::SetSoftwareMirroring(bool enabled) {
1006 SetMultiDisplayMode(enabled ? MIRRORING : default_multi_display_mode_);
1009 bool DisplayManager::SoftwareMirroringEnabled() const {
1010 return software_mirroring_enabled();
1012 #endif
1014 void DisplayManager::SetMultiDisplayMode(MultiDisplayMode mode) {
1015 multi_display_mode_ = mode;
1016 mirroring_display_id_ = gfx::Display::kInvalidDisplayID;
1017 software_mirroring_display_list_.clear();
1020 bool DisplayManager::UpdateDisplayBounds(int64 display_id,
1021 const gfx::Rect& new_bounds) {
1022 if (change_display_upon_host_resize_) {
1023 display_info_[display_id].SetBounds(new_bounds);
1024 // Don't notify observers if the mirrored window has changed.
1025 if (software_mirroring_enabled() && mirroring_display_id_ == display_id)
1026 return false;
1027 gfx::Display* display = FindDisplayForId(display_id);
1028 display->SetSize(display_info_[display_id].size_in_pixel());
1029 screen_->NotifyMetricsChanged(*display,
1030 gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS);
1031 return true;
1033 return false;
1036 void DisplayManager::CreateMirrorWindowAsyncIfAny() {
1037 // Do not post a task if the software mirroring doesn't exist, or
1038 // during initialization when compositor's init task isn't posted yet.
1039 // ash::Shell::Init() will call this after the compositor is initialized.
1040 if (software_mirroring_display_list_.empty() || !delegate_)
1041 return;
1042 base::MessageLoopForUI::current()->PostTask(
1043 FROM_HERE,
1044 base::Bind(&DisplayManager::CreateMirrorWindowIfAny,
1045 weak_ptr_factory_.GetWeakPtr()));
1048 scoped_ptr<MouseWarpController> DisplayManager::CreateMouseWarpController(
1049 aura::Window* drag_source) const {
1050 if (IsInUnifiedMode() && num_connected_displays() >= 2)
1051 return make_scoped_ptr(new UnifiedMouseWarpController());
1052 // Extra check for |num_connected_displays()| is for SystemDisplayApiTest
1053 // that injects MockScreen.
1054 if (GetNumDisplays() < 2 || num_connected_displays() < 2)
1055 return make_scoped_ptr(new NullMouseWarpController());
1056 return make_scoped_ptr(new ExtendedMouseWarpController(drag_source));
1059 void DisplayManager::CreateScreenForShutdown() const {
1060 bool native_is_ash =
1061 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE) == screen_.get();
1062 delete screen_for_shutdown;
1063 screen_for_shutdown = screen_->CloneForShutdown();
1064 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE,
1065 screen_for_shutdown);
1066 if (native_is_ash) {
1067 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE,
1068 screen_for_shutdown);
1072 void DisplayManager::UpdateInternalDisplayModeListForTest() {
1073 if (display_info_.count(gfx::Display::InternalDisplayId()) == 0)
1074 return;
1075 DisplayInfo* info = &display_info_[gfx::Display::InternalDisplayId()];
1076 SetInternalDisplayModeList(info);
1079 void DisplayManager::CreateSoftwareMirroringDisplay(
1080 DisplayInfoList* display_info_list) {
1081 // Use the internal display or 1st as the mirror source, then scale
1082 // the root window so that it matches the external display's
1083 // resolution. This is necessary in order for scaling to work while
1084 // mirrored.
1085 if (display_info_list->size() == 2) {
1086 switch (multi_display_mode_) {
1087 case MIRRORING: {
1088 bool zero_is_source =
1089 first_display_id_ == (*display_info_list)[0].id() ||
1090 gfx::Display::InternalDisplayId() == (*display_info_list)[0].id();
1091 DCHECK_EQ(MIRRORING, multi_display_mode_);
1092 mirroring_display_id_ =
1093 (*display_info_list)[zero_is_source ? 1 : 0].id();
1095 int64 display_id = mirroring_display_id_;
1096 auto iter =
1097 std::find_if(display_info_list->begin(), display_info_list->end(),
1098 [display_id](const DisplayInfo& info) {
1099 return info.id() == display_id;
1101 DCHECK(iter != display_info_list->end());
1103 DisplayInfo info = *iter;
1104 info.SetOverscanInsets(gfx::Insets());
1105 InsertAndUpdateDisplayInfo(info);
1106 software_mirroring_display_list_.push_back(
1107 CreateDisplayFromDisplayInfoById(mirroring_display_id_));
1108 display_info_list->erase(iter);
1109 break;
1111 case UNIFIED: {
1112 // TODO(oshima): Suport displays that have different heights.
1113 // TODO(oshima): Currently, all displays are laid out horizontally,
1114 // from left to right. Allow more flexible layouts, such as
1115 // right to left, or vertical layouts.
1116 gfx::Rect unified_bounds;
1117 software_mirroring_display_list_.clear();
1118 for (auto& info : *display_info_list) {
1119 InsertAndUpdateDisplayInfo(info);
1120 gfx::Display display = CreateDisplayFromDisplayInfoById(info.id());
1121 gfx::Point origin(unified_bounds.right(), 0);
1122 display.set_bounds(gfx::Rect(origin, info.size_in_pixel()));
1123 display.UpdateWorkAreaFromInsets(gfx::Insets());
1124 unified_bounds.Union(display.bounds());
1125 software_mirroring_display_list_.push_back(display);
1127 DisplayInfo info(kUnifiedDisplayId, "Unified Desktop", false);
1128 info.SetBounds(unified_bounds);
1129 display_info_list->clear();
1130 display_info_list->push_back(info);
1131 break;
1133 case EXTENDED:
1134 break;
1139 gfx::Display* DisplayManager::FindDisplayForId(int64 id) {
1140 auto iter = std::find_if(
1141 active_display_list_.begin(), active_display_list_.end(),
1142 [id](const gfx::Display& display) { return display.id() == id; });
1143 if (iter != active_display_list_.end())
1144 return &(*iter);
1145 // TODO(oshima): This happens when a windows in unified desktop have
1146 // been moved to normal window. Fix this.
1147 if (id != kUnifiedDisplayId)
1148 DLOG(WARNING) << "Could not find display:" << id;
1149 return NULL;
1152 void DisplayManager::AddMirrorDisplayInfoIfAny(
1153 std::vector<DisplayInfo>* display_info_list) {
1154 if (software_mirroring_enabled() && IsInMirrorMode())
1155 display_info_list->push_back(GetDisplayInfo(mirroring_display_id_));
1158 void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo& new_info) {
1159 std::map<int64, DisplayInfo>::iterator info =
1160 display_info_.find(new_info.id());
1161 if (info != display_info_.end()) {
1162 info->second.Copy(new_info);
1163 } else {
1164 display_info_[new_info.id()] = new_info;
1165 display_info_[new_info.id()].set_native(false);
1167 display_info_[new_info.id()].UpdateDisplaySize();
1168 OnDisplayInfoUpdated(display_info_[new_info.id()]);
1171 void DisplayManager::OnDisplayInfoUpdated(const DisplayInfo& display_info) {
1172 #if defined(OS_CHROMEOS)
1173 ui::ColorCalibrationProfile color_profile = display_info.color_profile();
1174 if (color_profile != ui::COLOR_PROFILE_STANDARD) {
1175 Shell::GetInstance()->display_configurator()->SetColorCalibrationProfile(
1176 display_info.id(), color_profile);
1178 #endif
1181 gfx::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64 id) {
1182 DCHECK(display_info_.find(id) != display_info_.end()) << "id=" << id;
1183 const DisplayInfo& display_info = display_info_[id];
1185 gfx::Display new_display(display_info.id());
1186 gfx::Rect bounds_in_native(display_info.size_in_pixel());
1187 float device_scale_factor = display_info.GetEffectiveDeviceScaleFactor();
1189 // Simply set the origin to (0,0). The primary display's origin is
1190 // always (0,0) and the bounds of non-primary display(s) will be updated
1191 // in |UpdateNonPrimaryDisplayBoundsForLayout| called in |UpdateDisplay|.
1192 new_display.SetScaleAndBounds(
1193 device_scale_factor, gfx::Rect(bounds_in_native.size()));
1194 new_display.set_rotation(display_info.GetActiveRotation());
1195 new_display.set_touch_support(display_info.touch_support());
1196 return new_display;
1199 bool DisplayManager::UpdateNonPrimaryDisplayBoundsForLayout(
1200 DisplayList* displays,
1201 std::vector<size_t>* updated_indices) const {
1203 if (displays->size() < 2U)
1204 return false;
1206 if (displays->size() > 2U) {
1207 // For more than 2 displays, always use horizontal layout.
1208 int x_offset = displays->at(0).bounds().width();
1209 for (size_t i = 1; i < displays->size(); ++i) {
1210 gfx::Display& display = displays->at(i);
1211 const gfx::Rect& bounds = display.bounds();
1212 gfx::Point origin = gfx::Point(x_offset, 0);
1213 gfx::Insets insets = display.GetWorkAreaInsets();
1214 display.set_bounds(gfx::Rect(origin, bounds.size()));
1215 display.UpdateWorkAreaFromInsets(insets);
1216 x_offset += bounds.width();
1217 updated_indices->push_back(i);
1219 return true;
1222 int64 id_at_zero = displays->at(0).id();
1223 DisplayIdPair pair =
1224 (id_at_zero == first_display_id_ ||
1225 id_at_zero == gfx::Display::InternalDisplayId()) ?
1226 std::make_pair(id_at_zero, displays->at(1).id()) :
1227 std::make_pair(displays->at(1).id(), id_at_zero);
1228 DisplayLayout layout =
1229 layout_store_->ComputeDisplayLayoutForDisplayIdPair(pair);
1231 // Ignore if a user has a old format (should be extremely rare)
1232 // and this will be replaced with DCHECK.
1233 if (layout.primary_id != gfx::Display::kInvalidDisplayID) {
1234 size_t primary_index, secondary_index;
1235 if (displays->at(0).id() == layout.primary_id) {
1236 primary_index = 0;
1237 secondary_index = 1;
1238 } else {
1239 primary_index = 1;
1240 secondary_index = 0;
1242 // This function may be called before the secondary display is
1243 // registered. The bounds is empty in that case and will
1244 // return true.
1245 gfx::Rect bounds =
1246 GetDisplayForId(displays->at(secondary_index).id()).bounds();
1247 UpdateDisplayBoundsForLayout(
1248 layout, displays->at(primary_index), &displays->at(secondary_index));
1249 updated_indices->push_back(secondary_index);
1250 return bounds != displays->at(secondary_index).bounds();
1252 return false;
1255 void DisplayManager::CreateMirrorWindowIfAny() {
1256 if (software_mirroring_display_list_.empty() || !delegate_)
1257 return;
1258 DisplayInfoList list;
1259 for (auto& display : software_mirroring_display_list_)
1260 list.push_back(GetDisplayInfo(display.id()));
1261 delegate_->CreateOrUpdateMirroringDisplay(list);
1264 // static
1265 void DisplayManager::UpdateDisplayBoundsForLayout(
1266 const DisplayLayout& layout,
1267 const gfx::Display& primary_display,
1268 gfx::Display* secondary_display) {
1269 DCHECK_EQ("0,0", primary_display.bounds().origin().ToString());
1271 const gfx::Rect& primary_bounds = primary_display.bounds();
1272 const gfx::Rect& secondary_bounds = secondary_display->bounds();
1273 gfx::Point new_secondary_origin = primary_bounds.origin();
1275 DisplayLayout::Position position = layout.position;
1277 // Ignore the offset in case the secondary display doesn't share edges with
1278 // the primary display.
1279 int offset = layout.offset;
1280 if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM) {
1281 offset = std::min(
1282 offset, primary_bounds.width() - kMinimumOverlapForInvalidOffset);
1283 offset = std::max(
1284 offset, -secondary_bounds.width() + kMinimumOverlapForInvalidOffset);
1285 } else {
1286 offset = std::min(
1287 offset, primary_bounds.height() - kMinimumOverlapForInvalidOffset);
1288 offset = std::max(
1289 offset, -secondary_bounds.height() + kMinimumOverlapForInvalidOffset);
1291 switch (position) {
1292 case DisplayLayout::TOP:
1293 new_secondary_origin.Offset(offset, -secondary_bounds.height());
1294 break;
1295 case DisplayLayout::RIGHT:
1296 new_secondary_origin.Offset(primary_bounds.width(), offset);
1297 break;
1298 case DisplayLayout::BOTTOM:
1299 new_secondary_origin.Offset(offset, primary_bounds.height());
1300 break;
1301 case DisplayLayout::LEFT:
1302 new_secondary_origin.Offset(-secondary_bounds.width(), offset);
1303 break;
1305 gfx::Insets insets = secondary_display->GetWorkAreaInsets();
1306 secondary_display->set_bounds(
1307 gfx::Rect(new_secondary_origin, secondary_bounds.size()));
1308 secondary_display->UpdateWorkAreaFromInsets(insets);
1311 void DisplayManager::RunPendingTasksForTest() {
1312 if (!software_mirroring_display_list_.empty())
1313 base::RunLoop().RunUntilIdle();
1316 } // namespace ash