Mac: Fix performance issues with remote CoreAnimation
[chromium-blink-merge.git] / ash / display / display_manager.cc
blob90be1bd1caeeb3bbcf306d5844e1b6f19c8e7d31
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/screen_ash.h"
16 #include "ash/screen_util.h"
17 #include "ash/shell.h"
18 #include "base/auto_reset.h"
19 #include "base/command_line.h"
20 #include "base/logging.h"
21 #include "base/metrics/histogram.h"
22 #include "base/strings/string_number_conversions.h"
23 #include "base/strings/string_split.h"
24 #include "base/strings/stringprintf.h"
25 #include "base/strings/utf_string_conversions.h"
26 #include "grit/ash_strings.h"
27 #include "ui/base/l10n/l10n_util.h"
28 #include "ui/gfx/display.h"
29 #include "ui/gfx/display_observer.h"
30 #include "ui/gfx/font_render_params.h"
31 #include "ui/gfx/rect.h"
32 #include "ui/gfx/screen.h"
33 #include "ui/gfx/size_conversions.h"
35 #if defined(USE_X11)
36 #include "ui/base/x/x11_util.h"
37 #endif
39 #if defined(OS_CHROMEOS)
40 #include "ash/display/display_configurator_animation.h"
41 #include "base/sys_info.h"
42 #endif
44 #if defined(OS_WIN)
45 #include "base/win/windows_version.h"
46 #endif
48 namespace ash {
49 typedef std::vector<gfx::Display> DisplayList;
50 typedef std::vector<DisplayInfo> DisplayInfoList;
52 namespace {
54 // We need to keep this in order for unittests to tell if
55 // the object in gfx::Screen::GetScreenByType is for shutdown.
56 gfx::Screen* screen_for_shutdown = NULL;
58 // The number of pixels to overlap between the primary and secondary displays,
59 // in case that the offset value is too large.
60 const int kMinimumOverlapForInvalidOffset = 100;
62 // List of value UI Scale values. Scales for 2x are equivalent to 640,
63 // 800, 1024, 1280, 1440, 1600 and 1920 pixel width respectively on
64 // 2560 pixel width 2x density display. Please see crbug.com/233375
65 // for the full list of resolutions.
66 const float kUIScalesFor2x[] =
67 {0.5f, 0.625f, 0.8f, 1.0f, 1.125f, 1.25f, 1.5f, 2.0f};
68 const float kUIScalesFor1_25x[] = {0.5f, 0.625f, 0.8f, 1.0f, 1.25f };
69 const float kUIScalesFor1280[] = {0.5f, 0.625f, 0.8f, 1.0f, 1.125f };
70 const float kUIScalesFor1366[] = {0.5f, 0.6f, 0.75f, 1.0f, 1.125f };
72 struct DisplaySortFunctor {
73 bool operator()(const gfx::Display& a, const gfx::Display& b) {
74 return a.id() < b.id();
78 struct DisplayInfoSortFunctor {
79 bool operator()(const DisplayInfo& a, const DisplayInfo& b) {
80 return a.id() < b.id();
84 struct DisplayModeMatcher {
85 DisplayModeMatcher(const DisplayMode& target_mode)
86 : target_mode(target_mode) {}
87 bool operator()(const DisplayMode& mode) {
88 return target_mode.IsEquivalent(mode);
90 DisplayMode target_mode;
93 struct ScaleComparator {
94 explicit ScaleComparator(float s) : scale(s) {}
96 bool operator()(float s) const {
97 const float kEpsilon = 0.0001f;
98 return std::abs(scale - s) < kEpsilon;
100 float scale;
103 gfx::Display& GetInvalidDisplay() {
104 static gfx::Display* invalid_display = new gfx::Display();
105 return *invalid_display;
108 void MaybeInitInternalDisplay(int64 id) {
109 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
110 if (command_line->HasSwitch(switches::kAshUseFirstDisplayAsInternal))
111 gfx::Display::SetInternalDisplayId(id);
114 } // namespace
116 using std::string;
117 using std::vector;
119 DisplayManager::DisplayManager()
120 : delegate_(NULL),
121 screen_ash_(new ScreenAsh),
122 screen_(screen_ash_.get()),
123 layout_store_(new DisplayLayoutStore),
124 first_display_id_(gfx::Display::kInvalidDisplayID),
125 num_connected_displays_(0),
126 force_bounds_changed_(false),
127 change_display_upon_host_resize_(false),
128 second_display_mode_(EXTENDED),
129 mirrored_display_id_(gfx::Display::kInvalidDisplayID),
130 registered_internal_display_rotation_lock_(false),
131 registered_internal_display_rotation_(gfx::Display::ROTATE_0),
132 weak_ptr_factory_(this) {
134 #if defined(OS_CHROMEOS)
135 // Enable only on the device so that DisplayManagerFontTest passes.
136 if (base::SysInfo::IsRunningOnChromeOS())
137 DisplayInfo::SetUse125DSFForUIScaling(true);
139 change_display_upon_host_resize_ = !base::SysInfo::IsRunningOnChromeOS();
140 #endif
141 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE,
142 screen_ash_.get());
143 gfx::Screen* current_native =
144 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE);
145 // If there is no native, or the native was for shutdown,
146 // use ash's screen.
147 if (!current_native ||
148 current_native == screen_for_shutdown) {
149 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE,
150 screen_ash_.get());
154 DisplayManager::~DisplayManager() {
155 #if defined(OS_CHROMEOS)
156 // Reset the font params.
157 gfx::SetFontRenderParamsDeviceScaleFactor(1.0f);
158 #endif
161 // static
162 std::vector<float> DisplayManager::GetScalesForDisplay(
163 const DisplayInfo& info) {
165 #define ASSIGN_ARRAY(v, a) v.assign(a, a + arraysize(a))
167 std::vector<float> ret;
168 if (info.device_scale_factor() == 2.0f) {
169 ASSIGN_ARRAY(ret, kUIScalesFor2x);
170 return ret;
171 } else if (info.device_scale_factor() == 1.25f) {
172 ASSIGN_ARRAY(ret, kUIScalesFor1_25x);
173 return ret;
175 switch (info.bounds_in_native().width()) {
176 case 1280:
177 ASSIGN_ARRAY(ret, kUIScalesFor1280);
178 break;
179 case 1366:
180 ASSIGN_ARRAY(ret, kUIScalesFor1366);
181 break;
182 default:
183 ASSIGN_ARRAY(ret, kUIScalesFor1280);
184 #if defined(OS_CHROMEOS)
185 if (base::SysInfo::IsRunningOnChromeOS())
186 NOTREACHED() << "Unknown resolution:" << info.ToString();
187 #endif
189 return ret;
192 // static
193 float DisplayManager::GetNextUIScale(const DisplayInfo& info, bool up) {
194 float scale = info.configured_ui_scale();
195 std::vector<float> scales = GetScalesForDisplay(info);
196 for (size_t i = 0; i < scales.size(); ++i) {
197 if (ScaleComparator(scales[i])(scale)) {
198 if (up && i != scales.size() - 1)
199 return scales[i + 1];
200 if (!up && i != 0)
201 return scales[i - 1];
202 return scales[i];
205 // Fallback to 1.0f if the |scale| wasn't in the list.
206 return 1.0f;
209 bool DisplayManager::InitFromCommandLine() {
210 DisplayInfoList info_list;
211 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
212 if (!command_line->HasSwitch(switches::kAshHostWindowBounds))
213 return false;
214 const string size_str =
215 command_line->GetSwitchValueASCII(switches::kAshHostWindowBounds);
216 vector<string> parts;
217 base::SplitString(size_str, ',', &parts);
218 for (vector<string>::const_iterator iter = parts.begin();
219 iter != parts.end(); ++iter) {
220 info_list.push_back(DisplayInfo::CreateFromSpec(*iter));
221 info_list.back().set_native(true);
223 MaybeInitInternalDisplay(info_list[0].id());
224 if (info_list.size() > 1 &&
225 command_line->HasSwitch(switches::kAshEnableSoftwareMirroring)) {
226 SetSecondDisplayMode(MIRRORING);
228 OnNativeDisplaysChanged(info_list);
229 return true;
232 void DisplayManager::InitDefaultDisplay() {
233 DisplayInfoList info_list;
234 info_list.push_back(DisplayInfo::CreateFromSpec(std::string()));
235 info_list.back().set_native(true);
236 MaybeInitInternalDisplay(info_list[0].id());
237 OnNativeDisplaysChanged(info_list);
240 void DisplayManager::InitFontParams() {
241 #if defined(OS_CHROMEOS)
242 if (!HasInternalDisplay())
243 return;
244 const DisplayInfo& display_info =
245 GetDisplayInfo(gfx::Display::InternalDisplayId());
246 gfx::SetFontRenderParamsDeviceScaleFactor(
247 display_info.GetEffectiveDeviceScaleFactor());
248 #endif // OS_CHROMEOS
251 // static
252 void DisplayManager::UpdateDisplayBoundsForLayoutById(
253 const DisplayLayout& layout,
254 const gfx::Display& primary_display,
255 int64 secondary_display_id) {
256 DCHECK_NE(gfx::Display::kInvalidDisplayID, secondary_display_id);
257 UpdateDisplayBoundsForLayout(
258 layout, primary_display,
259 Shell::GetInstance()->display_manager()->
260 FindDisplayForId(secondary_display_id));
263 bool DisplayManager::IsActiveDisplay(const gfx::Display& display) const {
264 for (DisplayList::const_iterator iter = displays_.begin();
265 iter != displays_.end(); ++iter) {
266 if ((*iter).id() == display.id())
267 return true;
269 return false;
272 bool DisplayManager::HasInternalDisplay() const {
273 return gfx::Display::InternalDisplayId() != gfx::Display::kInvalidDisplayID;
276 bool DisplayManager::IsInternalDisplayId(int64 id) const {
277 return gfx::Display::InternalDisplayId() == id;
280 DisplayLayout DisplayManager::GetCurrentDisplayLayout() {
281 DCHECK_EQ(2U, num_connected_displays());
282 // Invert if the primary was swapped.
283 if (num_connected_displays() > 1) {
284 DisplayIdPair pair = GetCurrentDisplayIdPair();
285 return layout_store_->ComputeDisplayLayoutForDisplayIdPair(pair);
287 NOTREACHED() << "DisplayLayout is requested for single display";
288 // On release build, just fallback to default instead of blowing up.
289 DisplayLayout layout =
290 layout_store_->default_display_layout();
291 layout.primary_id = displays_[0].id();
292 return layout;
295 DisplayIdPair DisplayManager::GetCurrentDisplayIdPair() const {
296 if (IsMirrored()) {
297 if (software_mirroring_enabled()) {
298 CHECK_EQ(2u, num_connected_displays());
299 // This comment is to make it easy to distinguish the crash
300 // between two checks.
301 CHECK_EQ(1u, displays_.size());
303 return std::make_pair(displays_[0].id(), mirrored_display_id_);
304 } else {
305 CHECK_GE(2u, displays_.size());
306 int64 id_at_zero = displays_[0].id();
307 if (id_at_zero == gfx::Display::InternalDisplayId() ||
308 id_at_zero == first_display_id()) {
309 return std::make_pair(id_at_zero, displays_[1].id());
310 } else {
311 return std::make_pair(displays_[1].id(), id_at_zero);
316 void DisplayManager::SetLayoutForCurrentDisplays(
317 const DisplayLayout& layout_relative_to_primary) {
318 DCHECK_EQ(2U, GetNumDisplays());
319 if (GetNumDisplays() < 2)
320 return;
321 const gfx::Display& primary = screen_->GetPrimaryDisplay();
322 const DisplayIdPair pair = GetCurrentDisplayIdPair();
323 // Invert if the primary was swapped.
324 DisplayLayout to_set = pair.first == primary.id() ?
325 layout_relative_to_primary : layout_relative_to_primary.Invert();
327 DisplayLayout current_layout =
328 layout_store_->GetRegisteredDisplayLayout(pair);
329 if (to_set.position != current_layout.position ||
330 to_set.offset != current_layout.offset) {
331 to_set.primary_id = primary.id();
332 layout_store_->RegisterLayoutForDisplayIdPair(
333 pair.first, pair.second, to_set);
334 if (delegate_)
335 delegate_->PreDisplayConfigurationChange(false);
336 // PreDisplayConfigurationChange(false);
337 // TODO(oshima): Call UpdateDisplays instead.
338 const DisplayLayout layout = GetCurrentDisplayLayout();
339 UpdateDisplayBoundsForLayoutById(
340 layout, primary,
341 ScreenUtil::GetSecondaryDisplay().id());
343 // Primary's bounds stay the same. Just notify bounds change
344 // on the secondary.
345 screen_ash_->NotifyMetricsChanged(
346 ScreenUtil::GetSecondaryDisplay(),
347 gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
348 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
349 if (delegate_)
350 delegate_->PostDisplayConfigurationChange();
354 const gfx::Display& DisplayManager::GetDisplayForId(int64 id) const {
355 gfx::Display* display =
356 const_cast<DisplayManager*>(this)->FindDisplayForId(id);
357 return display ? *display : GetInvalidDisplay();
360 const gfx::Display& DisplayManager::FindDisplayContainingPoint(
361 const gfx::Point& point_in_screen) const {
362 for (DisplayList::const_iterator iter = displays_.begin();
363 iter != displays_.end(); ++iter) {
364 const gfx::Display& display = *iter;
365 if (display.bounds().Contains(point_in_screen))
366 return display;
368 return GetInvalidDisplay();
371 bool DisplayManager::UpdateWorkAreaOfDisplay(int64 display_id,
372 const gfx::Insets& insets) {
373 gfx::Display* display = FindDisplayForId(display_id);
374 DCHECK(display);
375 gfx::Rect old_work_area = display->work_area();
376 display->UpdateWorkAreaFromInsets(insets);
377 return old_work_area != display->work_area();
380 void DisplayManager::SetOverscanInsets(int64 display_id,
381 const gfx::Insets& insets_in_dip) {
382 display_info_[display_id].SetOverscanInsets(insets_in_dip);
383 DisplayInfoList display_info_list;
384 for (DisplayList::const_iterator iter = displays_.begin();
385 iter != displays_.end(); ++iter) {
386 display_info_list.push_back(GetDisplayInfo(iter->id()));
388 AddMirrorDisplayInfoIfAny(&display_info_list);
389 UpdateDisplays(display_info_list);
392 void DisplayManager::SetDisplayRotation(int64 display_id,
393 gfx::Display::Rotation rotation) {
394 DisplayInfoList display_info_list;
395 for (DisplayList::const_iterator iter = displays_.begin();
396 iter != displays_.end(); ++iter) {
397 DisplayInfo info = GetDisplayInfo(iter->id());
398 if (info.id() == display_id) {
399 if (info.rotation() == rotation)
400 return;
401 info.set_rotation(rotation);
403 display_info_list.push_back(info);
405 AddMirrorDisplayInfoIfAny(&display_info_list);
406 UpdateDisplays(display_info_list);
409 void DisplayManager::SetDisplayUIScale(int64 display_id,
410 float ui_scale) {
411 if (!IsDisplayUIScalingEnabled() ||
412 gfx::Display::InternalDisplayId() != display_id) {
413 return;
416 // TODO(mukai): merge this implementation into SetDisplayMode().
417 DisplayInfoList display_info_list;
418 for (DisplayList::const_iterator iter = displays_.begin();
419 iter != displays_.end(); ++iter) {
420 DisplayInfo info = GetDisplayInfo(iter->id());
421 if (info.id() == display_id) {
422 if (info.configured_ui_scale() == ui_scale)
423 return;
424 std::vector<float> scales = GetScalesForDisplay(info);
425 ScaleComparator comparator(ui_scale);
426 if (std::find_if(scales.begin(), scales.end(), comparator) ==
427 scales.end()) {
428 return;
430 info.set_configured_ui_scale(ui_scale);
432 display_info_list.push_back(info);
434 AddMirrorDisplayInfoIfAny(&display_info_list);
435 UpdateDisplays(display_info_list);
438 void DisplayManager::SetDisplayResolution(int64 display_id,
439 const gfx::Size& resolution) {
440 DCHECK_NE(gfx::Display::InternalDisplayId(), display_id);
441 if (gfx::Display::InternalDisplayId() == display_id)
442 return;
443 const DisplayInfo& display_info = GetDisplayInfo(display_id);
444 const std::vector<DisplayMode>& modes = display_info.display_modes();
445 DCHECK_NE(0u, modes.size());
446 DisplayMode target_mode;
447 target_mode.size = resolution;
448 std::vector<DisplayMode>::const_iterator iter =
449 std::find_if(modes.begin(), modes.end(), DisplayModeMatcher(target_mode));
450 if (iter == modes.end()) {
451 LOG(WARNING) << "Unsupported resolution was requested:"
452 << resolution.ToString();
453 return;
455 display_modes_[display_id] = *iter;
456 #if defined(OS_CHROMEOS)
457 if (base::SysInfo::IsRunningOnChromeOS())
458 Shell::GetInstance()->display_configurator()->OnConfigurationChanged();
459 #endif
462 bool DisplayManager::SetDisplayMode(int64 display_id,
463 const DisplayMode& display_mode) {
464 if (IsInternalDisplayId(display_id)) {
465 SetDisplayUIScale(display_id, display_mode.ui_scale);
466 return false;
469 DisplayInfoList display_info_list;
470 bool display_property_changed = false;
471 bool resolution_changed = false;
472 for (DisplayList::const_iterator iter = displays_.begin();
473 iter != displays_.end(); ++iter) {
474 DisplayInfo info = GetDisplayInfo(iter->id());
475 if (info.id() == display_id) {
476 const std::vector<DisplayMode>& modes = info.display_modes();
477 std::vector<DisplayMode>::const_iterator iter =
478 std::find_if(modes.begin(),
479 modes.end(),
480 DisplayModeMatcher(display_mode));
481 if (iter == modes.end()) {
482 LOG(WARNING) << "Unsupported resolution was requested:"
483 << display_mode.size.ToString();
484 return false;
486 display_modes_[display_id] = *iter;
487 if (info.bounds_in_native().size() != display_mode.size)
488 resolution_changed = true;
489 if (info.device_scale_factor() != display_mode.device_scale_factor) {
490 info.set_device_scale_factor(display_mode.device_scale_factor);
491 display_property_changed = true;
494 display_info_list.push_back(info);
496 if (display_property_changed) {
497 AddMirrorDisplayInfoIfAny(&display_info_list);
498 UpdateDisplays(display_info_list);
500 #if defined(OS_CHROMEOS)
501 if (resolution_changed && base::SysInfo::IsRunningOnChromeOS())
502 Shell::GetInstance()->display_configurator()->OnConfigurationChanged();
503 #endif
504 return resolution_changed;
507 void DisplayManager::RegisterDisplayProperty(
508 int64 display_id,
509 gfx::Display::Rotation rotation,
510 float ui_scale,
511 const gfx::Insets* overscan_insets,
512 const gfx::Size& resolution_in_pixels,
513 float device_scale_factor,
514 ui::ColorCalibrationProfile color_profile) {
515 if (display_info_.find(display_id) == display_info_.end())
516 display_info_[display_id] = DisplayInfo(display_id, std::string(), false);
518 display_info_[display_id].set_rotation(rotation);
519 display_info_[display_id].SetColorProfile(color_profile);
520 // Just in case the preference file was corrupted.
521 // TODO(mukai): register |display_modes_| here as well, so the lookup for the
522 // default mode in GetActiveModeForDisplayId() gets much simpler.
523 if (0.5f <= ui_scale && ui_scale <= 2.0f)
524 display_info_[display_id].set_configured_ui_scale(ui_scale);
525 if (overscan_insets)
526 display_info_[display_id].SetOverscanInsets(*overscan_insets);
527 if (!resolution_in_pixels.IsEmpty()) {
528 DCHECK(!IsInternalDisplayId(display_id));
529 // Default refresh rate, until OnNativeDisplaysChanged() updates us with the
530 // actual display info, is 60 Hz.
531 DisplayMode mode(resolution_in_pixels, 60.0f, false, false);
532 mode.device_scale_factor = device_scale_factor;
533 display_modes_[display_id] = mode;
537 DisplayMode DisplayManager::GetActiveModeForDisplayId(int64 display_id) const {
538 DisplayMode selected_mode;
539 if (GetSelectedModeForDisplayId(display_id, &selected_mode))
540 return selected_mode;
542 // If 'selected' mode is empty, it should return the default mode. This means
543 // the native mode for the external display. Unfortunately this is not true
544 // for the internal display because restoring UI-scale doesn't register the
545 // restored mode to |display_mode_|, so it needs to look up the mode whose
546 // UI-scale value matches. See the TODO in RegisterDisplayProperty().
547 const DisplayInfo& info = GetDisplayInfo(display_id);
548 const std::vector<DisplayMode>& display_modes = info.display_modes();
550 if (IsInternalDisplayId(display_id)) {
551 for (size_t i = 0; i < display_modes.size(); ++i) {
552 if (info.configured_ui_scale() == display_modes[i].ui_scale)
553 return display_modes[i];
555 } else {
556 for (size_t i = 0; i < display_modes.size(); ++i) {
557 if (display_modes[i].native)
558 return display_modes[i];
561 return selected_mode;
564 void DisplayManager::RegisterDisplayRotationProperties(bool rotation_lock,
565 gfx::Display::Rotation rotation) {
566 if (delegate_)
567 delegate_->PreDisplayConfigurationChange(false);
568 registered_internal_display_rotation_lock_ = rotation_lock;
569 registered_internal_display_rotation_ = rotation;
570 if (delegate_)
571 delegate_->PostDisplayConfigurationChange();
574 bool DisplayManager::GetSelectedModeForDisplayId(int64 id,
575 DisplayMode* mode_out) const {
576 std::map<int64, DisplayMode>::const_iterator iter = display_modes_.find(id);
577 if (iter == display_modes_.end())
578 return false;
579 *mode_out = iter->second;
580 return true;
583 bool DisplayManager::IsDisplayUIScalingEnabled() const {
584 return GetDisplayIdForUIScaling() != gfx::Display::kInvalidDisplayID;
587 gfx::Insets DisplayManager::GetOverscanInsets(int64 display_id) const {
588 std::map<int64, DisplayInfo>::const_iterator it =
589 display_info_.find(display_id);
590 return (it != display_info_.end()) ?
591 it->second.overscan_insets_in_dip() : gfx::Insets();
594 void DisplayManager::SetColorCalibrationProfile(
595 int64 display_id,
596 ui::ColorCalibrationProfile profile) {
597 #if defined(OS_CHROMEOS)
598 if (!display_info_[display_id].IsColorProfileAvailable(profile))
599 return;
601 if (delegate_)
602 delegate_->PreDisplayConfigurationChange(false);
603 // Just sets color profile if it's not running on ChromeOS (like tests).
604 if (!base::SysInfo::IsRunningOnChromeOS() ||
605 Shell::GetInstance()->display_configurator()->SetColorCalibrationProfile(
606 display_id, profile)) {
607 display_info_[display_id].SetColorProfile(profile);
608 UMA_HISTOGRAM_ENUMERATION(
609 "ChromeOS.Display.ColorProfile", profile, ui::NUM_COLOR_PROFILES);
611 if (delegate_)
612 delegate_->PostDisplayConfigurationChange();
613 #endif
616 void DisplayManager::OnNativeDisplaysChanged(
617 const std::vector<DisplayInfo>& updated_displays) {
618 if (updated_displays.empty()) {
619 VLOG(1) << "OnNativeDisplaysChanged(0): # of current displays="
620 << displays_.size();
621 // If the device is booted without display, or chrome is started
622 // without --ash-host-window-bounds on linux desktop, use the
623 // default display.
624 if (displays_.empty()) {
625 std::vector<DisplayInfo> init_displays;
626 init_displays.push_back(DisplayInfo::CreateFromSpec(std::string()));
627 MaybeInitInternalDisplay(init_displays[0].id());
628 OnNativeDisplaysChanged(init_displays);
629 } else {
630 // Otherwise don't update the displays when all displays are disconnected.
631 // This happens when:
632 // - the device is idle and powerd requested to turn off all displays.
633 // - the device is suspended. (kernel turns off all displays)
634 // - the internal display's brightness is set to 0 and no external
635 // display is connected.
636 // - the internal display's brightness is 0 and external display is
637 // disconnected.
638 // The display will be updated when one of displays is turned on, and the
639 // display list will be updated correctly.
641 return;
643 first_display_id_ = updated_displays[0].id();
644 std::set<gfx::Point> origins;
646 if (updated_displays.size() == 1) {
647 VLOG(1) << "OnNativeDisplaysChanged(1):" << updated_displays[0].ToString();
648 } else {
649 VLOG(1) << "OnNativeDisplaysChanged(" << updated_displays.size()
650 << ") [0]=" << updated_displays[0].ToString()
651 << ", [1]=" << updated_displays[1].ToString();
654 bool internal_display_connected = false;
655 num_connected_displays_ = updated_displays.size();
656 mirrored_display_id_ = gfx::Display::kInvalidDisplayID;
657 mirroring_display_ = gfx::Display();
658 DisplayInfoList new_display_info_list;
659 for (DisplayInfoList::const_iterator iter = updated_displays.begin();
660 iter != updated_displays.end();
661 ++iter) {
662 if (!internal_display_connected)
663 internal_display_connected = IsInternalDisplayId(iter->id());
664 // Mirrored monitors have the same origins.
665 gfx::Point origin = iter->bounds_in_native().origin();
666 if (origins.find(origin) != origins.end()) {
667 InsertAndUpdateDisplayInfo(*iter);
668 mirrored_display_id_ = iter->id();
669 } else {
670 origins.insert(origin);
671 new_display_info_list.push_back(*iter);
674 DisplayMode new_mode;
675 new_mode.size = iter->bounds_in_native().size();
676 new_mode.device_scale_factor = iter->device_scale_factor();
677 new_mode.ui_scale = iter->configured_ui_scale();
678 const std::vector<DisplayMode>& display_modes = iter->display_modes();
679 // This is empty the displays are initialized from InitFromCommandLine.
680 if (!display_modes.size())
681 continue;
682 std::vector<DisplayMode>::const_iterator display_modes_iter =
683 std::find_if(display_modes.begin(),
684 display_modes.end(),
685 DisplayModeMatcher(new_mode));
686 // Update the actual resolution selected as the resolution request may fail.
687 if (display_modes_iter == display_modes.end())
688 display_modes_.erase(iter->id());
689 else if (display_modes_.find(iter->id()) != display_modes_.end())
690 display_modes_[iter->id()] = *display_modes_iter;
692 if (HasInternalDisplay() &&
693 !internal_display_connected &&
694 display_info_.find(gfx::Display::InternalDisplayId()) ==
695 display_info_.end()) {
696 DisplayInfo internal_display_info(
697 gfx::Display::InternalDisplayId(),
698 l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME),
699 false /*Internal display must not have overscan */);
700 internal_display_info.SetBounds(gfx::Rect(0, 0, 800, 600));
701 display_info_[gfx::Display::InternalDisplayId()] = internal_display_info;
703 UpdateDisplays(new_display_info_list);
706 void DisplayManager::UpdateDisplays() {
707 DisplayInfoList display_info_list;
708 for (DisplayList::const_iterator iter = displays_.begin();
709 iter != displays_.end(); ++iter) {
710 display_info_list.push_back(GetDisplayInfo(iter->id()));
712 AddMirrorDisplayInfoIfAny(&display_info_list);
713 UpdateDisplays(display_info_list);
716 void DisplayManager::UpdateDisplays(
717 const std::vector<DisplayInfo>& updated_display_info_list) {
718 #if defined(OS_WIN)
719 DCHECK_EQ(1u, updated_display_info_list.size()) <<
720 ": Multiple display test does not work on Windows bots. Please "
721 "skip (don't disable) the test using SupportsMultipleDisplays()";
722 #endif
724 DisplayInfoList new_display_info_list = updated_display_info_list;
725 std::sort(displays_.begin(), displays_.end(), DisplaySortFunctor());
726 std::sort(new_display_info_list.begin(),
727 new_display_info_list.end(),
728 DisplayInfoSortFunctor());
729 DisplayList removed_displays;
730 std::map<size_t, uint32_t> display_changes;
731 std::vector<size_t> added_display_indices;
733 DisplayList::iterator curr_iter = displays_.begin();
734 DisplayInfoList::const_iterator new_info_iter = new_display_info_list.begin();
736 DisplayList new_displays;
738 // Use the internal display or 1st as the mirror source, then scale
739 // the root window so that it matches the external display's
740 // resolution. This is necessary in order for scaling to work while
741 // mirrored.
742 int64 mirroing_display_id = gfx::Display::kInvalidDisplayID;
744 if (second_display_mode_ != EXTENDED && new_display_info_list.size() == 2) {
745 bool zero_is_source =
746 first_display_id_ == new_display_info_list[0].id() ||
747 gfx::Display::InternalDisplayId() == new_display_info_list[0].id();
748 DCHECK_EQ(MIRRORING, second_display_mode_);
749 mirrored_display_id_ = new_display_info_list[zero_is_source ? 1 : 0].id();
750 mirroing_display_id = mirrored_display_id_;
753 while (curr_iter != displays_.end() ||
754 new_info_iter != new_display_info_list.end()) {
755 if (new_info_iter != new_display_info_list.end() &&
756 mirroing_display_id == new_info_iter->id()) {
757 DisplayInfo info = *new_info_iter;
758 info.SetOverscanInsets(gfx::Insets());
759 InsertAndUpdateDisplayInfo(info);
760 mirroring_display_ =
761 CreateDisplayFromDisplayInfoById(mirroing_display_id);
762 ++new_info_iter;
763 // Remove existing external display if it is going to be used as
764 // mirroring display.
765 if (curr_iter != displays_.end() &&
766 curr_iter->id() == mirroing_display_id) {
767 removed_displays.push_back(*curr_iter);
768 ++curr_iter;
770 continue;
773 if (curr_iter == displays_.end()) {
774 // more displays in new list.
775 added_display_indices.push_back(new_displays.size());
776 InsertAndUpdateDisplayInfo(*new_info_iter);
777 new_displays.push_back(
778 CreateDisplayFromDisplayInfoById(new_info_iter->id()));
779 ++new_info_iter;
780 } else if (new_info_iter == new_display_info_list.end()) {
781 // more displays in current list.
782 removed_displays.push_back(*curr_iter);
783 ++curr_iter;
784 } else if (curr_iter->id() == new_info_iter->id()) {
785 const gfx::Display& current_display = *curr_iter;
786 // Copy the info because |CreateDisplayFromInfo| updates the instance.
787 const DisplayInfo current_display_info =
788 GetDisplayInfo(current_display.id());
789 InsertAndUpdateDisplayInfo(*new_info_iter);
790 gfx::Display new_display =
791 CreateDisplayFromDisplayInfoById(new_info_iter->id());
792 const DisplayInfo& new_display_info = GetDisplayInfo(new_display.id());
794 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_NONE;
796 // At that point the new Display objects we have are not entirely updated,
797 // they are missing the translation related to the Display disposition in
798 // the layout.
799 // Using display.bounds() and display.work_area() would fail most of the
800 // time.
801 if (force_bounds_changed_ ||
802 (current_display_info.bounds_in_native() !=
803 new_display_info.bounds_in_native()) ||
804 (current_display_info.size_in_pixel() !=
805 new_display.GetSizeInPixel()) ||
806 current_display.size() != new_display.size()) {
807 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
808 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
811 if (current_display.device_scale_factor() !=
812 new_display.device_scale_factor()) {
813 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
816 if (current_display.rotation() != new_display.rotation())
817 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_ROTATION;
819 if (metrics != gfx::DisplayObserver::DISPLAY_METRIC_NONE) {
820 display_changes.insert(
821 std::pair<size_t, uint32_t>(new_displays.size(), metrics));
824 new_display.UpdateWorkAreaFromInsets(current_display.GetWorkAreaInsets());
825 new_displays.push_back(new_display);
826 ++curr_iter;
827 ++new_info_iter;
828 } else if (curr_iter->id() < new_info_iter->id()) {
829 // more displays in current list between ids, which means it is deleted.
830 removed_displays.push_back(*curr_iter);
831 ++curr_iter;
832 } else {
833 // more displays in new list between ids, which means it is added.
834 added_display_indices.push_back(new_displays.size());
835 InsertAndUpdateDisplayInfo(*new_info_iter);
836 new_displays.push_back(
837 CreateDisplayFromDisplayInfoById(new_info_iter->id()));
838 ++new_info_iter;
841 gfx::Display old_primary;
842 if (delegate_)
843 old_primary = screen_ash_->GetPrimaryDisplay();
845 // Clear focus if the display has been removed, but don't clear focus if
846 // the destkop has been moved from one display to another
847 // (mirror -> docked, docked -> single internal).
848 bool clear_focus =
849 !removed_displays.empty() &&
850 !(removed_displays.size() == 1 && added_display_indices.size() == 1);
851 if (delegate_)
852 delegate_->PreDisplayConfigurationChange(clear_focus);
854 // Do not update |displays_| if there's nothing to be updated. Without this,
855 // it will not update the display layout, which causes the bug
856 // http://crbug.com/155948.
857 if (display_changes.empty() && added_display_indices.empty() &&
858 removed_displays.empty()) {
859 // When changing from software mirroring mode to sinlge display mode, it
860 // is possible there is no need to update |displays_| and we early out
861 // here. But we still want to run the PostDisplayConfigurationChange()
862 // cause there are some clients need to act on this, e.g.
863 // TouchTransformerController needs to adjust the TouchTransformer when
864 // switching from dual displays to single display.
865 if (delegate_)
866 delegate_->PostDisplayConfigurationChange();
867 return;
870 size_t updated_index;
871 if (UpdateSecondaryDisplayBoundsForLayout(&new_displays, &updated_index) &&
872 std::find(added_display_indices.begin(),
873 added_display_indices.end(),
874 updated_index) == added_display_indices.end()) {
875 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
876 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
877 if (display_changes.find(updated_index) != display_changes.end())
878 metrics |= display_changes[updated_index];
880 display_changes[updated_index] = metrics;
883 displays_ = new_displays;
885 base::AutoReset<bool> resetter(&change_display_upon_host_resize_, false);
887 // Temporarily add displays to be removed because display object
888 // being removed are accessed during shutting down the root.
889 displays_.insert(displays_.end(), removed_displays.begin(),
890 removed_displays.end());
892 for (DisplayList::const_reverse_iterator iter = removed_displays.rbegin();
893 iter != removed_displays.rend(); ++iter) {
894 screen_ash_->NotifyDisplayRemoved(displays_.back());
895 displays_.pop_back();
898 bool has_mirroring_display = HasSoftwareMirroringDisplay();
899 // Close the mirroring window here to avoid creating two compositor on
900 // one display.
901 if (!has_mirroring_display && delegate_)
902 delegate_->CloseMirroringDisplay();
904 for (std::vector<size_t>::iterator iter = added_display_indices.begin();
905 iter != added_display_indices.end(); ++iter) {
906 screen_ash_->NotifyDisplayAdded(displays_[*iter]);
909 bool notify_primary_change =
910 delegate_ ? old_primary.id() != screen_->GetPrimaryDisplay().id() : false;
912 for (std::map<size_t, uint32_t>::iterator iter = display_changes.begin();
913 iter != display_changes.end();
914 ++iter) {
915 uint32_t metrics = iter->second;
916 const gfx::Display& updated_display = displays_[iter->first];
918 if (notify_primary_change &&
919 updated_display.id() == screen_->GetPrimaryDisplay().id()) {
920 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_PRIMARY;
921 notify_primary_change = false;
923 screen_ash_->NotifyMetricsChanged(updated_display, metrics);
926 if (notify_primary_change) {
927 // This happens when a primary display has moved to anther display without
928 // bounds change.
929 const gfx::Display& primary = screen_->GetPrimaryDisplay();
930 if (primary.id() != old_primary.id()) {
931 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_PRIMARY;
932 if (primary.size() != old_primary.size()) {
933 metrics |= (gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
934 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
936 if (primary.device_scale_factor() != old_primary.device_scale_factor())
937 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
939 screen_ash_->NotifyMetricsChanged(primary, metrics);
943 if (delegate_)
944 delegate_->PostDisplayConfigurationChange();
946 #if defined(USE_X11) && defined(OS_CHROMEOS)
947 if (!display_changes.empty() && base::SysInfo::IsRunningOnChromeOS())
948 ui::ClearX11DefaultRootWindow();
949 #endif
951 // Create the mirroring window asynchronously after all displays
952 // are added so that it can mirror the display newly added. This can
953 // happen when switching from dock mode to software mirror mode.
954 if (has_mirroring_display && delegate_)
955 CreateMirrorWindowAsyncIfAny();
958 const gfx::Display& DisplayManager::GetDisplayAt(size_t index) const {
959 DCHECK_LT(index, displays_.size());
960 return displays_[index];
963 const gfx::Display& DisplayManager::GetPrimaryDisplayCandidate() const {
964 if (GetNumDisplays() == 1)
965 return displays_[0];
966 DisplayLayout layout = layout_store_->GetRegisteredDisplayLayout(
967 GetCurrentDisplayIdPair());
968 return GetDisplayForId(layout.primary_id);
971 size_t DisplayManager::GetNumDisplays() const {
972 return displays_.size();
975 bool DisplayManager::IsMirrored() const {
976 return mirrored_display_id_ != gfx::Display::kInvalidDisplayID;
979 const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const {
980 DCHECK_NE(gfx::Display::kInvalidDisplayID, display_id);
982 std::map<int64, DisplayInfo>::const_iterator iter =
983 display_info_.find(display_id);
984 CHECK(iter != display_info_.end()) << display_id;
985 return iter->second;
988 std::string DisplayManager::GetDisplayNameForId(int64 id) {
989 if (id == gfx::Display::kInvalidDisplayID)
990 return l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME);
992 std::map<int64, DisplayInfo>::const_iterator iter = display_info_.find(id);
993 if (iter != display_info_.end() && !iter->second.name().empty())
994 return iter->second.name();
996 return base::StringPrintf("Display %d", static_cast<int>(id));
999 int64 DisplayManager::GetDisplayIdForUIScaling() const {
1000 // UI Scaling is effective only on internal display.
1001 int64 display_id = gfx::Display::InternalDisplayId();
1002 #if defined(OS_WIN)
1003 display_id = first_display_id();
1004 #endif
1005 return display_id;
1008 void DisplayManager::SetMirrorMode(bool mirrored) {
1009 if (num_connected_displays() <= 1)
1010 return;
1012 #if defined(OS_CHROMEOS)
1013 if (base::SysInfo::IsRunningOnChromeOS()) {
1014 ui::MultipleDisplayState new_state =
1015 mirrored ? ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR :
1016 ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
1017 Shell::GetInstance()->display_configurator()->SetDisplayMode(new_state);
1018 return;
1020 #endif
1021 // This is fallback path to emulate mirroroing on desktop.
1022 SetSecondDisplayMode(mirrored ? MIRRORING : EXTENDED);
1023 DisplayInfoList display_info_list;
1024 int count = 0;
1025 for (std::map<int64, DisplayInfo>::const_iterator iter =
1026 display_info_.begin();
1027 count < 2; ++iter, ++count) {
1028 display_info_list.push_back(GetDisplayInfo(iter->second.id()));
1030 UpdateDisplays(display_info_list);
1031 #if defined(OS_CHROMEOS)
1032 if (Shell::GetInstance()->display_configurator_animation()) {
1033 Shell::GetInstance()->display_configurator_animation()->
1034 StartFadeInAnimation();
1036 #endif
1039 void DisplayManager::AddRemoveDisplay() {
1040 DCHECK(!displays_.empty());
1041 std::vector<DisplayInfo> new_display_info_list;
1042 const DisplayInfo& first_display = GetDisplayInfo(displays_[0].id());
1043 new_display_info_list.push_back(first_display);
1044 // Add if there is only one display connected.
1045 if (num_connected_displays() == 1) {
1046 // Layout the 2nd display below the primary as with the real device.
1047 gfx::Rect host_bounds = first_display.bounds_in_native();
1048 new_display_info_list.push_back(DisplayInfo::CreateFromSpec(
1049 base::StringPrintf(
1050 "%d+%d-500x400", host_bounds.x(), host_bounds.bottom())));
1052 num_connected_displays_ = new_display_info_list.size();
1053 mirrored_display_id_ = gfx::Display::kInvalidDisplayID;
1054 mirroring_display_ = gfx::Display();
1055 UpdateDisplays(new_display_info_list);
1058 void DisplayManager::ToggleDisplayScaleFactor() {
1059 DCHECK(!displays_.empty());
1060 std::vector<DisplayInfo> new_display_info_list;
1061 for (DisplayList::const_iterator iter = displays_.begin();
1062 iter != displays_.end(); ++iter) {
1063 DisplayInfo display_info = GetDisplayInfo(iter->id());
1064 display_info.set_device_scale_factor(
1065 display_info.device_scale_factor() == 1.0f ? 2.0f : 1.0f);
1066 new_display_info_list.push_back(display_info);
1068 AddMirrorDisplayInfoIfAny(&new_display_info_list);
1069 UpdateDisplays(new_display_info_list);
1072 #if defined(OS_CHROMEOS)
1073 void DisplayManager::SetSoftwareMirroring(bool enabled) {
1074 SetSecondDisplayMode(enabled ? MIRRORING : EXTENDED);
1077 bool DisplayManager::SoftwareMirroringEnabled() const {
1078 return software_mirroring_enabled();
1080 #endif
1082 void DisplayManager::SetSecondDisplayMode(SecondDisplayMode mode) {
1083 second_display_mode_ = mode;
1084 mirrored_display_id_ = gfx::Display::kInvalidDisplayID;
1085 mirroring_display_ = gfx::Display();
1088 bool DisplayManager::UpdateDisplayBounds(int64 display_id,
1089 const gfx::Rect& new_bounds) {
1090 if (change_display_upon_host_resize_) {
1091 display_info_[display_id].SetBounds(new_bounds);
1092 // Don't notify observers if the mirrored window has changed.
1093 if (software_mirroring_enabled() && mirrored_display_id_ == display_id)
1094 return false;
1095 gfx::Display* display = FindDisplayForId(display_id);
1096 display->SetSize(display_info_[display_id].size_in_pixel());
1097 screen_ash_->NotifyMetricsChanged(
1098 *display, gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS);
1099 return true;
1101 return false;
1104 void DisplayManager::CreateMirrorWindowAsyncIfAny() {
1105 base::MessageLoopForUI::current()->PostTask(
1106 FROM_HERE,
1107 base::Bind(&DisplayManager::CreateMirrorWindowIfAny,
1108 weak_ptr_factory_.GetWeakPtr()));
1111 void DisplayManager::CreateScreenForShutdown() const {
1112 bool native_is_ash =
1113 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE) ==
1114 screen_ash_.get();
1115 delete screen_for_shutdown;
1116 screen_for_shutdown = screen_ash_->CloneForShutdown();
1117 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE,
1118 screen_for_shutdown);
1119 if (native_is_ash) {
1120 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE,
1121 screen_for_shutdown);
1125 gfx::Display* DisplayManager::FindDisplayForId(int64 id) {
1126 for (DisplayList::iterator iter = displays_.begin();
1127 iter != displays_.end(); ++iter) {
1128 if ((*iter).id() == id)
1129 return &(*iter);
1131 DLOG(WARNING) << "Could not find display:" << id;
1132 return NULL;
1135 void DisplayManager::AddMirrorDisplayInfoIfAny(
1136 std::vector<DisplayInfo>* display_info_list) {
1137 if (software_mirroring_enabled() && IsMirrored())
1138 display_info_list->push_back(GetDisplayInfo(mirrored_display_id_));
1141 void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo& new_info) {
1142 std::map<int64, DisplayInfo>::iterator info =
1143 display_info_.find(new_info.id());
1144 if (info != display_info_.end()) {
1145 info->second.Copy(new_info);
1146 } else {
1147 display_info_[new_info.id()] = new_info;
1148 display_info_[new_info.id()].set_native(false);
1150 display_info_[new_info.id()].UpdateDisplaySize();
1152 OnDisplayInfoUpdated(display_info_[new_info.id()]);
1155 void DisplayManager::OnDisplayInfoUpdated(const DisplayInfo& display_info) {
1156 #if defined(OS_CHROMEOS)
1157 ui::ColorCalibrationProfile color_profile = display_info.color_profile();
1158 if (color_profile != ui::COLOR_PROFILE_STANDARD) {
1159 Shell::GetInstance()->display_configurator()->SetColorCalibrationProfile(
1160 display_info.id(), color_profile);
1162 #endif
1165 gfx::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64 id) {
1166 DCHECK(display_info_.find(id) != display_info_.end());
1167 const DisplayInfo& display_info = display_info_[id];
1169 gfx::Display new_display(display_info.id());
1170 gfx::Rect bounds_in_native(display_info.size_in_pixel());
1171 float device_scale_factor = display_info.GetEffectiveDeviceScaleFactor();
1173 // Simply set the origin to (0,0). The primary display's origin is
1174 // always (0,0) and the secondary display's bounds will be updated
1175 // in |UpdateSecondaryDisplayBoundsForLayout| called in |UpdateDisplay|.
1176 new_display.SetScaleAndBounds(
1177 device_scale_factor, gfx::Rect(bounds_in_native.size()));
1178 new_display.set_rotation(display_info.rotation());
1179 new_display.set_touch_support(display_info.touch_support());
1180 return new_display;
1183 bool DisplayManager::UpdateSecondaryDisplayBoundsForLayout(
1184 DisplayList* displays,
1185 size_t* updated_index) const {
1186 if (displays->size() != 2U)
1187 return false;
1189 int64 id_at_zero = displays->at(0).id();
1190 DisplayIdPair pair =
1191 (id_at_zero == first_display_id_ ||
1192 id_at_zero == gfx::Display::InternalDisplayId()) ?
1193 std::make_pair(id_at_zero, displays->at(1).id()) :
1194 std::make_pair(displays->at(1).id(), id_at_zero);
1195 DisplayLayout layout =
1196 layout_store_->ComputeDisplayLayoutForDisplayIdPair(pair);
1198 // Ignore if a user has a old format (should be extremely rare)
1199 // and this will be replaced with DCHECK.
1200 if (layout.primary_id != gfx::Display::kInvalidDisplayID) {
1201 size_t primary_index, secondary_index;
1202 if (displays->at(0).id() == layout.primary_id) {
1203 primary_index = 0;
1204 secondary_index = 1;
1205 } else {
1206 primary_index = 1;
1207 secondary_index = 0;
1209 // This function may be called before the secondary display is
1210 // registered. The bounds is empty in that case and will
1211 // return true.
1212 gfx::Rect bounds =
1213 GetDisplayForId(displays->at(secondary_index).id()).bounds();
1214 UpdateDisplayBoundsForLayout(
1215 layout, displays->at(primary_index), &displays->at(secondary_index));
1216 *updated_index = secondary_index;
1217 return bounds != displays->at(secondary_index).bounds();
1219 return false;
1222 void DisplayManager::CreateMirrorWindowIfAny() {
1223 if (HasSoftwareMirroringDisplay() && delegate_) {
1224 DisplayInfo display_info = GetDisplayInfo(mirroring_display_.id());
1225 delegate_->CreateOrUpdateMirroringDisplay(display_info);
1229 bool DisplayManager::HasSoftwareMirroringDisplay() {
1230 return second_display_mode_ != DisplayManager::EXTENDED &&
1231 mirroring_display_.is_valid();
1234 // static
1235 void DisplayManager::UpdateDisplayBoundsForLayout(
1236 const DisplayLayout& layout,
1237 const gfx::Display& primary_display,
1238 gfx::Display* secondary_display) {
1239 DCHECK_EQ("0,0", primary_display.bounds().origin().ToString());
1241 const gfx::Rect& primary_bounds = primary_display.bounds();
1242 const gfx::Rect& secondary_bounds = secondary_display->bounds();
1243 gfx::Point new_secondary_origin = primary_bounds.origin();
1245 DisplayLayout::Position position = layout.position;
1247 // Ignore the offset in case the secondary display doesn't share edges with
1248 // the primary display.
1249 int offset = layout.offset;
1250 if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM) {
1251 offset = std::min(
1252 offset, primary_bounds.width() - kMinimumOverlapForInvalidOffset);
1253 offset = std::max(
1254 offset, -secondary_bounds.width() + kMinimumOverlapForInvalidOffset);
1255 } else {
1256 offset = std::min(
1257 offset, primary_bounds.height() - kMinimumOverlapForInvalidOffset);
1258 offset = std::max(
1259 offset, -secondary_bounds.height() + kMinimumOverlapForInvalidOffset);
1261 switch (position) {
1262 case DisplayLayout::TOP:
1263 new_secondary_origin.Offset(offset, -secondary_bounds.height());
1264 break;
1265 case DisplayLayout::RIGHT:
1266 new_secondary_origin.Offset(primary_bounds.width(), offset);
1267 break;
1268 case DisplayLayout::BOTTOM:
1269 new_secondary_origin.Offset(offset, primary_bounds.height());
1270 break;
1271 case DisplayLayout::LEFT:
1272 new_secondary_origin.Offset(-secondary_bounds.width(), offset);
1273 break;
1275 gfx::Insets insets = secondary_display->GetWorkAreaInsets();
1276 secondary_display->set_bounds(
1277 gfx::Rect(new_secondary_origin, secondary_bounds.size()));
1278 secondary_display->UpdateWorkAreaFromInsets(insets);
1281 } // namespace ash