Rename initial_pos to initial_rect in ShowWidget and ShowView IPCs.
[chromium-blink-merge.git] / ash / display / display_manager.cc
blobc407da47751977e3c47a3f80052cf4edbe76b058
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 mode, it
814 // is possible there is no need to update |displays_| and we early out
815 // here. But we still want to run the PostDisplayConfigurationChange()
816 // cause there are some clients need to act on this, e.g.
817 // TouchTransformerController needs to adjust the TouchTransformer when
818 // switching from dual displays to single display.
819 if (delegate_)
820 delegate_->PostDisplayConfigurationChange();
821 return;
824 std::vector<size_t> updated_indices;
825 if (UpdateNonPrimaryDisplayBoundsForLayout(&new_displays, &updated_indices)) {
826 for (std::vector<size_t>::iterator it = updated_indices.begin();
827 it != updated_indices.end(); ++it) {
828 size_t updated_index = *it;
829 if (std::find(added_display_indices.begin(),
830 added_display_indices.end(),
831 updated_index) == added_display_indices.end()) {
832 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
833 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
834 if (display_changes.find(updated_index) != display_changes.end())
835 metrics |= display_changes[updated_index];
837 display_changes[updated_index] = metrics;
842 displays_ = new_displays;
844 RefreshFontParams();
845 base::AutoReset<bool> resetter(&change_display_upon_host_resize_, false);
847 // Temporarily add displays to be removed because display object
848 // being removed are accessed during shutting down the root.
849 displays_.insert(displays_.end(), removed_displays.begin(),
850 removed_displays.end());
852 for (DisplayList::const_reverse_iterator iter = removed_displays.rbegin();
853 iter != removed_displays.rend(); ++iter) {
854 screen_ash_->NotifyDisplayRemoved(displays_.back());
855 displays_.pop_back();
858 bool has_mirroring_display = HasSoftwareMirroringDisplay();
859 // Close the mirroring window here to avoid creating two compositor on
860 // one display.
861 if (!has_mirroring_display && delegate_)
862 delegate_->CloseMirroringDisplay();
864 for (std::vector<size_t>::iterator iter = added_display_indices.begin();
865 iter != added_display_indices.end(); ++iter) {
866 screen_ash_->NotifyDisplayAdded(displays_[*iter]);
869 bool notify_primary_change =
870 delegate_ ? old_primary.id() != screen_->GetPrimaryDisplay().id() : false;
872 for (std::map<size_t, uint32_t>::iterator iter = display_changes.begin();
873 iter != display_changes.end();
874 ++iter) {
875 uint32_t metrics = iter->second;
876 const gfx::Display& updated_display = displays_[iter->first];
878 if (notify_primary_change &&
879 updated_display.id() == screen_->GetPrimaryDisplay().id()) {
880 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_PRIMARY;
881 notify_primary_change = false;
883 screen_ash_->NotifyMetricsChanged(updated_display, metrics);
886 if (notify_primary_change) {
887 // This happens when a primary display has moved to anther display without
888 // bounds change.
889 const gfx::Display& primary = screen_->GetPrimaryDisplay();
890 if (primary.id() != old_primary.id()) {
891 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_PRIMARY;
892 if (primary.size() != old_primary.size()) {
893 metrics |= (gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
894 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
896 if (primary.device_scale_factor() != old_primary.device_scale_factor())
897 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
899 screen_ash_->NotifyMetricsChanged(primary, metrics);
903 if (delegate_)
904 delegate_->PostDisplayConfigurationChange();
906 #if defined(USE_X11) && defined(OS_CHROMEOS)
907 if (!display_changes.empty() && base::SysInfo::IsRunningOnChromeOS())
908 ui::ClearX11DefaultRootWindow();
909 #endif
911 // Create the mirroring window asynchronously after all displays
912 // are added so that it can mirror the display newly added. This can
913 // happen when switching from dock mode to software mirror mode.
914 if (has_mirroring_display && delegate_)
915 CreateMirrorWindowAsyncIfAny();
918 const gfx::Display& DisplayManager::GetDisplayAt(size_t index) const {
919 DCHECK_LT(index, displays_.size());
920 return displays_[index];
923 const gfx::Display& DisplayManager::GetPrimaryDisplayCandidate() const {
924 if (GetNumDisplays() != 2)
925 return displays_[0];
926 DisplayLayout layout = layout_store_->GetRegisteredDisplayLayout(
927 GetCurrentDisplayIdPair());
928 return GetDisplayForId(layout.primary_id);
931 size_t DisplayManager::GetNumDisplays() const {
932 return displays_.size();
935 bool DisplayManager::IsMirrored() const {
936 return mirrored_display_id_ != gfx::Display::kInvalidDisplayID;
939 const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const {
940 DCHECK_NE(gfx::Display::kInvalidDisplayID, display_id);
942 std::map<int64, DisplayInfo>::const_iterator iter =
943 display_info_.find(display_id);
944 CHECK(iter != display_info_.end()) << display_id;
945 return iter->second;
948 std::string DisplayManager::GetDisplayNameForId(int64 id) {
949 if (id == gfx::Display::kInvalidDisplayID)
950 return l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME);
952 std::map<int64, DisplayInfo>::const_iterator iter = display_info_.find(id);
953 if (iter != display_info_.end() && !iter->second.name().empty())
954 return iter->second.name();
956 return base::StringPrintf("Display %d", static_cast<int>(id));
959 int64 DisplayManager::GetDisplayIdForUIScaling() const {
960 // UI Scaling is effective only on internal display.
961 int64 display_id = gfx::Display::InternalDisplayId();
962 #if defined(OS_WIN)
963 display_id = first_display_id();
964 #endif
965 return display_id;
968 void DisplayManager::SetMirrorMode(bool mirrored) {
969 if (num_connected_displays() <= 1)
970 return;
972 #if defined(OS_CHROMEOS)
973 if (base::SysInfo::IsRunningOnChromeOS()) {
974 ui::MultipleDisplayState new_state =
975 mirrored ? ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR :
976 ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
977 Shell::GetInstance()->display_configurator()->SetDisplayMode(new_state);
978 return;
980 #endif
981 // This is fallback path to emulate mirroroing on desktop.
982 SetSecondDisplayMode(mirrored ? MIRRORING : EXTENDED);
983 DisplayInfoList display_info_list;
984 int count = 0;
985 for (std::map<int64, DisplayInfo>::const_iterator iter =
986 display_info_.begin();
987 count < 2; ++iter, ++count) {
988 display_info_list.push_back(GetDisplayInfo(iter->second.id()));
990 UpdateDisplays(display_info_list);
991 #if defined(OS_CHROMEOS)
992 if (Shell::GetInstance()->display_configurator_animation()) {
993 Shell::GetInstance()->display_configurator_animation()->
994 StartFadeInAnimation();
996 #endif
999 void DisplayManager::AddRemoveDisplay() {
1000 DCHECK(!displays_.empty());
1001 std::vector<DisplayInfo> new_display_info_list;
1002 const DisplayInfo& first_display = GetDisplayInfo(displays_[0].id());
1003 new_display_info_list.push_back(first_display);
1004 // Add if there is only one display connected.
1005 if (num_connected_displays() == 1) {
1006 // Layout the 2nd display below the primary as with the real device.
1007 gfx::Rect host_bounds = first_display.bounds_in_native();
1008 new_display_info_list.push_back(DisplayInfo::CreateFromSpec(
1009 base::StringPrintf(
1010 "%d+%d-500x400", host_bounds.x(), host_bounds.bottom())));
1012 num_connected_displays_ = new_display_info_list.size();
1013 mirrored_display_id_ = gfx::Display::kInvalidDisplayID;
1014 mirroring_display_ = gfx::Display();
1015 UpdateDisplays(new_display_info_list);
1018 void DisplayManager::ToggleDisplayScaleFactor() {
1019 DCHECK(!displays_.empty());
1020 std::vector<DisplayInfo> new_display_info_list;
1021 for (DisplayList::const_iterator iter = displays_.begin();
1022 iter != displays_.end(); ++iter) {
1023 DisplayInfo display_info = GetDisplayInfo(iter->id());
1024 display_info.set_device_scale_factor(
1025 display_info.device_scale_factor() == 1.0f ? 2.0f : 1.0f);
1026 new_display_info_list.push_back(display_info);
1028 AddMirrorDisplayInfoIfAny(&new_display_info_list);
1029 UpdateDisplays(new_display_info_list);
1032 #if defined(OS_CHROMEOS)
1033 void DisplayManager::SetSoftwareMirroring(bool enabled) {
1034 SetSecondDisplayMode(enabled ? MIRRORING : EXTENDED);
1037 bool DisplayManager::SoftwareMirroringEnabled() const {
1038 return software_mirroring_enabled();
1040 #endif
1042 void DisplayManager::SetSecondDisplayMode(SecondDisplayMode mode) {
1043 second_display_mode_ = mode;
1044 mirrored_display_id_ = gfx::Display::kInvalidDisplayID;
1045 mirroring_display_ = gfx::Display();
1048 bool DisplayManager::UpdateDisplayBounds(int64 display_id,
1049 const gfx::Rect& new_bounds) {
1050 if (change_display_upon_host_resize_) {
1051 display_info_[display_id].SetBounds(new_bounds);
1052 // Don't notify observers if the mirrored window has changed.
1053 if (software_mirroring_enabled() && mirrored_display_id_ == display_id)
1054 return false;
1055 gfx::Display* display = FindDisplayForId(display_id);
1056 display->SetSize(display_info_[display_id].size_in_pixel());
1057 screen_ash_->NotifyMetricsChanged(
1058 *display, gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS);
1059 return true;
1061 return false;
1064 void DisplayManager::CreateMirrorWindowAsyncIfAny() {
1065 base::MessageLoopForUI::current()->PostTask(
1066 FROM_HERE,
1067 base::Bind(&DisplayManager::CreateMirrorWindowIfAny,
1068 weak_ptr_factory_.GetWeakPtr()));
1071 void DisplayManager::CreateScreenForShutdown() const {
1072 bool native_is_ash =
1073 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE) ==
1074 screen_ash_.get();
1075 delete screen_for_shutdown;
1076 screen_for_shutdown = screen_ash_->CloneForShutdown();
1077 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE,
1078 screen_for_shutdown);
1079 if (native_is_ash) {
1080 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE,
1081 screen_for_shutdown);
1085 void DisplayManager::UpdateInternalDisplayModeListForTest() {
1086 if (display_info_.count(gfx::Display::InternalDisplayId()) == 0)
1087 return;
1088 DisplayInfo* info = &display_info_[gfx::Display::InternalDisplayId()];
1089 SetInternalDisplayModeList(info);
1092 gfx::Display* DisplayManager::FindDisplayForId(int64 id) {
1093 for (DisplayList::iterator iter = displays_.begin();
1094 iter != displays_.end(); ++iter) {
1095 if ((*iter).id() == id)
1096 return &(*iter);
1098 DLOG(WARNING) << "Could not find display:" << id;
1099 return NULL;
1102 void DisplayManager::AddMirrorDisplayInfoIfAny(
1103 std::vector<DisplayInfo>* display_info_list) {
1104 if (software_mirroring_enabled() && IsMirrored())
1105 display_info_list->push_back(GetDisplayInfo(mirrored_display_id_));
1108 void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo& new_info) {
1109 std::map<int64, DisplayInfo>::iterator info =
1110 display_info_.find(new_info.id());
1111 if (info != display_info_.end()) {
1112 info->second.Copy(new_info);
1113 } else {
1114 display_info_[new_info.id()] = new_info;
1115 display_info_[new_info.id()].set_native(false);
1117 display_info_[new_info.id()].UpdateDisplaySize();
1118 OnDisplayInfoUpdated(display_info_[new_info.id()]);
1121 void DisplayManager::OnDisplayInfoUpdated(const DisplayInfo& display_info) {
1122 #if defined(OS_CHROMEOS)
1123 ui::ColorCalibrationProfile color_profile = display_info.color_profile();
1124 if (color_profile != ui::COLOR_PROFILE_STANDARD) {
1125 Shell::GetInstance()->display_configurator()->SetColorCalibrationProfile(
1126 display_info.id(), color_profile);
1128 #endif
1131 gfx::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64 id) {
1132 DCHECK(display_info_.find(id) != display_info_.end());
1133 const DisplayInfo& display_info = display_info_[id];
1135 gfx::Display new_display(display_info.id());
1136 gfx::Rect bounds_in_native(display_info.size_in_pixel());
1137 float device_scale_factor = display_info.GetEffectiveDeviceScaleFactor();
1139 // Simply set the origin to (0,0). The primary display's origin is
1140 // always (0,0) and the bounds of non-primary display(s) will be updated
1141 // in |UpdateNonPrimaryDisplayBoundsForLayout| called in |UpdateDisplay|.
1142 new_display.SetScaleAndBounds(
1143 device_scale_factor, gfx::Rect(bounds_in_native.size()));
1144 new_display.set_rotation(display_info.rotation());
1145 new_display.set_touch_support(display_info.touch_support());
1146 return new_display;
1149 bool DisplayManager::UpdateNonPrimaryDisplayBoundsForLayout(
1150 DisplayList* displays,
1151 std::vector<size_t>* updated_indices) const {
1153 if (displays->size() < 2U)
1154 return false;
1156 if (displays->size() > 2U) {
1157 // For more than 2 displays, always use horizontal layout.
1158 int x_offset = displays->at(0).bounds().width();
1159 for (size_t i = 1; i < displays->size(); ++i) {
1160 gfx::Display& display = displays->at(i);
1161 const gfx::Rect& bounds = display.bounds();
1162 gfx::Point origin = gfx::Point(x_offset, 0);
1163 gfx::Insets insets = display.GetWorkAreaInsets();
1164 display.set_bounds(gfx::Rect(origin, bounds.size()));
1165 display.UpdateWorkAreaFromInsets(insets);
1166 x_offset += bounds.width();
1167 updated_indices->push_back(i);
1169 return true;
1172 int64 id_at_zero = displays->at(0).id();
1173 DisplayIdPair pair =
1174 (id_at_zero == first_display_id_ ||
1175 id_at_zero == gfx::Display::InternalDisplayId()) ?
1176 std::make_pair(id_at_zero, displays->at(1).id()) :
1177 std::make_pair(displays->at(1).id(), id_at_zero);
1178 DisplayLayout layout =
1179 layout_store_->ComputeDisplayLayoutForDisplayIdPair(pair);
1181 // Ignore if a user has a old format (should be extremely rare)
1182 // and this will be replaced with DCHECK.
1183 if (layout.primary_id != gfx::Display::kInvalidDisplayID) {
1184 size_t primary_index, secondary_index;
1185 if (displays->at(0).id() == layout.primary_id) {
1186 primary_index = 0;
1187 secondary_index = 1;
1188 } else {
1189 primary_index = 1;
1190 secondary_index = 0;
1192 // This function may be called before the secondary display is
1193 // registered. The bounds is empty in that case and will
1194 // return true.
1195 gfx::Rect bounds =
1196 GetDisplayForId(displays->at(secondary_index).id()).bounds();
1197 UpdateDisplayBoundsForLayout(
1198 layout, displays->at(primary_index), &displays->at(secondary_index));
1199 updated_indices->push_back(secondary_index);
1200 return bounds != displays->at(secondary_index).bounds();
1202 return false;
1205 void DisplayManager::CreateMirrorWindowIfAny() {
1206 if (HasSoftwareMirroringDisplay() && delegate_) {
1207 DisplayInfo display_info = GetDisplayInfo(mirroring_display_.id());
1208 delegate_->CreateOrUpdateMirroringDisplay(display_info);
1212 bool DisplayManager::HasSoftwareMirroringDisplay() {
1213 return second_display_mode_ != DisplayManager::EXTENDED &&
1214 mirroring_display_.is_valid();
1217 // static
1218 void DisplayManager::UpdateDisplayBoundsForLayout(
1219 const DisplayLayout& layout,
1220 const gfx::Display& primary_display,
1221 gfx::Display* secondary_display) {
1222 DCHECK_EQ("0,0", primary_display.bounds().origin().ToString());
1224 const gfx::Rect& primary_bounds = primary_display.bounds();
1225 const gfx::Rect& secondary_bounds = secondary_display->bounds();
1226 gfx::Point new_secondary_origin = primary_bounds.origin();
1228 DisplayLayout::Position position = layout.position;
1230 // Ignore the offset in case the secondary display doesn't share edges with
1231 // the primary display.
1232 int offset = layout.offset;
1233 if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM) {
1234 offset = std::min(
1235 offset, primary_bounds.width() - kMinimumOverlapForInvalidOffset);
1236 offset = std::max(
1237 offset, -secondary_bounds.width() + kMinimumOverlapForInvalidOffset);
1238 } else {
1239 offset = std::min(
1240 offset, primary_bounds.height() - kMinimumOverlapForInvalidOffset);
1241 offset = std::max(
1242 offset, -secondary_bounds.height() + kMinimumOverlapForInvalidOffset);
1244 switch (position) {
1245 case DisplayLayout::TOP:
1246 new_secondary_origin.Offset(offset, -secondary_bounds.height());
1247 break;
1248 case DisplayLayout::RIGHT:
1249 new_secondary_origin.Offset(primary_bounds.width(), offset);
1250 break;
1251 case DisplayLayout::BOTTOM:
1252 new_secondary_origin.Offset(offset, primary_bounds.height());
1253 break;
1254 case DisplayLayout::LEFT:
1255 new_secondary_origin.Offset(-secondary_bounds.width(), offset);
1256 break;
1258 gfx::Insets insets = secondary_display->GetWorkAreaInsets();
1259 secondary_display->set_bounds(
1260 gfx::Rect(new_secondary_origin, secondary_bounds.size()));
1261 secondary_display->UpdateWorkAreaFromInsets(insets);
1264 } // namespace ash