Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ash / display / display_manager.cc
blob00f2102253e396c968d7d66b791558115a1c4d41
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/display/display_manager.h"
7 #include <algorithm>
8 #include <cmath>
9 #include <set>
10 #include <string>
11 #include <vector>
13 #include "ash/ash_switches.h"
14 #include "ash/display/display_layout_store.h"
15 #include "ash/display/display_util.h"
16 #include "ash/display/extended_mouse_warp_controller.h"
17 #include "ash/display/null_mouse_warp_controller.h"
18 #include "ash/display/screen_ash.h"
19 #include "ash/display/unified_mouse_warp_controller.h"
20 #include "ash/screen_util.h"
21 #include "ash/shell.h"
22 #include "base/auto_reset.h"
23 #include "base/command_line.h"
24 #include "base/logging.h"
25 #include "base/metrics/histogram.h"
26 #include "base/run_loop.h"
27 #include "base/strings/string_number_conversions.h"
28 #include "base/strings/string_split.h"
29 #include "base/strings/stringprintf.h"
30 #include "base/strings/utf_string_conversions.h"
31 #include "grit/ash_strings.h"
32 #include "ui/base/l10n/l10n_util.h"
33 #include "ui/gfx/display.h"
34 #include "ui/gfx/display_observer.h"
35 #include "ui/gfx/font_render_params.h"
36 #include "ui/gfx/geometry/rect.h"
37 #include "ui/gfx/geometry/size_conversions.h"
38 #include "ui/gfx/screen.h"
40 #if defined(USE_X11)
41 #include "ui/base/x/x11_util.h"
42 #endif
44 #if defined(OS_CHROMEOS)
45 #include "ash/display/display_configurator_animation.h"
46 #include "base/sys_info.h"
47 #endif
49 #if defined(OS_WIN)
50 #include "base/win/windows_version.h"
51 #endif
53 #include "base/debug/stack_trace.h"
55 namespace ash {
56 typedef std::vector<gfx::Display> DisplayList;
57 typedef std::vector<DisplayInfo> DisplayInfoList;
59 namespace {
61 // We need to keep this in order for unittests to tell if
62 // the object in gfx::Screen::GetScreenByType is for shutdown.
63 gfx::Screen* screen_for_shutdown = NULL;
65 // The number of pixels to overlap between the primary and secondary displays,
66 // in case that the offset value is too large.
67 const int kMinimumOverlapForInvalidOffset = 100;
69 struct DisplaySortFunctor {
70 bool operator()(const gfx::Display& a, const gfx::Display& b) {
71 return a.id() < b.id();
75 struct DisplayInfoSortFunctor {
76 bool operator()(const DisplayInfo& a, const DisplayInfo& b) {
77 return a.id() < b.id();
81 struct DisplayModeMatcher {
82 DisplayModeMatcher(const DisplayMode& target_mode)
83 : target_mode(target_mode) {}
84 bool operator()(const DisplayMode& mode) {
85 return target_mode.IsEquivalent(mode);
87 DisplayMode target_mode;
90 gfx::Display& GetInvalidDisplay() {
91 static gfx::Display* invalid_display = new gfx::Display();
92 return *invalid_display;
95 void SetInternalDisplayModeList(DisplayInfo* info) {
96 DisplayMode native_mode;
97 native_mode.size = info->bounds_in_native().size();
98 native_mode.device_scale_factor = info->device_scale_factor();
99 native_mode.ui_scale = 1.0f;
100 info->SetDisplayModes(CreateInternalDisplayModeList(native_mode));
103 void MaybeInitInternalDisplay(DisplayInfo* info) {
104 int64 id = info->id();
105 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
106 if (command_line->HasSwitch(switches::kAshUseFirstDisplayAsInternal)) {
107 gfx::Display::SetInternalDisplayId(id);
108 SetInternalDisplayModeList(info);
112 } // namespace
114 using std::string;
115 using std::vector;
117 // static
118 int64 DisplayManager::kUnifiedDisplayId = -10;
120 DisplayManager::DisplayManager()
121 : delegate_(NULL),
122 screen_(new ScreenAsh),
123 layout_store_(new DisplayLayoutStore),
124 first_display_id_(gfx::Display::kInvalidDisplayID),
125 num_connected_displays_(0),
126 force_bounds_changed_(false),
127 change_display_upon_host_resize_(false),
128 multi_display_mode_(EXTENDED),
129 default_multi_display_mode_(EXTENDED),
130 mirroring_display_id_(gfx::Display::kInvalidDisplayID),
131 registered_internal_display_rotation_lock_(false),
132 registered_internal_display_rotation_(gfx::Display::ROTATE_0),
133 weak_ptr_factory_(this) {
134 #if defined(OS_CHROMEOS)
135 change_display_upon_host_resize_ = !base::SysInfo::IsRunningOnChromeOS();
136 #endif
137 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE, screen_.get());
138 gfx::Screen* current_native =
139 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE);
140 // If there is no native, or the native was for shutdown,
141 // use ash's screen.
142 if (!current_native ||
143 current_native == screen_for_shutdown) {
144 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, screen_.get());
148 DisplayManager::~DisplayManager() {
149 #if defined(OS_CHROMEOS)
150 // Reset the font params.
151 gfx::SetFontRenderParamsDeviceScaleFactor(1.0f);
152 #endif
155 bool DisplayManager::InitFromCommandLine() {
156 DisplayInfoList info_list;
157 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
158 if (!command_line->HasSwitch(switches::kAshHostWindowBounds))
159 return false;
160 const string size_str =
161 command_line->GetSwitchValueASCII(switches::kAshHostWindowBounds);
162 vector<string> parts;
163 base::SplitString(size_str, ',', &parts);
164 for (vector<string>::const_iterator iter = parts.begin();
165 iter != parts.end(); ++iter) {
166 info_list.push_back(DisplayInfo::CreateFromSpec(*iter));
167 info_list.back().set_native(true);
169 MaybeInitInternalDisplay(&info_list[0]);
170 if (info_list.size() > 1 &&
171 command_line->HasSwitch(switches::kAshEnableSoftwareMirroring)) {
172 SetMultiDisplayMode(MIRRORING);
174 OnNativeDisplaysChanged(info_list);
175 return true;
178 void DisplayManager::InitDefaultDisplay() {
179 DisplayInfoList info_list;
180 info_list.push_back(DisplayInfo::CreateFromSpec(std::string()));
181 info_list.back().set_native(true);
182 MaybeInitInternalDisplay(&info_list[0]);
183 OnNativeDisplaysChanged(info_list);
186 void DisplayManager::RefreshFontParams() {
187 #if defined(OS_CHROMEOS)
188 // Use the largest device scale factor among currently active displays. Non
189 // internal display may have bigger scale factor in case the external display
190 // is an 4K display.
191 float largest_device_scale_factor = 1.0f;
192 for (const gfx::Display& display : active_display_list_) {
193 const ash::DisplayInfo& info = display_info_[display.id()];
194 largest_device_scale_factor = std::max(
195 largest_device_scale_factor, info.GetEffectiveDeviceScaleFactor());
197 gfx::SetFontRenderParamsDeviceScaleFactor(largest_device_scale_factor);
198 #endif // OS_CHROMEOS
201 DisplayLayout DisplayManager::GetCurrentDisplayLayout() {
202 DCHECK_LE(2U, num_connected_displays());
203 // Invert if the primary was swapped.
204 if (num_connected_displays() == 2) {
205 DisplayIdPair pair = GetCurrentDisplayIdPair();
206 return layout_store_->ComputeDisplayLayoutForDisplayIdPair(pair);
207 } else if (num_connected_displays() > 2) {
208 // Return fixed horizontal layout for >= 3 displays.
209 DisplayLayout layout(DisplayLayout::RIGHT, 0);
210 return layout;
212 NOTREACHED() << "DisplayLayout is requested for single display";
213 // On release build, just fallback to default instead of blowing up.
214 DisplayLayout layout =
215 layout_store_->default_display_layout();
216 layout.primary_id = active_display_list_[0].id();
217 return layout;
220 DisplayIdPair DisplayManager::GetCurrentDisplayIdPair() const {
221 if (IsInUnifiedMode()) {
222 return std::make_pair(software_mirroring_display_list_[0].id(),
223 software_mirroring_display_list_[1].id());
224 } else if (IsInMirrorMode()) {
225 if (software_mirroring_enabled()) {
226 CHECK_EQ(2u, num_connected_displays());
227 // This comment is to make it easy to distinguish the crash
228 // between two checks.
229 CHECK_EQ(1u, active_display_list_.size());
231 return std::make_pair(active_display_list_[0].id(), mirroring_display_id_);
232 } else {
233 CHECK_LE(2u, active_display_list_.size());
234 int64 id_at_zero = active_display_list_[0].id();
235 if (gfx::Display::IsInternalDisplayId(id_at_zero) ||
236 id_at_zero == first_display_id()) {
237 return std::make_pair(id_at_zero, active_display_list_[1].id());
238 } else {
239 return std::make_pair(active_display_list_[1].id(), id_at_zero);
244 void DisplayManager::SetLayoutForCurrentDisplays(
245 const DisplayLayout& layout_relative_to_primary) {
246 if (GetNumDisplays() != 2)
247 return;
248 const gfx::Display& primary = screen_->GetPrimaryDisplay();
249 const DisplayIdPair pair = GetCurrentDisplayIdPair();
250 // Invert if the primary was swapped.
251 DisplayLayout to_set = pair.first == primary.id() ?
252 layout_relative_to_primary : layout_relative_to_primary.Invert();
254 DisplayLayout current_layout =
255 layout_store_->GetRegisteredDisplayLayout(pair);
256 if (to_set.position != current_layout.position ||
257 to_set.offset != current_layout.offset) {
258 to_set.primary_id = primary.id();
259 layout_store_->RegisterLayoutForDisplayIdPair(
260 pair.first, pair.second, to_set);
261 if (delegate_)
262 delegate_->PreDisplayConfigurationChange(false);
263 // PreDisplayConfigurationChange(false);
264 // TODO(oshima): Call UpdateDisplays instead.
265 const DisplayLayout layout = GetCurrentDisplayLayout();
266 UpdateDisplayBoundsForLayout(
267 layout, primary,
268 FindDisplayForId(ScreenUtil::GetSecondaryDisplay().id()));
270 // Primary's bounds stay the same. Just notify bounds change
271 // on the secondary.
272 screen_->NotifyMetricsChanged(
273 ScreenUtil::GetSecondaryDisplay(),
274 gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
275 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
276 if (delegate_)
277 delegate_->PostDisplayConfigurationChange();
281 const gfx::Display& DisplayManager::GetDisplayForId(int64 id) const {
282 gfx::Display* display =
283 const_cast<DisplayManager*>(this)->FindDisplayForId(id);
284 return display ? *display : GetInvalidDisplay();
287 const gfx::Display& DisplayManager::FindDisplayContainingPoint(
288 const gfx::Point& point_in_screen) const {
289 int index =
290 FindDisplayIndexContainingPoint(active_display_list_, point_in_screen);
291 return index < 0 ? GetInvalidDisplay() : active_display_list_[index];
294 bool DisplayManager::UpdateWorkAreaOfDisplay(int64 display_id,
295 const gfx::Insets& insets) {
296 gfx::Display* display = FindDisplayForId(display_id);
297 DCHECK(display);
298 gfx::Rect old_work_area = display->work_area();
299 display->UpdateWorkAreaFromInsets(insets);
300 return old_work_area != display->work_area();
303 void DisplayManager::SetOverscanInsets(int64 display_id,
304 const gfx::Insets& insets_in_dip) {
305 bool update = false;
306 DisplayInfoList display_info_list;
307 for (const auto& display : active_display_list_) {
308 DisplayInfo info = GetDisplayInfo(display.id());
309 if (info.id() == display_id) {
310 if (insets_in_dip.empty()) {
311 info.set_clear_overscan_insets(true);
312 } else {
313 info.set_clear_overscan_insets(false);
314 info.SetOverscanInsets(insets_in_dip);
316 update = true;
318 display_info_list.push_back(info);
320 if (update) {
321 AddMirrorDisplayInfoIfAny(&display_info_list);
322 UpdateDisplays(display_info_list);
323 } else {
324 display_info_[display_id].SetOverscanInsets(insets_in_dip);
328 void DisplayManager::SetDisplayRotation(int64 display_id,
329 gfx::Display::Rotation rotation,
330 gfx::Display::RotationSource source) {
331 if (IsInUnifiedMode())
332 return;
334 DisplayInfoList display_info_list;
335 bool is_active = false;
336 for (const auto& display : active_display_list_) {
337 DisplayInfo info = GetDisplayInfo(display.id());
338 if (info.id() == display_id) {
339 if (info.GetRotation(source) == rotation &&
340 info.GetActiveRotation() == rotation) {
341 return;
343 info.SetRotation(rotation, source);
344 is_active = true;
346 display_info_list.push_back(info);
348 if (is_active) {
349 AddMirrorDisplayInfoIfAny(&display_info_list);
350 UpdateDisplays(display_info_list);
351 } else if (display_info_.find(display_id) != display_info_.end()) {
352 // Inactive displays can reactivate, ensure they have been updated.
353 display_info_[display_id].SetRotation(rotation, source);
357 bool DisplayManager::SetDisplayUIScale(int64 display_id,
358 float ui_scale) {
359 if (GetDisplayIdForUIScaling() != display_id)
360 return false;
362 bool found = false;
363 // TODO(mukai): merge this implementation into SetDisplayMode().
364 DisplayInfoList display_info_list;
365 for (const auto& display : active_display_list_) {
366 DisplayInfo info = GetDisplayInfo(display.id());
367 if (info.id() == display_id) {
368 found = true;
369 if (info.configured_ui_scale() == ui_scale)
370 return true;
371 if (!HasDisplayModeForUIScale(info, ui_scale))
372 return false;
373 info.set_configured_ui_scale(ui_scale);
375 display_info_list.push_back(info);
377 if (found) {
378 AddMirrorDisplayInfoIfAny(&display_info_list);
379 UpdateDisplays(display_info_list);
380 return true;
382 return false;
385 void DisplayManager::SetDisplayResolution(int64 display_id,
386 const gfx::Size& resolution) {
387 DCHECK(!gfx::Display::IsInternalDisplayId(display_id));
388 if (gfx::Display::IsInternalDisplayId(display_id))
389 return;
390 const DisplayInfo& display_info = GetDisplayInfo(display_id);
391 const std::vector<DisplayMode>& modes = display_info.display_modes();
392 DCHECK_NE(0u, modes.size());
393 DisplayMode target_mode;
394 target_mode.size = resolution;
395 std::vector<DisplayMode>::const_iterator iter =
396 std::find_if(modes.begin(), modes.end(), DisplayModeMatcher(target_mode));
397 if (iter == modes.end()) {
398 LOG(WARNING) << "Unsupported resolution was requested:"
399 << resolution.ToString();
400 return;
402 display_modes_[display_id] = *iter;
403 #if defined(OS_CHROMEOS)
404 if (base::SysInfo::IsRunningOnChromeOS())
405 Shell::GetInstance()->display_configurator()->OnConfigurationChanged();
406 #endif
409 bool DisplayManager::SetDisplayMode(int64 display_id,
410 const DisplayMode& display_mode) {
411 if (GetDisplayIdForUIScaling() == display_id) {
412 SetDisplayUIScale(display_id, display_mode.ui_scale);
413 return false;
416 DisplayInfoList display_info_list;
417 bool display_property_changed = false;
418 bool resolution_changed = false;
419 for (const auto& display : active_display_list_) {
420 DisplayInfo info = GetDisplayInfo(display.id());
421 if (info.id() == display_id) {
422 const std::vector<DisplayMode>& modes = info.display_modes();
423 std::vector<DisplayMode>::const_iterator iter =
424 std::find_if(modes.begin(),
425 modes.end(),
426 DisplayModeMatcher(display_mode));
427 if (iter == modes.end()) {
428 LOG(WARNING) << "Unsupported resolution was requested:"
429 << display_mode.size.ToString();
430 return false;
432 display_modes_[display_id] = *iter;
433 if (info.bounds_in_native().size() != display_mode.size)
434 resolution_changed = true;
435 if (info.device_scale_factor() != display_mode.device_scale_factor) {
436 info.set_device_scale_factor(display_mode.device_scale_factor);
437 display_property_changed = true;
440 display_info_list.push_back(info);
442 if (display_property_changed) {
443 AddMirrorDisplayInfoIfAny(&display_info_list);
444 UpdateDisplays(display_info_list);
446 #if defined(OS_CHROMEOS)
447 if (resolution_changed && base::SysInfo::IsRunningOnChromeOS())
448 Shell::GetInstance()->display_configurator()->OnConfigurationChanged();
449 #endif
450 return resolution_changed;
453 void DisplayManager::RegisterDisplayProperty(
454 int64 display_id,
455 gfx::Display::Rotation rotation,
456 float ui_scale,
457 const gfx::Insets* overscan_insets,
458 const gfx::Size& resolution_in_pixels,
459 float device_scale_factor,
460 ui::ColorCalibrationProfile color_profile) {
461 if (display_info_.find(display_id) == display_info_.end())
462 display_info_[display_id] = DisplayInfo(display_id, std::string(), false);
464 // Do not allow rotation in unified desktop mode.
465 if (display_id == kUnifiedDisplayId)
466 rotation = gfx::Display::ROTATE_0;
468 display_info_[display_id].SetRotation(rotation,
469 gfx::Display::ROTATION_SOURCE_USER);
470 display_info_[display_id].SetRotation(rotation,
471 gfx::Display::ROTATION_SOURCE_ACTIVE);
472 display_info_[display_id].SetColorProfile(color_profile);
473 // Just in case the preference file was corrupted.
474 // TODO(mukai): register |display_modes_| here as well, so the lookup for the
475 // default mode in GetActiveModeForDisplayId() gets much simpler.
476 if (0.5f <= ui_scale && ui_scale <= 2.0f)
477 display_info_[display_id].set_configured_ui_scale(ui_scale);
478 if (overscan_insets)
479 display_info_[display_id].SetOverscanInsets(*overscan_insets);
480 if (!resolution_in_pixels.IsEmpty()) {
481 DCHECK(!gfx::Display::IsInternalDisplayId(display_id));
482 // Default refresh rate, until OnNativeDisplaysChanged() updates us with the
483 // actual display info, is 60 Hz.
484 DisplayMode mode(resolution_in_pixels, 60.0f, false, false);
485 mode.device_scale_factor = device_scale_factor;
486 display_modes_[display_id] = mode;
490 DisplayMode DisplayManager::GetActiveModeForDisplayId(int64 display_id) const {
491 DisplayMode selected_mode;
492 if (GetSelectedModeForDisplayId(display_id, &selected_mode))
493 return selected_mode;
495 // If 'selected' mode is empty, it should return the default mode. This means
496 // the native mode for the external display. Unfortunately this is not true
497 // for the internal display because restoring UI-scale doesn't register the
498 // restored mode to |display_mode_|, so it needs to look up the mode whose
499 // UI-scale value matches. See the TODO in RegisterDisplayProperty().
500 const DisplayInfo& info = GetDisplayInfo(display_id);
501 const std::vector<DisplayMode>& display_modes = info.display_modes();
503 if (GetDisplayIdForUIScaling() == display_id) {
504 for (size_t i = 0; i < display_modes.size(); ++i) {
505 if (info.configured_ui_scale() == display_modes[i].ui_scale)
506 return display_modes[i];
508 } else {
509 for (size_t i = 0; i < display_modes.size(); ++i) {
510 if (display_modes[i].native)
511 return display_modes[i];
514 return selected_mode;
517 void DisplayManager::RegisterDisplayRotationProperties(bool rotation_lock,
518 gfx::Display::Rotation rotation) {
519 if (delegate_)
520 delegate_->PreDisplayConfigurationChange(false);
521 registered_internal_display_rotation_lock_ = rotation_lock;
522 registered_internal_display_rotation_ = rotation;
523 if (delegate_)
524 delegate_->PostDisplayConfigurationChange();
527 bool DisplayManager::GetSelectedModeForDisplayId(int64 id,
528 DisplayMode* mode_out) const {
529 std::map<int64, DisplayMode>::const_iterator iter = display_modes_.find(id);
530 if (iter == display_modes_.end())
531 return false;
532 *mode_out = iter->second;
533 return true;
536 bool DisplayManager::IsDisplayUIScalingEnabled() const {
537 return GetDisplayIdForUIScaling() != gfx::Display::kInvalidDisplayID;
540 gfx::Insets DisplayManager::GetOverscanInsets(int64 display_id) const {
541 std::map<int64, DisplayInfo>::const_iterator it =
542 display_info_.find(display_id);
543 return (it != display_info_.end()) ?
544 it->second.overscan_insets_in_dip() : gfx::Insets();
547 void DisplayManager::SetColorCalibrationProfile(
548 int64 display_id,
549 ui::ColorCalibrationProfile profile) {
550 #if defined(OS_CHROMEOS)
551 if (!display_info_[display_id].IsColorProfileAvailable(profile))
552 return;
554 if (delegate_)
555 delegate_->PreDisplayConfigurationChange(false);
556 // Just sets color profile if it's not running on ChromeOS (like tests).
557 if (!base::SysInfo::IsRunningOnChromeOS() ||
558 Shell::GetInstance()->display_configurator()->SetColorCalibrationProfile(
559 display_id, profile)) {
560 display_info_[display_id].SetColorProfile(profile);
561 UMA_HISTOGRAM_ENUMERATION(
562 "ChromeOS.Display.ColorProfile", profile, ui::NUM_COLOR_PROFILES);
564 if (delegate_)
565 delegate_->PostDisplayConfigurationChange();
566 #endif
569 void DisplayManager::OnNativeDisplaysChanged(
570 const std::vector<DisplayInfo>& updated_displays) {
571 if (updated_displays.empty()) {
572 VLOG(1) << "OnNativeDisplaysChanged(0): # of current displays="
573 << active_display_list_.size();
574 // If the device is booted without display, or chrome is started
575 // without --ash-host-window-bounds on linux desktop, use the
576 // default display.
577 if (active_display_list_.empty()) {
578 std::vector<DisplayInfo> init_displays;
579 init_displays.push_back(DisplayInfo::CreateFromSpec(std::string()));
580 MaybeInitInternalDisplay(&init_displays[0]);
581 OnNativeDisplaysChanged(init_displays);
582 } else {
583 // Otherwise don't update the displays when all displays are disconnected.
584 // This happens when:
585 // - the device is idle and powerd requested to turn off all displays.
586 // - the device is suspended. (kernel turns off all displays)
587 // - the internal display's brightness is set to 0 and no external
588 // display is connected.
589 // - the internal display's brightness is 0 and external display is
590 // disconnected.
591 // The display will be updated when one of displays is turned on, and the
592 // display list will be updated correctly.
594 return;
596 first_display_id_ = updated_displays[0].id();
597 std::set<gfx::Point> origins;
599 if (updated_displays.size() == 1) {
600 VLOG(1) << "OnNativeDisplaysChanged(1):" << updated_displays[0].ToString();
601 } else {
602 VLOG(1) << "OnNativeDisplaysChanged(" << updated_displays.size()
603 << ") [0]=" << updated_displays[0].ToString()
604 << ", [1]=" << updated_displays[1].ToString();
607 bool internal_display_connected = false;
608 num_connected_displays_ = updated_displays.size();
609 mirroring_display_id_ = gfx::Display::kInvalidDisplayID;
610 software_mirroring_display_list_.clear();
611 DisplayInfoList new_display_info_list;
612 for (DisplayInfoList::const_iterator iter = updated_displays.begin();
613 iter != updated_displays.end();
614 ++iter) {
615 if (!internal_display_connected)
616 internal_display_connected =
617 gfx::Display::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 mirroring_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 (gfx::Display::HasInternalDisplay() && !internal_display_connected) {
647 if (display_info_.find(gfx::Display::InternalDisplayId()) ==
648 display_info_.end()) {
649 // Create a dummy internal display if the chrome restarted
650 // in docked mode.
651 DisplayInfo internal_display_info(
652 gfx::Display::InternalDisplayId(),
653 l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME),
654 false /*Internal display must not have overscan */);
655 internal_display_info.SetBounds(gfx::Rect(0, 0, 800, 600));
656 display_info_[gfx::Display::InternalDisplayId()] = internal_display_info;
657 } else {
658 // Internal display is no longer active. Reset its rotation to user
659 // preference, so that it is restored when the internal display becomes
660 // active again.
661 gfx::Display::Rotation user_rotation =
662 display_info_[gfx::Display::InternalDisplayId()].GetRotation(
663 gfx::Display::ROTATION_SOURCE_USER);
664 display_info_[gfx::Display::InternalDisplayId()].SetRotation(
665 user_rotation, gfx::Display::ROTATION_SOURCE_USER);
669 #if defined(OS_CHROMEOS)
670 if (new_display_info_list.size() > 1) {
671 std::sort(new_display_info_list.begin(), new_display_info_list.end(),
672 DisplayInfoSortFunctor());
673 DisplayIdPair pair = std::make_pair(new_display_info_list[0].id(),
674 new_display_info_list[1].id());
675 DisplayLayout layout = layout_store_->GetRegisteredDisplayLayout(pair);
676 default_multi_display_mode_ =
677 (layout.default_unified && switches::UnifiedDesktopEnabled())
678 ? UNIFIED
679 : EXTENDED;
680 // Mirror mode is set by DisplayConfigurator on the device.
681 // Emulate it when running on linux desktop.
682 if (!base::SysInfo::IsRunningOnChromeOS() && layout.mirrored)
683 SetMultiDisplayMode(MIRRORING);
685 #endif
687 UpdateDisplays(new_display_info_list);
690 void DisplayManager::UpdateDisplays() {
691 DisplayInfoList display_info_list;
692 for (const auto& display : active_display_list_)
693 display_info_list.push_back(GetDisplayInfo(display.id()));
694 AddMirrorDisplayInfoIfAny(&display_info_list);
695 UpdateDisplays(display_info_list);
698 void DisplayManager::UpdateDisplays(
699 const std::vector<DisplayInfo>& updated_display_info_list) {
700 #if defined(OS_WIN)
701 DCHECK_EQ(1u, updated_display_info_list.size()) <<
702 ": Multiple display test does not work on Windows bots. Please "
703 "skip (don't disable) the test using SupportsMultipleDisplays()";
704 #endif
706 DisplayInfoList new_display_info_list = updated_display_info_list;
707 std::sort(active_display_list_.begin(), active_display_list_.end(),
708 DisplaySortFunctor());
709 std::sort(new_display_info_list.begin(),
710 new_display_info_list.end(),
711 DisplayInfoSortFunctor());
713 if (multi_display_mode_ != MIRRORING)
714 multi_display_mode_ = default_multi_display_mode_;
716 CreateSoftwareMirroringDisplayInfo(&new_display_info_list);
718 // Close the mirroring window if any here to avoid creating two compositor on
719 // one display.
720 if (delegate_)
721 delegate_->CloseMirroringDisplayIfNotNecessary();
723 DisplayList new_displays;
724 DisplayList removed_displays;
725 std::map<size_t, uint32_t> display_changes;
726 std::vector<size_t> added_display_indices;
728 DisplayList::iterator curr_iter = active_display_list_.begin();
729 DisplayInfoList::const_iterator new_info_iter = new_display_info_list.begin();
731 while (curr_iter != active_display_list_.end() ||
732 new_info_iter != new_display_info_list.end()) {
733 if (curr_iter == active_display_list_.end()) {
734 // more displays in new list.
735 added_display_indices.push_back(new_displays.size());
736 InsertAndUpdateDisplayInfo(*new_info_iter);
737 new_displays.push_back(
738 CreateDisplayFromDisplayInfoById(new_info_iter->id()));
739 ++new_info_iter;
740 } else if (new_info_iter == new_display_info_list.end()) {
741 // more displays in current list.
742 removed_displays.push_back(*curr_iter);
743 ++curr_iter;
744 } else if (curr_iter->id() == new_info_iter->id()) {
745 const gfx::Display& current_display = *curr_iter;
746 // Copy the info because |CreateDisplayFromInfo| updates the instance.
747 const DisplayInfo current_display_info =
748 GetDisplayInfo(current_display.id());
749 InsertAndUpdateDisplayInfo(*new_info_iter);
750 gfx::Display new_display =
751 CreateDisplayFromDisplayInfoById(new_info_iter->id());
752 const DisplayInfo& new_display_info = GetDisplayInfo(new_display.id());
754 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_NONE;
756 // At that point the new Display objects we have are not entirely updated,
757 // they are missing the translation related to the Display disposition in
758 // the layout.
759 // Using display.bounds() and display.work_area() would fail most of the
760 // time.
761 if (force_bounds_changed_ ||
762 (current_display_info.bounds_in_native() !=
763 new_display_info.bounds_in_native()) ||
764 (current_display_info.GetOverscanInsetsInPixel() !=
765 new_display_info.GetOverscanInsetsInPixel()) ||
766 current_display.size() != new_display.size()) {
767 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
768 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
771 if (current_display.device_scale_factor() !=
772 new_display.device_scale_factor()) {
773 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
776 if (current_display.rotation() != new_display.rotation())
777 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_ROTATION;
779 if (metrics != gfx::DisplayObserver::DISPLAY_METRIC_NONE) {
780 display_changes.insert(
781 std::pair<size_t, uint32_t>(new_displays.size(), metrics));
784 new_display.UpdateWorkAreaFromInsets(current_display.GetWorkAreaInsets());
785 new_displays.push_back(new_display);
786 ++curr_iter;
787 ++new_info_iter;
788 } else if (curr_iter->id() < new_info_iter->id()) {
789 // more displays in current list between ids, which means it is deleted.
790 removed_displays.push_back(*curr_iter);
791 ++curr_iter;
792 } else {
793 // more displays in new list between ids, which means it is added.
794 added_display_indices.push_back(new_displays.size());
795 InsertAndUpdateDisplayInfo(*new_info_iter);
796 new_displays.push_back(
797 CreateDisplayFromDisplayInfoById(new_info_iter->id()));
798 ++new_info_iter;
801 gfx::Display old_primary;
802 if (delegate_)
803 old_primary = screen_->GetPrimaryDisplay();
805 // Clear focus if the display has been removed, but don't clear focus if
806 // the destkop has been moved from one display to another
807 // (mirror -> docked, docked -> single internal).
808 bool clear_focus =
809 !removed_displays.empty() &&
810 !(removed_displays.size() == 1 && added_display_indices.size() == 1);
811 if (delegate_)
812 delegate_->PreDisplayConfigurationChange(clear_focus);
814 std::vector<size_t> updated_indices;
815 if (UpdateNonPrimaryDisplayBoundsForLayout(&new_displays, &updated_indices)) {
816 for (std::vector<size_t>::iterator it = updated_indices.begin();
817 it != updated_indices.end(); ++it) {
818 size_t updated_index = *it;
819 if (std::find(added_display_indices.begin(),
820 added_display_indices.end(),
821 updated_index) == added_display_indices.end()) {
822 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
823 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
824 if (display_changes.find(updated_index) != display_changes.end())
825 metrics |= display_changes[updated_index];
827 display_changes[updated_index] = metrics;
832 active_display_list_ = new_displays;
834 RefreshFontParams();
835 base::AutoReset<bool> resetter(&change_display_upon_host_resize_, false);
837 int active_display_list_size = active_display_list_.size();
838 // Temporarily add displays to be removed because display object
839 // being removed are accessed during shutting down the root.
840 active_display_list_.insert(active_display_list_.end(),
841 removed_displays.begin(), removed_displays.end());
843 for (const auto& display : removed_displays)
844 screen_->NotifyDisplayRemoved(display);
846 for (size_t index : added_display_indices)
847 screen_->NotifyDisplayAdded(active_display_list_[index]);
849 active_display_list_.resize(active_display_list_size);
851 bool notify_primary_change =
852 delegate_ ? old_primary.id() != screen_->GetPrimaryDisplay().id() : false;
854 for (std::map<size_t, uint32_t>::iterator iter = display_changes.begin();
855 iter != display_changes.end();
856 ++iter) {
857 uint32_t metrics = iter->second;
858 const gfx::Display& updated_display = active_display_list_[iter->first];
860 if (notify_primary_change &&
861 updated_display.id() == screen_->GetPrimaryDisplay().id()) {
862 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_PRIMARY;
863 notify_primary_change = false;
865 screen_->NotifyMetricsChanged(updated_display, metrics);
868 if (notify_primary_change) {
869 // This happens when a primary display has moved to anther display without
870 // bounds change.
871 const gfx::Display& primary = screen_->GetPrimaryDisplay();
872 if (primary.id() != old_primary.id()) {
873 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_PRIMARY;
874 if (primary.size() != old_primary.size()) {
875 metrics |= (gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
876 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
878 if (primary.device_scale_factor() != old_primary.device_scale_factor())
879 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
881 screen_->NotifyMetricsChanged(primary, metrics);
885 if (delegate_)
886 delegate_->PostDisplayConfigurationChange();
888 #if defined(USE_X11) && defined(OS_CHROMEOS)
889 if (!display_changes.empty() && base::SysInfo::IsRunningOnChromeOS())
890 ui::ClearX11DefaultRootWindow();
891 #endif
893 // Create the mirroring window asynchronously after all displays
894 // are added so that it can mirror the display newly added. This can
895 // happen when switching from dock mode to software mirror mode.
896 CreateMirrorWindowAsyncIfAny();
899 const gfx::Display& DisplayManager::GetDisplayAt(size_t index) const {
900 DCHECK_LT(index, active_display_list_.size());
901 return active_display_list_[index];
904 const gfx::Display& DisplayManager::GetPrimaryDisplayCandidate() const {
905 if (GetNumDisplays() != 2)
906 return active_display_list_[0];
907 DisplayLayout layout = layout_store_->GetRegisteredDisplayLayout(
908 GetCurrentDisplayIdPair());
909 return GetDisplayForId(layout.primary_id);
912 size_t DisplayManager::GetNumDisplays() const {
913 return active_display_list_.size();
916 bool DisplayManager::IsInMirrorMode() const {
917 return mirroring_display_id_ != gfx::Display::kInvalidDisplayID;
920 bool DisplayManager::IsInUnifiedMode() const {
921 return multi_display_mode_ == UNIFIED &&
922 !software_mirroring_display_list_.empty();
925 const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const {
926 DCHECK_NE(gfx::Display::kInvalidDisplayID, display_id);
928 std::map<int64, DisplayInfo>::const_iterator iter =
929 display_info_.find(display_id);
930 CHECK(iter != display_info_.end()) << display_id;
931 return iter->second;
934 const gfx::Display DisplayManager::GetMirroringDisplayById(
935 int64 display_id) const {
936 auto iter = std::find_if(software_mirroring_display_list_.begin(),
937 software_mirroring_display_list_.end(),
938 [display_id](const gfx::Display& display) {
939 return display.id() == display_id;
941 return iter == software_mirroring_display_list_.end() ? gfx::Display()
942 : *iter;
945 std::string DisplayManager::GetDisplayNameForId(int64 id) {
946 if (id == gfx::Display::kInvalidDisplayID)
947 return l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME);
949 std::map<int64, DisplayInfo>::const_iterator iter = display_info_.find(id);
950 if (iter != display_info_.end() && !iter->second.name().empty())
951 return iter->second.name();
953 return base::StringPrintf("Display %d", static_cast<int>(id));
956 int64 DisplayManager::GetDisplayIdForUIScaling() const {
957 // UI Scaling is effective on internal display or on unified desktop.
958 return IsInUnifiedMode() ? kUnifiedDisplayId
959 : (gfx::Display::HasInternalDisplay()
960 ? gfx::Display::InternalDisplayId()
961 : gfx::Display::kInvalidDisplayID);
964 void DisplayManager::SetMirrorMode(bool mirror) {
965 #if defined(OS_CHROMEOS)
966 if (num_connected_displays() <= 1)
967 return;
969 if (base::SysInfo::IsRunningOnChromeOS()) {
970 ui::MultipleDisplayState new_state =
971 mirror ? ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR
972 : ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
973 Shell::GetInstance()->display_configurator()->SetDisplayMode(new_state);
974 return;
976 multi_display_mode_ = mirror ? MIRRORING : default_multi_display_mode_;
977 ReconfigureDisplays();
978 if (Shell::GetInstance()->display_configurator_animation()) {
979 Shell::GetInstance()->display_configurator_animation()->
980 StartFadeInAnimation();
982 RunPendingTasksForTest();
983 #endif
986 void DisplayManager::AddRemoveDisplay() {
987 DCHECK(!active_display_list_.empty());
988 std::vector<DisplayInfo> new_display_info_list;
989 const DisplayInfo& first_display =
990 IsInUnifiedMode()
991 ? GetDisplayInfo(software_mirroring_display_list_[0].id())
992 : GetDisplayInfo(active_display_list_[0].id());
993 new_display_info_list.push_back(first_display);
994 // Add if there is only one display connected.
995 if (num_connected_displays() == 1) {
996 const int kVerticalOffsetPx = 100;
997 // Layout the 2nd display below the primary as with the real device.
998 gfx::Rect host_bounds = first_display.bounds_in_native();
999 new_display_info_list.push_back(
1000 DisplayInfo::CreateFromSpec(base::StringPrintf(
1001 "%d+%d-600x%d", host_bounds.x(),
1002 host_bounds.bottom() + kVerticalOffsetPx, host_bounds.height())));
1004 num_connected_displays_ = new_display_info_list.size();
1005 mirroring_display_id_ = gfx::Display::kInvalidDisplayID;
1006 software_mirroring_display_list_.clear();
1007 UpdateDisplays(new_display_info_list);
1010 void DisplayManager::ToggleDisplayScaleFactor() {
1011 DCHECK(!active_display_list_.empty());
1012 std::vector<DisplayInfo> new_display_info_list;
1013 for (DisplayList::const_iterator iter = active_display_list_.begin();
1014 iter != active_display_list_.end(); ++iter) {
1015 DisplayInfo display_info = GetDisplayInfo(iter->id());
1016 display_info.set_device_scale_factor(
1017 display_info.device_scale_factor() == 1.0f ? 2.0f : 1.0f);
1018 new_display_info_list.push_back(display_info);
1020 AddMirrorDisplayInfoIfAny(&new_display_info_list);
1021 UpdateDisplays(new_display_info_list);
1024 #if defined(OS_CHROMEOS)
1025 void DisplayManager::SetSoftwareMirroring(bool enabled) {
1026 SetMultiDisplayMode(enabled ? MIRRORING : default_multi_display_mode_);
1029 bool DisplayManager::SoftwareMirroringEnabled() const {
1030 return software_mirroring_enabled();
1032 #endif
1034 void DisplayManager::SetMultiDisplayMode(MultiDisplayMode mode) {
1035 multi_display_mode_ = mode;
1036 mirroring_display_id_ = gfx::Display::kInvalidDisplayID;
1037 software_mirroring_display_list_.clear();
1040 void DisplayManager::SetDefaultMultiDisplayMode(MultiDisplayMode mode) {
1041 DCHECK_NE(mode, MIRRORING);
1042 default_multi_display_mode_ = mode;
1045 void DisplayManager::ReconfigureDisplays() {
1046 DisplayInfoList display_info_list;
1047 for (DisplayList::const_iterator iter = active_display_list_.begin();
1048 (display_info_list.size() < 2 && iter != active_display_list_.end());
1049 ++iter) {
1050 if (iter->id() == kUnifiedDisplayId)
1051 continue;
1052 display_info_list.push_back(GetDisplayInfo(iter->id()));
1054 for (auto iter = software_mirroring_display_list_.begin();
1055 (display_info_list.size() < 2 &&
1056 iter != software_mirroring_display_list_.end());
1057 ++iter) {
1058 display_info_list.push_back(GetDisplayInfo(iter->id()));
1060 mirroring_display_id_ = gfx::Display::kInvalidDisplayID;
1061 software_mirroring_display_list_.clear();
1062 UpdateDisplays(display_info_list);
1065 bool DisplayManager::UpdateDisplayBounds(int64 display_id,
1066 const gfx::Rect& new_bounds) {
1067 if (change_display_upon_host_resize_) {
1068 display_info_[display_id].SetBounds(new_bounds);
1069 // Don't notify observers if the mirrored window has changed.
1070 if (software_mirroring_enabled() && mirroring_display_id_ == display_id)
1071 return false;
1072 gfx::Display* display = FindDisplayForId(display_id);
1073 display->SetSize(display_info_[display_id].size_in_pixel());
1074 screen_->NotifyMetricsChanged(*display,
1075 gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS);
1076 return true;
1078 return false;
1081 void DisplayManager::CreateMirrorWindowAsyncIfAny() {
1082 // Do not post a task if the software mirroring doesn't exist, or
1083 // during initialization when compositor's init task isn't posted yet.
1084 // ash::Shell::Init() will call this after the compositor is initialized.
1085 if (software_mirroring_display_list_.empty() || !delegate_)
1086 return;
1087 base::MessageLoopForUI::current()->PostTask(
1088 FROM_HERE,
1089 base::Bind(&DisplayManager::CreateMirrorWindowIfAny,
1090 weak_ptr_factory_.GetWeakPtr()));
1093 scoped_ptr<MouseWarpController> DisplayManager::CreateMouseWarpController(
1094 aura::Window* drag_source) const {
1095 if (IsInUnifiedMode() && num_connected_displays() >= 2)
1096 return make_scoped_ptr(new UnifiedMouseWarpController());
1097 // Extra check for |num_connected_displays()| is for SystemDisplayApiTest
1098 // that injects MockScreen.
1099 if (GetNumDisplays() < 2 || num_connected_displays() < 2)
1100 return make_scoped_ptr(new NullMouseWarpController());
1101 return make_scoped_ptr(new ExtendedMouseWarpController(drag_source));
1104 void DisplayManager::CreateScreenForShutdown() const {
1105 bool native_is_ash =
1106 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE) == screen_.get();
1107 delete screen_for_shutdown;
1108 screen_for_shutdown = screen_->CloneForShutdown();
1109 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE,
1110 screen_for_shutdown);
1111 if (native_is_ash) {
1112 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE,
1113 screen_for_shutdown);
1117 void DisplayManager::UpdateInternalDisplayModeListForTest() {
1118 if (!gfx::Display::HasInternalDisplay() ||
1119 display_info_.count(gfx::Display::InternalDisplayId()) == 0)
1120 return;
1121 DisplayInfo* info = &display_info_[gfx::Display::InternalDisplayId()];
1122 SetInternalDisplayModeList(info);
1125 void DisplayManager::CreateSoftwareMirroringDisplayInfo(
1126 DisplayInfoList* display_info_list) {
1127 // Use the internal display or 1st as the mirror source, then scale
1128 // the root window so that it matches the external display's
1129 // resolution. This is necessary in order for scaling to work while
1130 // mirrored.
1131 if (display_info_list->size() == 2) {
1132 switch (multi_display_mode_) {
1133 case MIRRORING: {
1134 bool zero_is_source =
1135 first_display_id_ == (*display_info_list)[0].id() ||
1136 gfx::Display::IsInternalDisplayId((*display_info_list)[0].id());
1137 DCHECK_EQ(MIRRORING, multi_display_mode_);
1138 mirroring_display_id_ =
1139 (*display_info_list)[zero_is_source ? 1 : 0].id();
1141 int64 display_id = mirroring_display_id_;
1142 auto iter =
1143 std::find_if(display_info_list->begin(), display_info_list->end(),
1144 [display_id](const DisplayInfo& info) {
1145 return info.id() == display_id;
1147 DCHECK(iter != display_info_list->end());
1149 DisplayInfo info = *iter;
1150 info.SetOverscanInsets(gfx::Insets());
1151 InsertAndUpdateDisplayInfo(info);
1152 software_mirroring_display_list_.push_back(
1153 CreateMirroringDisplayFromDisplayInfoById(mirroring_display_id_,
1154 gfx::Point(), 1.0f));
1155 display_info_list->erase(iter);
1156 break;
1158 case UNIFIED: {
1159 // TODO(oshima): Currently, all displays are laid out horizontally,
1160 // from left to right. Allow more flexible layouts, such as
1161 // right to left, or vertical layouts.
1162 gfx::Rect unified_bounds;
1163 software_mirroring_display_list_.clear();
1165 int max_height = std::numeric_limits<int>::min();
1166 for (auto& info : *display_info_list)
1167 max_height = std::max(max_height, info.size_in_pixel().height());
1169 std::vector<DisplayMode> display_mode_list;
1170 std::set<float> ui_scales;
1172 for (auto& info : *display_info_list) {
1173 InsertAndUpdateDisplayInfo(info);
1174 gfx::Point origin(unified_bounds.right(), 0);
1175 float ui_scale =
1176 info.size_in_pixel().height() / static_cast<float>(max_height);
1177 // The display is scaled to fit the unified desktop size.
1178 gfx::Display display = CreateMirroringDisplayFromDisplayInfoById(
1179 info.id(), origin, 1.0f / ui_scale);
1180 display.UpdateWorkAreaFromInsets(gfx::Insets());
1181 unified_bounds.Union(display.bounds());
1183 ui_scales.insert(ui_scale);
1185 software_mirroring_display_list_.push_back(display);
1187 DisplayInfo info(kUnifiedDisplayId, "Unified Desktop", false);
1188 info.SetBounds(unified_bounds);
1190 DisplayMode native_mode(unified_bounds.size(), 60.0f, false, true);
1191 info.SetDisplayModes(
1192 CreateUnifiedDisplayModeList(native_mode, ui_scales));
1194 display_info_list->clear();
1195 display_info_list->push_back(info);
1196 InsertAndUpdateDisplayInfo(info);
1197 break;
1199 case EXTENDED:
1200 break;
1205 gfx::Display* DisplayManager::FindDisplayForId(int64 id) {
1206 auto iter = std::find_if(
1207 active_display_list_.begin(), active_display_list_.end(),
1208 [id](const gfx::Display& display) { return display.id() == id; });
1209 if (iter != active_display_list_.end())
1210 return &(*iter);
1211 // TODO(oshima): This happens when a windows in unified desktop have
1212 // been moved to normal window. Fix this.
1213 if (id != kUnifiedDisplayId)
1214 DLOG(WARNING) << "Could not find display:" << id;
1215 return NULL;
1218 void DisplayManager::AddMirrorDisplayInfoIfAny(
1219 std::vector<DisplayInfo>* display_info_list) {
1220 if (software_mirroring_enabled() && IsInMirrorMode())
1221 display_info_list->push_back(GetDisplayInfo(mirroring_display_id_));
1224 void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo& new_info) {
1225 std::map<int64, DisplayInfo>::iterator info =
1226 display_info_.find(new_info.id());
1227 if (info != display_info_.end()) {
1228 info->second.Copy(new_info);
1229 } else {
1230 display_info_[new_info.id()] = new_info;
1231 display_info_[new_info.id()].set_native(false);
1233 display_info_[new_info.id()].UpdateDisplaySize();
1234 OnDisplayInfoUpdated(display_info_[new_info.id()]);
1237 void DisplayManager::OnDisplayInfoUpdated(const DisplayInfo& display_info) {
1238 #if defined(OS_CHROMEOS)
1239 ui::ColorCalibrationProfile color_profile = display_info.color_profile();
1240 if (color_profile != ui::COLOR_PROFILE_STANDARD) {
1241 Shell::GetInstance()->display_configurator()->SetColorCalibrationProfile(
1242 display_info.id(), color_profile);
1244 #endif
1247 gfx::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64 id) {
1248 DCHECK(display_info_.find(id) != display_info_.end()) << "id=" << id;
1249 const DisplayInfo& display_info = display_info_[id];
1251 gfx::Display new_display(display_info.id());
1252 gfx::Rect bounds_in_native(display_info.size_in_pixel());
1253 float device_scale_factor = display_info.GetEffectiveDeviceScaleFactor();
1255 // Simply set the origin to (0,0). The primary display's origin is
1256 // always (0,0) and the bounds of non-primary display(s) will be updated
1257 // in |UpdateNonPrimaryDisplayBoundsForLayout| called in |UpdateDisplay|.
1258 new_display.SetScaleAndBounds(
1259 device_scale_factor, gfx::Rect(bounds_in_native.size()));
1260 new_display.set_rotation(display_info.GetActiveRotation());
1261 new_display.set_touch_support(display_info.touch_support());
1262 return new_display;
1265 gfx::Display DisplayManager::CreateMirroringDisplayFromDisplayInfoById(
1266 int64 id,
1267 const gfx::Point& origin,
1268 float scale) {
1269 DCHECK(display_info_.find(id) != display_info_.end()) << "id=" << id;
1270 const DisplayInfo& display_info = display_info_[id];
1272 gfx::Display new_display(display_info.id());
1273 new_display.SetScaleAndBounds(
1274 1.0f, gfx::Rect(origin, gfx::ToFlooredSize(gfx::ScaleSize(
1275 display_info.size_in_pixel(), scale))));
1276 new_display.set_touch_support(display_info.touch_support());
1277 return new_display;
1280 bool DisplayManager::UpdateNonPrimaryDisplayBoundsForLayout(
1281 DisplayList* displays,
1282 std::vector<size_t>* updated_indices) const {
1284 if (displays->size() < 2U)
1285 return false;
1287 if (displays->size() > 2U) {
1288 // For more than 2 displays, always use horizontal layout.
1289 int x_offset = displays->at(0).bounds().width();
1290 for (size_t i = 1; i < displays->size(); ++i) {
1291 gfx::Display& display = displays->at(i);
1292 const gfx::Rect& bounds = display.bounds();
1293 gfx::Point origin = gfx::Point(x_offset, 0);
1294 gfx::Insets insets = display.GetWorkAreaInsets();
1295 display.set_bounds(gfx::Rect(origin, bounds.size()));
1296 display.UpdateWorkAreaFromInsets(insets);
1297 x_offset += bounds.width();
1298 updated_indices->push_back(i);
1300 return true;
1303 int64 id_at_zero = displays->at(0).id();
1304 DisplayIdPair pair = (id_at_zero == first_display_id_ ||
1305 gfx::Display::IsInternalDisplayId(id_at_zero))
1306 ? std::make_pair(id_at_zero, displays->at(1).id())
1307 : std::make_pair(displays->at(1).id(), id_at_zero);
1308 DisplayLayout layout =
1309 layout_store_->ComputeDisplayLayoutForDisplayIdPair(pair);
1311 // Ignore if a user has a old format (should be extremely rare)
1312 // and this will be replaced with DCHECK.
1313 if (layout.primary_id != gfx::Display::kInvalidDisplayID) {
1314 size_t primary_index, secondary_index;
1315 if (displays->at(0).id() == layout.primary_id) {
1316 primary_index = 0;
1317 secondary_index = 1;
1318 } else {
1319 primary_index = 1;
1320 secondary_index = 0;
1322 // This function may be called before the secondary display is
1323 // registered. The bounds is empty in that case and will
1324 // return true.
1325 gfx::Rect bounds =
1326 GetDisplayForId(displays->at(secondary_index).id()).bounds();
1327 UpdateDisplayBoundsForLayout(
1328 layout, displays->at(primary_index), &displays->at(secondary_index));
1329 updated_indices->push_back(secondary_index);
1330 return bounds != displays->at(secondary_index).bounds();
1332 return false;
1335 void DisplayManager::CreateMirrorWindowIfAny() {
1336 if (software_mirroring_display_list_.empty() || !delegate_)
1337 return;
1338 DisplayInfoList list;
1339 for (auto& display : software_mirroring_display_list_)
1340 list.push_back(GetDisplayInfo(display.id()));
1341 delegate_->CreateOrUpdateMirroringDisplay(list);
1344 // static
1345 void DisplayManager::UpdateDisplayBoundsForLayout(
1346 const DisplayLayout& layout,
1347 const gfx::Display& primary_display,
1348 gfx::Display* secondary_display) {
1349 DCHECK_EQ("0,0", primary_display.bounds().origin().ToString());
1351 const gfx::Rect& primary_bounds = primary_display.bounds();
1352 const gfx::Rect& secondary_bounds = secondary_display->bounds();
1353 gfx::Point new_secondary_origin = primary_bounds.origin();
1355 DisplayLayout::Position position = layout.position;
1357 // Ignore the offset in case the secondary display doesn't share edges with
1358 // the primary display.
1359 int offset = layout.offset;
1360 if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM) {
1361 offset = std::min(
1362 offset, primary_bounds.width() - kMinimumOverlapForInvalidOffset);
1363 offset = std::max(
1364 offset, -secondary_bounds.width() + kMinimumOverlapForInvalidOffset);
1365 } else {
1366 offset = std::min(
1367 offset, primary_bounds.height() - kMinimumOverlapForInvalidOffset);
1368 offset = std::max(
1369 offset, -secondary_bounds.height() + kMinimumOverlapForInvalidOffset);
1371 switch (position) {
1372 case DisplayLayout::TOP:
1373 new_secondary_origin.Offset(offset, -secondary_bounds.height());
1374 break;
1375 case DisplayLayout::RIGHT:
1376 new_secondary_origin.Offset(primary_bounds.width(), offset);
1377 break;
1378 case DisplayLayout::BOTTOM:
1379 new_secondary_origin.Offset(offset, primary_bounds.height());
1380 break;
1381 case DisplayLayout::LEFT:
1382 new_secondary_origin.Offset(-secondary_bounds.width(), offset);
1383 break;
1385 gfx::Insets insets = secondary_display->GetWorkAreaInsets();
1386 secondary_display->set_bounds(
1387 gfx::Rect(new_secondary_origin, secondary_bounds.size()));
1388 secondary_display->UpdateWorkAreaFromInsets(insets);
1391 void DisplayManager::RunPendingTasksForTest() {
1392 if (!software_mirroring_display_list_.empty())
1393 base::RunLoop().RunUntilIdle();
1396 } // namespace ash