Fix crash when a webview tries to load a plugin resource.
[chromium-blink-merge.git] / ash / display / display_manager.cc
blobb731ded75629bb985b260d201867de780c7edb0c
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/screen_ash.h"
17 #include "ash/screen_util.h"
18 #include "ash/shell.h"
19 #include "base/auto_reset.h"
20 #include "base/command_line.h"
21 #include "base/logging.h"
22 #include "base/metrics/histogram.h"
23 #include "base/strings/string_number_conversions.h"
24 #include "base/strings/string_split.h"
25 #include "base/strings/stringprintf.h"
26 #include "base/strings/utf_string_conversions.h"
27 #include "grit/ash_strings.h"
28 #include "ui/base/l10n/l10n_util.h"
29 #include "ui/gfx/display.h"
30 #include "ui/gfx/display_observer.h"
31 #include "ui/gfx/font_render_params.h"
32 #include "ui/gfx/geometry/rect.h"
33 #include "ui/gfx/geometry/size_conversions.h"
34 #include "ui/gfx/screen.h"
36 #if defined(USE_X11)
37 #include "ui/base/x/x11_util.h"
38 #endif
40 #if defined(OS_CHROMEOS)
41 #include "ash/display/display_configurator_animation.h"
42 #include "base/sys_info.h"
43 #endif
45 #if defined(OS_WIN)
46 #include "base/win/windows_version.h"
47 #endif
49 namespace ash {
50 typedef std::vector<gfx::Display> DisplayList;
51 typedef std::vector<DisplayInfo> DisplayInfoList;
53 namespace {
55 // We need to keep this in order for unittests to tell if
56 // the object in gfx::Screen::GetScreenByType is for shutdown.
57 gfx::Screen* screen_for_shutdown = NULL;
59 // The number of pixels to overlap between the primary and secondary displays,
60 // in case that the offset value is too large.
61 const int kMinimumOverlapForInvalidOffset = 100;
63 struct DisplaySortFunctor {
64 bool operator()(const gfx::Display& a, const gfx::Display& b) {
65 return a.id() < b.id();
69 struct DisplayInfoSortFunctor {
70 bool operator()(const DisplayInfo& a, const DisplayInfo& b) {
71 return a.id() < b.id();
75 struct DisplayModeMatcher {
76 DisplayModeMatcher(const DisplayMode& target_mode)
77 : target_mode(target_mode) {}
78 bool operator()(const DisplayMode& mode) {
79 return target_mode.IsEquivalent(mode);
81 DisplayMode target_mode;
84 gfx::Display& GetInvalidDisplay() {
85 static gfx::Display* invalid_display = new gfx::Display();
86 return *invalid_display;
89 void SetInternalDisplayModeList(DisplayInfo* info) {
90 DisplayMode native_mode;
91 native_mode.size = info->bounds_in_native().size();
92 native_mode.device_scale_factor = info->device_scale_factor();
93 native_mode.ui_scale = 1.0f;
94 info->SetDisplayModes(CreateInternalDisplayModeList(native_mode));
97 void MaybeInitInternalDisplay(DisplayInfo* info) {
98 int64 id = info->id();
99 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
100 if (command_line->HasSwitch(switches::kAshUseFirstDisplayAsInternal)) {
101 gfx::Display::SetInternalDisplayId(id);
102 SetInternalDisplayModeList(info);
106 } // namespace
108 using std::string;
109 using std::vector;
111 DisplayManager::DisplayManager()
112 : delegate_(NULL),
113 screen_ash_(new ScreenAsh),
114 screen_(screen_ash_.get()),
115 layout_store_(new DisplayLayoutStore),
116 first_display_id_(gfx::Display::kInvalidDisplayID),
117 num_connected_displays_(0),
118 force_bounds_changed_(false),
119 change_display_upon_host_resize_(false),
120 second_display_mode_(EXTENDED),
121 mirrored_display_id_(gfx::Display::kInvalidDisplayID),
122 registered_internal_display_rotation_lock_(false),
123 registered_internal_display_rotation_(gfx::Display::ROTATE_0),
124 weak_ptr_factory_(this) {
126 #if defined(OS_CHROMEOS)
127 // Enable only on the device so that DisplayManagerFontTest passes.
128 if (base::SysInfo::IsRunningOnChromeOS())
129 DisplayInfo::SetUse125DSFForUIScaling(true);
131 change_display_upon_host_resize_ = !base::SysInfo::IsRunningOnChromeOS();
132 #endif
133 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE,
134 screen_ash_.get());
135 gfx::Screen* current_native =
136 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE);
137 // If there is no native, or the native was for shutdown,
138 // use ash's screen.
139 if (!current_native ||
140 current_native == screen_for_shutdown) {
141 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE,
142 screen_ash_.get());
146 DisplayManager::~DisplayManager() {
147 #if defined(OS_CHROMEOS)
148 // Reset the font params.
149 gfx::SetFontRenderParamsDeviceScaleFactor(1.0f);
150 #endif
153 bool DisplayManager::InitFromCommandLine() {
154 DisplayInfoList info_list;
155 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
156 if (!command_line->HasSwitch(switches::kAshHostWindowBounds))
157 return false;
158 const string size_str =
159 command_line->GetSwitchValueASCII(switches::kAshHostWindowBounds);
160 vector<string> parts;
161 base::SplitString(size_str, ',', &parts);
162 for (vector<string>::const_iterator iter = parts.begin();
163 iter != parts.end(); ++iter) {
164 info_list.push_back(DisplayInfo::CreateFromSpec(*iter));
165 info_list.back().set_native(true);
167 MaybeInitInternalDisplay(&info_list[0]);
168 if (info_list.size() > 1 &&
169 command_line->HasSwitch(switches::kAshEnableSoftwareMirroring)) {
170 SetSecondDisplayMode(MIRRORING);
172 OnNativeDisplaysChanged(info_list);
173 return true;
176 void DisplayManager::InitDefaultDisplay() {
177 DisplayInfoList info_list;
178 info_list.push_back(DisplayInfo::CreateFromSpec(std::string()));
179 info_list.back().set_native(true);
180 MaybeInitInternalDisplay(&info_list[0]);
181 OnNativeDisplaysChanged(info_list);
184 void DisplayManager::RefreshFontParams() {
185 #if defined(OS_CHROMEOS)
186 // Use the largest device scale factor among currently active displays. Non
187 // internal display may have bigger scale factor in case the external display
188 // is an 4K display.
189 float largest_device_scale_factor = 1.0f;
190 for (const gfx::Display& display : displays_) {
191 const ash::DisplayInfo& info = display_info_[display.id()];
192 largest_device_scale_factor = std::max(
193 largest_device_scale_factor, info.GetEffectiveDeviceScaleFactor());
195 gfx::SetFontRenderParamsDeviceScaleFactor(largest_device_scale_factor);
196 #endif // OS_CHROMEOS
199 bool DisplayManager::IsActiveDisplay(const gfx::Display& display) const {
200 for (DisplayList::const_iterator iter = displays_.begin();
201 iter != displays_.end(); ++iter) {
202 if ((*iter).id() == display.id())
203 return true;
205 return false;
208 bool DisplayManager::HasInternalDisplay() const {
209 return gfx::Display::InternalDisplayId() != gfx::Display::kInvalidDisplayID;
212 bool DisplayManager::IsInternalDisplayId(int64 id) const {
213 return gfx::Display::InternalDisplayId() == id;
216 DisplayLayout DisplayManager::GetCurrentDisplayLayout() {
217 DCHECK_LE(2U, num_connected_displays());
218 // Invert if the primary was swapped.
219 if (num_connected_displays() == 2) {
220 DisplayIdPair pair = GetCurrentDisplayIdPair();
221 return layout_store_->ComputeDisplayLayoutForDisplayIdPair(pair);
222 } else if (num_connected_displays() > 2) {
223 // Return fixed horizontal layout for >= 3 displays.
224 DisplayLayout layout(DisplayLayout::RIGHT, 0);
225 return layout;
227 NOTREACHED() << "DisplayLayout is requested for single display";
228 // On release build, just fallback to default instead of blowing up.
229 DisplayLayout layout =
230 layout_store_->default_display_layout();
231 layout.primary_id = displays_[0].id();
232 return layout;
235 DisplayIdPair DisplayManager::GetCurrentDisplayIdPair() const {
236 if (IsMirrored()) {
237 if (software_mirroring_enabled()) {
238 CHECK_EQ(2u, num_connected_displays());
239 // This comment is to make it easy to distinguish the crash
240 // between two checks.
241 CHECK_EQ(1u, displays_.size());
243 return std::make_pair(displays_[0].id(), mirrored_display_id_);
244 } else {
245 CHECK_LE(2u, displays_.size());
246 int64 id_at_zero = displays_[0].id();
247 if (id_at_zero == gfx::Display::InternalDisplayId() ||
248 id_at_zero == first_display_id()) {
249 return std::make_pair(id_at_zero, displays_[1].id());
250 } else {
251 return std::make_pair(displays_[1].id(), id_at_zero);
256 void DisplayManager::SetLayoutForCurrentDisplays(
257 const DisplayLayout& layout_relative_to_primary) {
258 if (GetNumDisplays() != 2)
259 return;
260 const gfx::Display& primary = screen_->GetPrimaryDisplay();
261 const DisplayIdPair pair = GetCurrentDisplayIdPair();
262 // Invert if the primary was swapped.
263 DisplayLayout to_set = pair.first == primary.id() ?
264 layout_relative_to_primary : layout_relative_to_primary.Invert();
266 DisplayLayout current_layout =
267 layout_store_->GetRegisteredDisplayLayout(pair);
268 if (to_set.position != current_layout.position ||
269 to_set.offset != current_layout.offset) {
270 to_set.primary_id = primary.id();
271 layout_store_->RegisterLayoutForDisplayIdPair(
272 pair.first, pair.second, to_set);
273 if (delegate_)
274 delegate_->PreDisplayConfigurationChange(false);
275 // PreDisplayConfigurationChange(false);
276 // TODO(oshima): Call UpdateDisplays instead.
277 const DisplayLayout layout = GetCurrentDisplayLayout();
278 UpdateDisplayBoundsForLayout(
279 layout, primary,
280 FindDisplayForId(ScreenUtil::GetSecondaryDisplay().id()));
282 // Primary's bounds stay the same. Just notify bounds change
283 // on the secondary.
284 screen_ash_->NotifyMetricsChanged(
285 ScreenUtil::GetSecondaryDisplay(),
286 gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
287 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
288 if (delegate_)
289 delegate_->PostDisplayConfigurationChange();
293 const gfx::Display& DisplayManager::GetDisplayForId(int64 id) const {
294 gfx::Display* display =
295 const_cast<DisplayManager*>(this)->FindDisplayForId(id);
296 return display ? *display : GetInvalidDisplay();
299 const gfx::Display& DisplayManager::FindDisplayContainingPoint(
300 const gfx::Point& point_in_screen) const {
301 for (DisplayList::const_iterator iter = displays_.begin();
302 iter != displays_.end(); ++iter) {
303 const gfx::Display& display = *iter;
304 if (display.bounds().Contains(point_in_screen))
305 return display;
307 return GetInvalidDisplay();
310 bool DisplayManager::UpdateWorkAreaOfDisplay(int64 display_id,
311 const gfx::Insets& insets) {
312 gfx::Display* display = FindDisplayForId(display_id);
313 DCHECK(display);
314 gfx::Rect old_work_area = display->work_area();
315 display->UpdateWorkAreaFromInsets(insets);
316 return old_work_area != display->work_area();
319 void DisplayManager::SetOverscanInsets(int64 display_id,
320 const gfx::Insets& insets_in_dip) {
321 bool update = false;
322 DisplayInfoList display_info_list;
323 for (DisplayList::const_iterator iter = displays_.begin();
324 iter != displays_.end(); ++iter) {
325 DisplayInfo info = GetDisplayInfo(iter->id());
326 if (info.id() == display_id) {
327 if (insets_in_dip.empty()) {
328 info.set_clear_overscan_insets(true);
329 } else {
330 info.set_clear_overscan_insets(false);
331 info.SetOverscanInsets(insets_in_dip);
333 update = true;
335 display_info_list.push_back(info);
337 if (update) {
338 AddMirrorDisplayInfoIfAny(&display_info_list);
339 UpdateDisplays(display_info_list);
340 } else {
341 display_info_[display_id].SetOverscanInsets(insets_in_dip);
345 void DisplayManager::SetDisplayRotation(int64 display_id,
346 gfx::Display::Rotation rotation) {
347 DisplayInfoList display_info_list;
348 for (DisplayList::const_iterator iter = displays_.begin();
349 iter != displays_.end(); ++iter) {
350 DisplayInfo info = GetDisplayInfo(iter->id());
351 if (info.id() == display_id) {
352 if (info.rotation() == rotation)
353 return;
354 info.set_rotation(rotation);
356 display_info_list.push_back(info);
358 AddMirrorDisplayInfoIfAny(&display_info_list);
359 UpdateDisplays(display_info_list);
362 bool DisplayManager::SetDisplayUIScale(int64 display_id,
363 float ui_scale) {
364 if (!IsDisplayUIScalingEnabled() ||
365 gfx::Display::InternalDisplayId() != display_id) {
366 return false;
368 bool found = false;
369 // TODO(mukai): merge this implementation into SetDisplayMode().
370 DisplayInfoList display_info_list;
371 for (DisplayList::const_iterator iter = displays_.begin();
372 iter != displays_.end(); ++iter) {
373 DisplayInfo info = GetDisplayInfo(iter->id());
374 if (info.id() == display_id) {
375 found = true;
376 if (info.configured_ui_scale() == ui_scale)
377 return true;
378 if (!HasDisplayModeForUIScale(info, ui_scale))
379 return false;
380 info.set_configured_ui_scale(ui_scale);
382 display_info_list.push_back(info);
384 if (found) {
385 AddMirrorDisplayInfoIfAny(&display_info_list);
386 UpdateDisplays(display_info_list);
387 return true;
389 return false;
392 void DisplayManager::SetDisplayResolution(int64 display_id,
393 const gfx::Size& resolution) {
394 DCHECK_NE(gfx::Display::InternalDisplayId(), display_id);
395 if (gfx::Display::InternalDisplayId() == display_id)
396 return;
397 const DisplayInfo& display_info = GetDisplayInfo(display_id);
398 const std::vector<DisplayMode>& modes = display_info.display_modes();
399 DCHECK_NE(0u, modes.size());
400 DisplayMode target_mode;
401 target_mode.size = resolution;
402 std::vector<DisplayMode>::const_iterator iter =
403 std::find_if(modes.begin(), modes.end(), DisplayModeMatcher(target_mode));
404 if (iter == modes.end()) {
405 LOG(WARNING) << "Unsupported resolution was requested:"
406 << resolution.ToString();
407 return;
409 display_modes_[display_id] = *iter;
410 #if defined(OS_CHROMEOS)
411 if (base::SysInfo::IsRunningOnChromeOS())
412 Shell::GetInstance()->display_configurator()->OnConfigurationChanged();
413 #endif
416 bool DisplayManager::SetDisplayMode(int64 display_id,
417 const DisplayMode& display_mode) {
418 if (IsInternalDisplayId(display_id)) {
419 SetDisplayUIScale(display_id, display_mode.ui_scale);
420 return false;
423 DisplayInfoList display_info_list;
424 bool display_property_changed = false;
425 bool resolution_changed = false;
426 for (DisplayList::const_iterator iter = displays_.begin();
427 iter != displays_.end(); ++iter) {
428 DisplayInfo info = GetDisplayInfo(iter->id());
429 if (info.id() == display_id) {
430 const std::vector<DisplayMode>& modes = info.display_modes();
431 std::vector<DisplayMode>::const_iterator iter =
432 std::find_if(modes.begin(),
433 modes.end(),
434 DisplayModeMatcher(display_mode));
435 if (iter == modes.end()) {
436 LOG(WARNING) << "Unsupported resolution was requested:"
437 << display_mode.size.ToString();
438 return false;
440 display_modes_[display_id] = *iter;
441 if (info.bounds_in_native().size() != display_mode.size)
442 resolution_changed = true;
443 if (info.device_scale_factor() != display_mode.device_scale_factor) {
444 info.set_device_scale_factor(display_mode.device_scale_factor);
445 display_property_changed = true;
448 display_info_list.push_back(info);
450 if (display_property_changed) {
451 AddMirrorDisplayInfoIfAny(&display_info_list);
452 UpdateDisplays(display_info_list);
454 #if defined(OS_CHROMEOS)
455 if (resolution_changed && base::SysInfo::IsRunningOnChromeOS())
456 Shell::GetInstance()->display_configurator()->OnConfigurationChanged();
457 #endif
458 return resolution_changed;
461 void DisplayManager::RegisterDisplayProperty(
462 int64 display_id,
463 gfx::Display::Rotation rotation,
464 float ui_scale,
465 const gfx::Insets* overscan_insets,
466 const gfx::Size& resolution_in_pixels,
467 float device_scale_factor,
468 ui::ColorCalibrationProfile color_profile) {
469 if (display_info_.find(display_id) == display_info_.end())
470 display_info_[display_id] = DisplayInfo(display_id, std::string(), false);
472 display_info_[display_id].set_rotation(rotation);
473 display_info_[display_id].SetColorProfile(color_profile);
474 // Just in case the preference file was corrupted.
475 // TODO(mukai): register |display_modes_| here as well, so the lookup for the
476 // default mode in GetActiveModeForDisplayId() gets much simpler.
477 if (0.5f <= ui_scale && ui_scale <= 2.0f)
478 display_info_[display_id].set_configured_ui_scale(ui_scale);
479 if (overscan_insets)
480 display_info_[display_id].SetOverscanInsets(*overscan_insets);
481 if (!resolution_in_pixels.IsEmpty()) {
482 DCHECK(!IsInternalDisplayId(display_id));
483 // Default refresh rate, until OnNativeDisplaysChanged() updates us with the
484 // actual display info, is 60 Hz.
485 DisplayMode mode(resolution_in_pixels, 60.0f, false, false);
486 mode.device_scale_factor = device_scale_factor;
487 display_modes_[display_id] = mode;
491 DisplayMode DisplayManager::GetActiveModeForDisplayId(int64 display_id) const {
492 DisplayMode selected_mode;
493 if (GetSelectedModeForDisplayId(display_id, &selected_mode))
494 return selected_mode;
496 // If 'selected' mode is empty, it should return the default mode. This means
497 // the native mode for the external display. Unfortunately this is not true
498 // for the internal display because restoring UI-scale doesn't register the
499 // restored mode to |display_mode_|, so it needs to look up the mode whose
500 // UI-scale value matches. See the TODO in RegisterDisplayProperty().
501 const DisplayInfo& info = GetDisplayInfo(display_id);
502 const std::vector<DisplayMode>& display_modes = info.display_modes();
504 if (IsInternalDisplayId(display_id)) {
505 for (size_t i = 0; i < display_modes.size(); ++i) {
506 if (info.configured_ui_scale() == display_modes[i].ui_scale)
507 return display_modes[i];
509 } else {
510 for (size_t i = 0; i < display_modes.size(); ++i) {
511 if (display_modes[i].native)
512 return display_modes[i];
515 return selected_mode;
518 void DisplayManager::RegisterDisplayRotationProperties(bool rotation_lock,
519 gfx::Display::Rotation rotation) {
520 if (delegate_)
521 delegate_->PreDisplayConfigurationChange(false);
522 registered_internal_display_rotation_lock_ = rotation_lock;
523 registered_internal_display_rotation_ = rotation;
524 if (delegate_)
525 delegate_->PostDisplayConfigurationChange();
528 bool DisplayManager::GetSelectedModeForDisplayId(int64 id,
529 DisplayMode* mode_out) const {
530 std::map<int64, DisplayMode>::const_iterator iter = display_modes_.find(id);
531 if (iter == display_modes_.end())
532 return false;
533 *mode_out = iter->second;
534 return true;
537 bool DisplayManager::IsDisplayUIScalingEnabled() const {
538 return GetDisplayIdForUIScaling() != gfx::Display::kInvalidDisplayID;
541 gfx::Insets DisplayManager::GetOverscanInsets(int64 display_id) const {
542 std::map<int64, DisplayInfo>::const_iterator it =
543 display_info_.find(display_id);
544 return (it != display_info_.end()) ?
545 it->second.overscan_insets_in_dip() : gfx::Insets();
548 void DisplayManager::SetColorCalibrationProfile(
549 int64 display_id,
550 ui::ColorCalibrationProfile profile) {
551 #if defined(OS_CHROMEOS)
552 if (!display_info_[display_id].IsColorProfileAvailable(profile))
553 return;
555 if (delegate_)
556 delegate_->PreDisplayConfigurationChange(false);
557 // Just sets color profile if it's not running on ChromeOS (like tests).
558 if (!base::SysInfo::IsRunningOnChromeOS() ||
559 Shell::GetInstance()->display_configurator()->SetColorCalibrationProfile(
560 display_id, profile)) {
561 display_info_[display_id].SetColorProfile(profile);
562 UMA_HISTOGRAM_ENUMERATION(
563 "ChromeOS.Display.ColorProfile", profile, ui::NUM_COLOR_PROFILES);
565 if (delegate_)
566 delegate_->PostDisplayConfigurationChange();
567 #endif
570 void DisplayManager::OnNativeDisplaysChanged(
571 const std::vector<DisplayInfo>& updated_displays) {
572 if (updated_displays.empty()) {
573 VLOG(1) << "OnNativeDisplaysChanged(0): # of current displays="
574 << displays_.size();
575 // If the device is booted without display, or chrome is started
576 // without --ash-host-window-bounds on linux desktop, use the
577 // default display.
578 if (displays_.empty()) {
579 std::vector<DisplayInfo> init_displays;
580 init_displays.push_back(DisplayInfo::CreateFromSpec(std::string()));
581 MaybeInitInternalDisplay(&init_displays[0]);
582 OnNativeDisplaysChanged(init_displays);
583 } else {
584 // Otherwise don't update the displays when all displays are disconnected.
585 // This happens when:
586 // - the device is idle and powerd requested to turn off all displays.
587 // - the device is suspended. (kernel turns off all displays)
588 // - the internal display's brightness is set to 0 and no external
589 // display is connected.
590 // - the internal display's brightness is 0 and external display is
591 // disconnected.
592 // The display will be updated when one of displays is turned on, and the
593 // display list will be updated correctly.
595 return;
597 first_display_id_ = updated_displays[0].id();
598 std::set<gfx::Point> origins;
600 if (updated_displays.size() == 1) {
601 VLOG(1) << "OnNativeDisplaysChanged(1):" << updated_displays[0].ToString();
602 } else {
603 VLOG(1) << "OnNativeDisplaysChanged(" << updated_displays.size()
604 << ") [0]=" << updated_displays[0].ToString()
605 << ", [1]=" << updated_displays[1].ToString();
608 bool internal_display_connected = false;
609 num_connected_displays_ = updated_displays.size();
610 mirrored_display_id_ = gfx::Display::kInvalidDisplayID;
611 mirroring_display_ = gfx::Display();
612 DisplayInfoList new_display_info_list;
613 for (DisplayInfoList::const_iterator iter = updated_displays.begin();
614 iter != updated_displays.end();
615 ++iter) {
616 if (!internal_display_connected)
617 internal_display_connected = IsInternalDisplayId(iter->id());
618 // Mirrored monitors have the same origins.
619 gfx::Point origin = iter->bounds_in_native().origin();
620 if (origins.find(origin) != origins.end()) {
621 InsertAndUpdateDisplayInfo(*iter);
622 mirrored_display_id_ = iter->id();
623 } else {
624 origins.insert(origin);
625 new_display_info_list.push_back(*iter);
628 DisplayMode new_mode;
629 new_mode.size = iter->bounds_in_native().size();
630 new_mode.device_scale_factor = iter->device_scale_factor();
631 new_mode.ui_scale = iter->configured_ui_scale();
632 const std::vector<DisplayMode>& display_modes = iter->display_modes();
633 // This is empty the displays are initialized from InitFromCommandLine.
634 if (!display_modes.size())
635 continue;
636 std::vector<DisplayMode>::const_iterator display_modes_iter =
637 std::find_if(display_modes.begin(),
638 display_modes.end(),
639 DisplayModeMatcher(new_mode));
640 // Update the actual resolution selected as the resolution request may fail.
641 if (display_modes_iter == display_modes.end())
642 display_modes_.erase(iter->id());
643 else if (display_modes_.find(iter->id()) != display_modes_.end())
644 display_modes_[iter->id()] = *display_modes_iter;
646 if (HasInternalDisplay() &&
647 !internal_display_connected &&
648 display_info_.find(gfx::Display::InternalDisplayId()) ==
649 display_info_.end()) {
650 DisplayInfo internal_display_info(
651 gfx::Display::InternalDisplayId(),
652 l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME),
653 false /*Internal display must not have overscan */);
654 internal_display_info.SetBounds(gfx::Rect(0, 0, 800, 600));
655 display_info_[gfx::Display::InternalDisplayId()] = internal_display_info;
657 UpdateDisplays(new_display_info_list);
660 void DisplayManager::UpdateDisplays() {
661 DisplayInfoList display_info_list;
662 for (DisplayList::const_iterator iter = displays_.begin();
663 iter != displays_.end(); ++iter) {
664 display_info_list.push_back(GetDisplayInfo(iter->id()));
666 AddMirrorDisplayInfoIfAny(&display_info_list);
667 UpdateDisplays(display_info_list);
670 void DisplayManager::UpdateDisplays(
671 const std::vector<DisplayInfo>& updated_display_info_list) {
672 #if defined(OS_WIN)
673 DCHECK_EQ(1u, updated_display_info_list.size()) <<
674 ": Multiple display test does not work on Windows bots. Please "
675 "skip (don't disable) the test using SupportsMultipleDisplays()";
676 #endif
678 DisplayInfoList new_display_info_list = updated_display_info_list;
679 std::sort(displays_.begin(), displays_.end(), DisplaySortFunctor());
680 std::sort(new_display_info_list.begin(),
681 new_display_info_list.end(),
682 DisplayInfoSortFunctor());
683 DisplayList removed_displays;
684 std::map<size_t, uint32_t> display_changes;
685 std::vector<size_t> added_display_indices;
687 DisplayList::iterator curr_iter = displays_.begin();
688 DisplayInfoList::const_iterator new_info_iter = new_display_info_list.begin();
690 DisplayList new_displays;
692 // Use the internal display or 1st as the mirror source, then scale
693 // the root window so that it matches the external display's
694 // resolution. This is necessary in order for scaling to work while
695 // mirrored.
696 int64 mirroing_display_id = gfx::Display::kInvalidDisplayID;
698 if (second_display_mode_ != EXTENDED && new_display_info_list.size() == 2) {
699 bool zero_is_source =
700 first_display_id_ == new_display_info_list[0].id() ||
701 gfx::Display::InternalDisplayId() == new_display_info_list[0].id();
702 DCHECK_EQ(MIRRORING, second_display_mode_);
703 mirrored_display_id_ = new_display_info_list[zero_is_source ? 1 : 0].id();
704 mirroing_display_id = mirrored_display_id_;
707 while (curr_iter != displays_.end() ||
708 new_info_iter != new_display_info_list.end()) {
709 if (new_info_iter != new_display_info_list.end() &&
710 mirroing_display_id == new_info_iter->id()) {
711 DisplayInfo info = *new_info_iter;
712 info.SetOverscanInsets(gfx::Insets());
713 InsertAndUpdateDisplayInfo(info);
714 mirroring_display_ =
715 CreateDisplayFromDisplayInfoById(mirroing_display_id);
716 ++new_info_iter;
717 // Remove existing external display if it is going to be used as
718 // mirroring display.
719 if (curr_iter != displays_.end() &&
720 curr_iter->id() == mirroing_display_id) {
721 removed_displays.push_back(*curr_iter);
722 ++curr_iter;
724 continue;
727 if (curr_iter == displays_.end()) {
728 // more displays in new list.
729 added_display_indices.push_back(new_displays.size());
730 InsertAndUpdateDisplayInfo(*new_info_iter);
731 new_displays.push_back(
732 CreateDisplayFromDisplayInfoById(new_info_iter->id()));
733 ++new_info_iter;
734 } else if (new_info_iter == new_display_info_list.end()) {
735 // more displays in current list.
736 removed_displays.push_back(*curr_iter);
737 ++curr_iter;
738 } else if (curr_iter->id() == new_info_iter->id()) {
739 const gfx::Display& current_display = *curr_iter;
740 // Copy the info because |CreateDisplayFromInfo| updates the instance.
741 const DisplayInfo current_display_info =
742 GetDisplayInfo(current_display.id());
743 InsertAndUpdateDisplayInfo(*new_info_iter);
744 gfx::Display new_display =
745 CreateDisplayFromDisplayInfoById(new_info_iter->id());
746 const DisplayInfo& new_display_info = GetDisplayInfo(new_display.id());
748 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_NONE;
750 // At that point the new Display objects we have are not entirely updated,
751 // they are missing the translation related to the Display disposition in
752 // the layout.
753 // Using display.bounds() and display.work_area() would fail most of the
754 // time.
755 if (force_bounds_changed_ ||
756 (current_display_info.bounds_in_native() !=
757 new_display_info.bounds_in_native()) ||
758 (current_display_info.GetOverscanInsetsInPixel() !=
759 new_display_info.GetOverscanInsetsInPixel()) ||
760 current_display.size() != new_display.size()) {
761 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
762 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
765 if (current_display.device_scale_factor() !=
766 new_display.device_scale_factor()) {
767 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
770 if (current_display.rotation() != new_display.rotation())
771 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_ROTATION;
773 if (metrics != gfx::DisplayObserver::DISPLAY_METRIC_NONE) {
774 display_changes.insert(
775 std::pair<size_t, uint32_t>(new_displays.size(), metrics));
778 new_display.UpdateWorkAreaFromInsets(current_display.GetWorkAreaInsets());
779 new_displays.push_back(new_display);
780 ++curr_iter;
781 ++new_info_iter;
782 } else if (curr_iter->id() < new_info_iter->id()) {
783 // more displays in current list between ids, which means it is deleted.
784 removed_displays.push_back(*curr_iter);
785 ++curr_iter;
786 } else {
787 // more displays in new list between ids, which means it is added.
788 added_display_indices.push_back(new_displays.size());
789 InsertAndUpdateDisplayInfo(*new_info_iter);
790 new_displays.push_back(
791 CreateDisplayFromDisplayInfoById(new_info_iter->id()));
792 ++new_info_iter;
795 gfx::Display old_primary;
796 if (delegate_)
797 old_primary = screen_ash_->GetPrimaryDisplay();
799 // Clear focus if the display has been removed, but don't clear focus if
800 // the destkop has been moved from one display to another
801 // (mirror -> docked, docked -> single internal).
802 bool clear_focus =
803 !removed_displays.empty() &&
804 !(removed_displays.size() == 1 && added_display_indices.size() == 1);
805 if (delegate_)
806 delegate_->PreDisplayConfigurationChange(clear_focus);
808 // Do not update |displays_| if there's nothing to be updated. Without this,
809 // it will not update the display layout, which causes the bug
810 // http://crbug.com/155948.
811 if (display_changes.empty() && added_display_indices.empty() &&
812 removed_displays.empty()) {
813 // When changing from software mirroring mode to sinlge display
814 // mode, it is possible there is no need to update |displays_| and
815 // we early out here. But we still need to update the mirroring
816 // window and call the PostDisplayConfigurationChange() cause
817 // there are some clients need to act on this,
818 // e.g. TouchTransformerController needs to adjust the
819 // TouchTransformer when/ switching from dual displays to single
820 // display.
821 if (delegate_) {
822 if (HasSoftwareMirroringDisplay())
823 CreateMirrorWindowAsyncIfAny();
824 else
825 delegate_->CloseMirroringDisplay();
826 delegate_->PostDisplayConfigurationChange();
828 return;
831 std::vector<size_t> updated_indices;
832 if (UpdateNonPrimaryDisplayBoundsForLayout(&new_displays, &updated_indices)) {
833 for (std::vector<size_t>::iterator it = updated_indices.begin();
834 it != updated_indices.end(); ++it) {
835 size_t updated_index = *it;
836 if (std::find(added_display_indices.begin(),
837 added_display_indices.end(),
838 updated_index) == added_display_indices.end()) {
839 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
840 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
841 if (display_changes.find(updated_index) != display_changes.end())
842 metrics |= display_changes[updated_index];
844 display_changes[updated_index] = metrics;
849 displays_ = new_displays;
851 RefreshFontParams();
852 base::AutoReset<bool> resetter(&change_display_upon_host_resize_, false);
854 // Temporarily add displays to be removed because display object
855 // being removed are accessed during shutting down the root.
856 displays_.insert(displays_.end(), removed_displays.begin(),
857 removed_displays.end());
859 for (DisplayList::const_reverse_iterator iter = removed_displays.rbegin();
860 iter != removed_displays.rend(); ++iter) {
861 screen_ash_->NotifyDisplayRemoved(displays_.back());
862 displays_.pop_back();
865 bool has_mirroring_display = HasSoftwareMirroringDisplay();
866 // Close the mirroring window here to avoid creating two compositor on
867 // one display.
868 if (!has_mirroring_display && delegate_)
869 delegate_->CloseMirroringDisplay();
871 for (std::vector<size_t>::iterator iter = added_display_indices.begin();
872 iter != added_display_indices.end(); ++iter) {
873 screen_ash_->NotifyDisplayAdded(displays_[*iter]);
876 bool notify_primary_change =
877 delegate_ ? old_primary.id() != screen_->GetPrimaryDisplay().id() : false;
879 for (std::map<size_t, uint32_t>::iterator iter = display_changes.begin();
880 iter != display_changes.end();
881 ++iter) {
882 uint32_t metrics = iter->second;
883 const gfx::Display& updated_display = displays_[iter->first];
885 if (notify_primary_change &&
886 updated_display.id() == screen_->GetPrimaryDisplay().id()) {
887 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_PRIMARY;
888 notify_primary_change = false;
890 screen_ash_->NotifyMetricsChanged(updated_display, metrics);
893 if (notify_primary_change) {
894 // This happens when a primary display has moved to anther display without
895 // bounds change.
896 const gfx::Display& primary = screen_->GetPrimaryDisplay();
897 if (primary.id() != old_primary.id()) {
898 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_PRIMARY;
899 if (primary.size() != old_primary.size()) {
900 metrics |= (gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
901 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
903 if (primary.device_scale_factor() != old_primary.device_scale_factor())
904 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
906 screen_ash_->NotifyMetricsChanged(primary, metrics);
910 if (delegate_)
911 delegate_->PostDisplayConfigurationChange();
913 #if defined(USE_X11) && defined(OS_CHROMEOS)
914 if (!display_changes.empty() && base::SysInfo::IsRunningOnChromeOS())
915 ui::ClearX11DefaultRootWindow();
916 #endif
918 // Create the mirroring window asynchronously after all displays
919 // are added so that it can mirror the display newly added. This can
920 // happen when switching from dock mode to software mirror mode.
921 CreateMirrorWindowAsyncIfAny();
924 const gfx::Display& DisplayManager::GetDisplayAt(size_t index) const {
925 DCHECK_LT(index, displays_.size());
926 return displays_[index];
929 const gfx::Display& DisplayManager::GetPrimaryDisplayCandidate() const {
930 if (GetNumDisplays() != 2)
931 return displays_[0];
932 DisplayLayout layout = layout_store_->GetRegisteredDisplayLayout(
933 GetCurrentDisplayIdPair());
934 return GetDisplayForId(layout.primary_id);
937 size_t DisplayManager::GetNumDisplays() const {
938 return displays_.size();
941 bool DisplayManager::IsMirrored() const {
942 return mirrored_display_id_ != gfx::Display::kInvalidDisplayID;
945 const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const {
946 DCHECK_NE(gfx::Display::kInvalidDisplayID, display_id);
948 std::map<int64, DisplayInfo>::const_iterator iter =
949 display_info_.find(display_id);
950 CHECK(iter != display_info_.end()) << display_id;
951 return iter->second;
954 std::string DisplayManager::GetDisplayNameForId(int64 id) {
955 if (id == gfx::Display::kInvalidDisplayID)
956 return l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME);
958 std::map<int64, DisplayInfo>::const_iterator iter = display_info_.find(id);
959 if (iter != display_info_.end() && !iter->second.name().empty())
960 return iter->second.name();
962 return base::StringPrintf("Display %d", static_cast<int>(id));
965 int64 DisplayManager::GetDisplayIdForUIScaling() const {
966 // UI Scaling is effective only on internal display.
967 int64 display_id = gfx::Display::InternalDisplayId();
968 #if defined(OS_WIN)
969 display_id = first_display_id();
970 #endif
971 return display_id;
974 void DisplayManager::SetMirrorMode(bool mirrored) {
975 if (num_connected_displays() <= 1)
976 return;
978 #if defined(OS_CHROMEOS)
979 if (base::SysInfo::IsRunningOnChromeOS()) {
980 ui::MultipleDisplayState new_state =
981 mirrored ? ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR :
982 ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
983 Shell::GetInstance()->display_configurator()->SetDisplayMode(new_state);
984 return;
986 #endif
987 // This is fallback path to emulate mirroroing on desktop.
988 SetSecondDisplayMode(mirrored ? MIRRORING : EXTENDED);
989 DisplayInfoList display_info_list;
990 int count = 0;
991 for (std::map<int64, DisplayInfo>::const_iterator iter =
992 display_info_.begin();
993 count < 2; ++iter, ++count) {
994 display_info_list.push_back(GetDisplayInfo(iter->second.id()));
996 UpdateDisplays(display_info_list);
997 #if defined(OS_CHROMEOS)
998 if (Shell::GetInstance()->display_configurator_animation()) {
999 Shell::GetInstance()->display_configurator_animation()->
1000 StartFadeInAnimation();
1002 #endif
1005 void DisplayManager::AddRemoveDisplay() {
1006 DCHECK(!displays_.empty());
1007 std::vector<DisplayInfo> new_display_info_list;
1008 const DisplayInfo& first_display = GetDisplayInfo(displays_[0].id());
1009 new_display_info_list.push_back(first_display);
1010 // Add if there is only one display connected.
1011 if (num_connected_displays() == 1) {
1012 // Layout the 2nd display below the primary as with the real device.
1013 gfx::Rect host_bounds = first_display.bounds_in_native();
1014 new_display_info_list.push_back(DisplayInfo::CreateFromSpec(
1015 base::StringPrintf(
1016 "%d+%d-500x400", host_bounds.x(), host_bounds.bottom())));
1018 num_connected_displays_ = new_display_info_list.size();
1019 mirrored_display_id_ = gfx::Display::kInvalidDisplayID;
1020 mirroring_display_ = gfx::Display();
1021 UpdateDisplays(new_display_info_list);
1024 void DisplayManager::ToggleDisplayScaleFactor() {
1025 DCHECK(!displays_.empty());
1026 std::vector<DisplayInfo> new_display_info_list;
1027 for (DisplayList::const_iterator iter = displays_.begin();
1028 iter != displays_.end(); ++iter) {
1029 DisplayInfo display_info = GetDisplayInfo(iter->id());
1030 display_info.set_device_scale_factor(
1031 display_info.device_scale_factor() == 1.0f ? 2.0f : 1.0f);
1032 new_display_info_list.push_back(display_info);
1034 AddMirrorDisplayInfoIfAny(&new_display_info_list);
1035 UpdateDisplays(new_display_info_list);
1038 #if defined(OS_CHROMEOS)
1039 void DisplayManager::SetSoftwareMirroring(bool enabled) {
1040 SetSecondDisplayMode(enabled ? MIRRORING : EXTENDED);
1043 bool DisplayManager::SoftwareMirroringEnabled() const {
1044 return software_mirroring_enabled();
1046 #endif
1048 void DisplayManager::SetSecondDisplayMode(SecondDisplayMode mode) {
1049 second_display_mode_ = mode;
1050 mirrored_display_id_ = gfx::Display::kInvalidDisplayID;
1051 mirroring_display_ = gfx::Display();
1054 bool DisplayManager::UpdateDisplayBounds(int64 display_id,
1055 const gfx::Rect& new_bounds) {
1056 if (change_display_upon_host_resize_) {
1057 display_info_[display_id].SetBounds(new_bounds);
1058 // Don't notify observers if the mirrored window has changed.
1059 if (software_mirroring_enabled() && mirrored_display_id_ == display_id)
1060 return false;
1061 gfx::Display* display = FindDisplayForId(display_id);
1062 display->SetSize(display_info_[display_id].size_in_pixel());
1063 screen_ash_->NotifyMetricsChanged(
1064 *display, gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS);
1065 return true;
1067 return false;
1070 void DisplayManager::CreateMirrorWindowAsyncIfAny() {
1071 // Do not post a task if the software mirroring doesn't exist, or
1072 // during initialization when compositor's init task isn't posted yet.
1073 // ash::Shell::Init() will call this after the compositor is initialized.
1074 if (!HasSoftwareMirroringDisplay() || !delegate_)
1075 return;
1076 base::MessageLoopForUI::current()->PostTask(
1077 FROM_HERE,
1078 base::Bind(&DisplayManager::CreateMirrorWindowIfAny,
1079 weak_ptr_factory_.GetWeakPtr()));
1082 void DisplayManager::CreateScreenForShutdown() const {
1083 bool native_is_ash =
1084 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE) ==
1085 screen_ash_.get();
1086 delete screen_for_shutdown;
1087 screen_for_shutdown = screen_ash_->CloneForShutdown();
1088 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE,
1089 screen_for_shutdown);
1090 if (native_is_ash) {
1091 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE,
1092 screen_for_shutdown);
1096 void DisplayManager::UpdateInternalDisplayModeListForTest() {
1097 if (display_info_.count(gfx::Display::InternalDisplayId()) == 0)
1098 return;
1099 DisplayInfo* info = &display_info_[gfx::Display::InternalDisplayId()];
1100 SetInternalDisplayModeList(info);
1103 gfx::Display* DisplayManager::FindDisplayForId(int64 id) {
1104 for (DisplayList::iterator iter = displays_.begin();
1105 iter != displays_.end(); ++iter) {
1106 if ((*iter).id() == id)
1107 return &(*iter);
1109 DLOG(WARNING) << "Could not find display:" << id;
1110 return NULL;
1113 void DisplayManager::AddMirrorDisplayInfoIfAny(
1114 std::vector<DisplayInfo>* display_info_list) {
1115 if (software_mirroring_enabled() && IsMirrored())
1116 display_info_list->push_back(GetDisplayInfo(mirrored_display_id_));
1119 void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo& new_info) {
1120 std::map<int64, DisplayInfo>::iterator info =
1121 display_info_.find(new_info.id());
1122 if (info != display_info_.end()) {
1123 info->second.Copy(new_info);
1124 } else {
1125 display_info_[new_info.id()] = new_info;
1126 display_info_[new_info.id()].set_native(false);
1128 display_info_[new_info.id()].UpdateDisplaySize();
1129 OnDisplayInfoUpdated(display_info_[new_info.id()]);
1132 void DisplayManager::OnDisplayInfoUpdated(const DisplayInfo& display_info) {
1133 #if defined(OS_CHROMEOS)
1134 ui::ColorCalibrationProfile color_profile = display_info.color_profile();
1135 if (color_profile != ui::COLOR_PROFILE_STANDARD) {
1136 Shell::GetInstance()->display_configurator()->SetColorCalibrationProfile(
1137 display_info.id(), color_profile);
1139 #endif
1142 gfx::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64 id) {
1143 DCHECK(display_info_.find(id) != display_info_.end());
1144 const DisplayInfo& display_info = display_info_[id];
1146 gfx::Display new_display(display_info.id());
1147 gfx::Rect bounds_in_native(display_info.size_in_pixel());
1148 float device_scale_factor = display_info.GetEffectiveDeviceScaleFactor();
1150 // Simply set the origin to (0,0). The primary display's origin is
1151 // always (0,0) and the bounds of non-primary display(s) will be updated
1152 // in |UpdateNonPrimaryDisplayBoundsForLayout| called in |UpdateDisplay|.
1153 new_display.SetScaleAndBounds(
1154 device_scale_factor, gfx::Rect(bounds_in_native.size()));
1155 new_display.set_rotation(display_info.rotation());
1156 new_display.set_touch_support(display_info.touch_support());
1157 return new_display;
1160 bool DisplayManager::UpdateNonPrimaryDisplayBoundsForLayout(
1161 DisplayList* displays,
1162 std::vector<size_t>* updated_indices) const {
1164 if (displays->size() < 2U)
1165 return false;
1167 if (displays->size() > 2U) {
1168 // For more than 2 displays, always use horizontal layout.
1169 int x_offset = displays->at(0).bounds().width();
1170 for (size_t i = 1; i < displays->size(); ++i) {
1171 gfx::Display& display = displays->at(i);
1172 const gfx::Rect& bounds = display.bounds();
1173 gfx::Point origin = gfx::Point(x_offset, 0);
1174 gfx::Insets insets = display.GetWorkAreaInsets();
1175 display.set_bounds(gfx::Rect(origin, bounds.size()));
1176 display.UpdateWorkAreaFromInsets(insets);
1177 x_offset += bounds.width();
1178 updated_indices->push_back(i);
1180 return true;
1183 int64 id_at_zero = displays->at(0).id();
1184 DisplayIdPair pair =
1185 (id_at_zero == first_display_id_ ||
1186 id_at_zero == gfx::Display::InternalDisplayId()) ?
1187 std::make_pair(id_at_zero, displays->at(1).id()) :
1188 std::make_pair(displays->at(1).id(), id_at_zero);
1189 DisplayLayout layout =
1190 layout_store_->ComputeDisplayLayoutForDisplayIdPair(pair);
1192 // Ignore if a user has a old format (should be extremely rare)
1193 // and this will be replaced with DCHECK.
1194 if (layout.primary_id != gfx::Display::kInvalidDisplayID) {
1195 size_t primary_index, secondary_index;
1196 if (displays->at(0).id() == layout.primary_id) {
1197 primary_index = 0;
1198 secondary_index = 1;
1199 } else {
1200 primary_index = 1;
1201 secondary_index = 0;
1203 // This function may be called before the secondary display is
1204 // registered. The bounds is empty in that case and will
1205 // return true.
1206 gfx::Rect bounds =
1207 GetDisplayForId(displays->at(secondary_index).id()).bounds();
1208 UpdateDisplayBoundsForLayout(
1209 layout, displays->at(primary_index), &displays->at(secondary_index));
1210 updated_indices->push_back(secondary_index);
1211 return bounds != displays->at(secondary_index).bounds();
1213 return false;
1216 void DisplayManager::CreateMirrorWindowIfAny() {
1217 if (HasSoftwareMirroringDisplay() && delegate_) {
1218 DisplayInfo display_info = GetDisplayInfo(mirroring_display_.id());
1219 delegate_->CreateOrUpdateMirroringDisplay(display_info);
1223 bool DisplayManager::HasSoftwareMirroringDisplay() {
1224 return second_display_mode_ != DisplayManager::EXTENDED &&
1225 mirroring_display_.is_valid();
1228 // static
1229 void DisplayManager::UpdateDisplayBoundsForLayout(
1230 const DisplayLayout& layout,
1231 const gfx::Display& primary_display,
1232 gfx::Display* secondary_display) {
1233 DCHECK_EQ("0,0", primary_display.bounds().origin().ToString());
1235 const gfx::Rect& primary_bounds = primary_display.bounds();
1236 const gfx::Rect& secondary_bounds = secondary_display->bounds();
1237 gfx::Point new_secondary_origin = primary_bounds.origin();
1239 DisplayLayout::Position position = layout.position;
1241 // Ignore the offset in case the secondary display doesn't share edges with
1242 // the primary display.
1243 int offset = layout.offset;
1244 if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM) {
1245 offset = std::min(
1246 offset, primary_bounds.width() - kMinimumOverlapForInvalidOffset);
1247 offset = std::max(
1248 offset, -secondary_bounds.width() + kMinimumOverlapForInvalidOffset);
1249 } else {
1250 offset = std::min(
1251 offset, primary_bounds.height() - kMinimumOverlapForInvalidOffset);
1252 offset = std::max(
1253 offset, -secondary_bounds.height() + kMinimumOverlapForInvalidOffset);
1255 switch (position) {
1256 case DisplayLayout::TOP:
1257 new_secondary_origin.Offset(offset, -secondary_bounds.height());
1258 break;
1259 case DisplayLayout::RIGHT:
1260 new_secondary_origin.Offset(primary_bounds.width(), offset);
1261 break;
1262 case DisplayLayout::BOTTOM:
1263 new_secondary_origin.Offset(offset, primary_bounds.height());
1264 break;
1265 case DisplayLayout::LEFT:
1266 new_secondary_origin.Offset(-secondary_bounds.width(), offset);
1267 break;
1269 gfx::Insets insets = secondary_display->GetWorkAreaInsets();
1270 secondary_display->set_bounds(
1271 gfx::Rect(new_secondary_origin, secondary_bounds.size()));
1272 secondary_display->UpdateWorkAreaFromInsets(insets);
1275 } // namespace ash