Don't preload rarely seen large images
[chromium-blink-merge.git] / ash / display / display_manager.cc
blobc8a2b9dfd309b22ee943e5745b6a2aaa593710a9
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/display/display_manager.h"
7 #include <algorithm>
8 #include <cmath>
9 #include <set>
10 #include <string>
11 #include <vector>
13 #include "ash/ash_switches.h"
14 #include "ash/display/display_layout_store.h"
15 #include "ash/display/display_util.h"
16 #include "ash/display/extended_mouse_warp_controller.h"
17 #include "ash/display/null_mouse_warp_controller.h"
18 #include "ash/display/screen_ash.h"
19 #include "ash/display/unified_mouse_warp_controller.h"
20 #include "ash/screen_util.h"
21 #include "ash/shell.h"
22 #include "base/auto_reset.h"
23 #include "base/command_line.h"
24 #include "base/logging.h"
25 #include "base/metrics/histogram.h"
26 #include "base/run_loop.h"
27 #include "base/strings/string_number_conversions.h"
28 #include "base/strings/string_split.h"
29 #include "base/strings/stringprintf.h"
30 #include "base/strings/utf_string_conversions.h"
31 #include "grit/ash_strings.h"
32 #include "ui/base/l10n/l10n_util.h"
33 #include "ui/gfx/display.h"
34 #include "ui/gfx/display_observer.h"
35 #include "ui/gfx/font_render_params.h"
36 #include "ui/gfx/geometry/rect.h"
37 #include "ui/gfx/geometry/size_conversions.h"
38 #include "ui/gfx/screen.h"
40 #if defined(USE_X11)
41 #include "ui/base/x/x11_util.h"
42 #endif
44 #if defined(OS_CHROMEOS)
45 #include "ash/display/display_configurator_animation.h"
46 #include "base/sys_info.h"
47 #endif
49 #if defined(OS_WIN)
50 #include "base/win/windows_version.h"
51 #endif
53 #include "base/debug/stack_trace.h"
55 namespace ash {
56 typedef std::vector<gfx::Display> DisplayList;
57 typedef std::vector<DisplayInfo> DisplayInfoList;
59 namespace {
61 // We need to keep this in order for unittests to tell if
62 // the object in gfx::Screen::GetScreenByType is for shutdown.
63 gfx::Screen* screen_for_shutdown = NULL;
65 // The number of pixels to overlap between the primary and secondary displays,
66 // in case that the offset value is too large.
67 const int kMinimumOverlapForInvalidOffset = 100;
69 struct DisplaySortFunctor {
70 bool operator()(const gfx::Display& a, const gfx::Display& b) {
71 return a.id() < b.id();
75 struct DisplayInfoSortFunctor {
76 bool operator()(const DisplayInfo& a, const DisplayInfo& b) {
77 return a.id() < b.id();
81 struct DisplayModeMatcher {
82 DisplayModeMatcher(const DisplayMode& target_mode)
83 : target_mode(target_mode) {}
84 bool operator()(const DisplayMode& mode) {
85 return target_mode.IsEquivalent(mode);
87 DisplayMode target_mode;
90 gfx::Display& GetInvalidDisplay() {
91 static gfx::Display* invalid_display = new gfx::Display();
92 return *invalid_display;
95 void SetInternalDisplayModeList(DisplayInfo* info) {
96 DisplayMode native_mode;
97 native_mode.size = info->bounds_in_native().size();
98 native_mode.device_scale_factor = info->device_scale_factor();
99 native_mode.ui_scale = 1.0f;
100 info->SetDisplayModes(CreateInternalDisplayModeList(native_mode));
103 void MaybeInitInternalDisplay(DisplayInfo* info) {
104 int64 id = info->id();
105 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
106 if (command_line->HasSwitch(switches::kAshUseFirstDisplayAsInternal)) {
107 gfx::Display::SetInternalDisplayId(id);
108 SetInternalDisplayModeList(info);
112 bool IsInternalDisplayId(int64 id) {
113 return gfx::Display::InternalDisplayId() == id;
116 } // namespace
118 using std::string;
119 using std::vector;
121 // static
122 int64 DisplayManager::kUnifiedDisplayId = -10;
124 DisplayManager::DisplayManager()
125 : delegate_(NULL),
126 screen_(new ScreenAsh),
127 layout_store_(new DisplayLayoutStore),
128 first_display_id_(gfx::Display::kInvalidDisplayID),
129 num_connected_displays_(0),
130 force_bounds_changed_(false),
131 change_display_upon_host_resize_(false),
132 multi_display_mode_(EXTENDED),
133 default_multi_display_mode_(EXTENDED),
134 mirroring_display_id_(gfx::Display::kInvalidDisplayID),
135 registered_internal_display_rotation_lock_(false),
136 registered_internal_display_rotation_(gfx::Display::ROTATE_0),
137 weak_ptr_factory_(this) {
138 #if defined(OS_CHROMEOS)
139 // Enable only on the device so that DisplayManagerFontTest passes.
140 if (base::SysInfo::IsRunningOnChromeOS())
141 DisplayInfo::SetUse125DSFForUIScaling(true);
143 change_display_upon_host_resize_ = !base::SysInfo::IsRunningOnChromeOS();
144 #endif
145 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE, screen_.get());
146 gfx::Screen* current_native =
147 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE);
148 // If there is no native, or the native was for shutdown,
149 // use ash's screen.
150 if (!current_native ||
151 current_native == screen_for_shutdown) {
152 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, screen_.get());
156 DisplayManager::~DisplayManager() {
157 #if defined(OS_CHROMEOS)
158 // Reset the font params.
159 gfx::SetFontRenderParamsDeviceScaleFactor(1.0f);
160 #endif
163 bool DisplayManager::InitFromCommandLine() {
164 DisplayInfoList info_list;
165 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
166 if (!command_line->HasSwitch(switches::kAshHostWindowBounds))
167 return false;
168 const string size_str =
169 command_line->GetSwitchValueASCII(switches::kAshHostWindowBounds);
170 vector<string> parts;
171 base::SplitString(size_str, ',', &parts);
172 for (vector<string>::const_iterator iter = parts.begin();
173 iter != parts.end(); ++iter) {
174 info_list.push_back(DisplayInfo::CreateFromSpec(*iter));
175 info_list.back().set_native(true);
177 MaybeInitInternalDisplay(&info_list[0]);
178 if (info_list.size() > 1 &&
179 command_line->HasSwitch(switches::kAshEnableSoftwareMirroring)) {
180 SetMultiDisplayMode(MIRRORING);
182 OnNativeDisplaysChanged(info_list);
183 return true;
186 void DisplayManager::InitDefaultDisplay() {
187 DisplayInfoList info_list;
188 info_list.push_back(DisplayInfo::CreateFromSpec(std::string()));
189 info_list.back().set_native(true);
190 MaybeInitInternalDisplay(&info_list[0]);
191 OnNativeDisplaysChanged(info_list);
194 void DisplayManager::RefreshFontParams() {
195 #if defined(OS_CHROMEOS)
196 // Use the largest device scale factor among currently active displays. Non
197 // internal display may have bigger scale factor in case the external display
198 // is an 4K display.
199 float largest_device_scale_factor = 1.0f;
200 for (const gfx::Display& display : active_display_list_) {
201 const ash::DisplayInfo& info = display_info_[display.id()];
202 largest_device_scale_factor = std::max(
203 largest_device_scale_factor, info.GetEffectiveDeviceScaleFactor());
205 gfx::SetFontRenderParamsDeviceScaleFactor(largest_device_scale_factor);
206 #endif // OS_CHROMEOS
209 DisplayLayout DisplayManager::GetCurrentDisplayLayout() {
210 DCHECK_LE(2U, num_connected_displays());
211 // Invert if the primary was swapped.
212 if (num_connected_displays() == 2) {
213 DisplayIdPair pair = GetCurrentDisplayIdPair();
214 return layout_store_->ComputeDisplayLayoutForDisplayIdPair(pair);
215 } else if (num_connected_displays() > 2) {
216 // Return fixed horizontal layout for >= 3 displays.
217 DisplayLayout layout(DisplayLayout::RIGHT, 0);
218 return layout;
220 NOTREACHED() << "DisplayLayout is requested for single display";
221 // On release build, just fallback to default instead of blowing up.
222 DisplayLayout layout =
223 layout_store_->default_display_layout();
224 layout.primary_id = active_display_list_[0].id();
225 return layout;
228 DisplayIdPair DisplayManager::GetCurrentDisplayIdPair() const {
229 if (IsInUnifiedMode()) {
230 return std::make_pair(software_mirroring_display_list_[0].id(),
231 software_mirroring_display_list_[1].id());
232 } else if (IsInMirrorMode()) {
233 if (software_mirroring_enabled()) {
234 CHECK_EQ(2u, num_connected_displays());
235 // This comment is to make it easy to distinguish the crash
236 // between two checks.
237 CHECK_EQ(1u, active_display_list_.size());
239 return std::make_pair(active_display_list_[0].id(), mirroring_display_id_);
240 } else {
241 CHECK_LE(2u, active_display_list_.size());
242 int64 id_at_zero = active_display_list_[0].id();
243 if (id_at_zero == gfx::Display::InternalDisplayId() ||
244 id_at_zero == first_display_id()) {
245 return std::make_pair(id_at_zero, active_display_list_[1].id());
246 } else {
247 return std::make_pair(active_display_list_[1].id(), id_at_zero);
252 void DisplayManager::SetLayoutForCurrentDisplays(
253 const DisplayLayout& layout_relative_to_primary) {
254 if (GetNumDisplays() != 2)
255 return;
256 const gfx::Display& primary = screen_->GetPrimaryDisplay();
257 const DisplayIdPair pair = GetCurrentDisplayIdPair();
258 // Invert if the primary was swapped.
259 DisplayLayout to_set = pair.first == primary.id() ?
260 layout_relative_to_primary : layout_relative_to_primary.Invert();
262 DisplayLayout current_layout =
263 layout_store_->GetRegisteredDisplayLayout(pair);
264 if (to_set.position != current_layout.position ||
265 to_set.offset != current_layout.offset) {
266 to_set.primary_id = primary.id();
267 layout_store_->RegisterLayoutForDisplayIdPair(
268 pair.first, pair.second, to_set);
269 if (delegate_)
270 delegate_->PreDisplayConfigurationChange(false);
271 // PreDisplayConfigurationChange(false);
272 // TODO(oshima): Call UpdateDisplays instead.
273 const DisplayLayout layout = GetCurrentDisplayLayout();
274 UpdateDisplayBoundsForLayout(
275 layout, primary,
276 FindDisplayForId(ScreenUtil::GetSecondaryDisplay().id()));
278 // Primary's bounds stay the same. Just notify bounds change
279 // on the secondary.
280 screen_->NotifyMetricsChanged(
281 ScreenUtil::GetSecondaryDisplay(),
282 gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
283 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
284 if (delegate_)
285 delegate_->PostDisplayConfigurationChange();
289 const gfx::Display& DisplayManager::GetDisplayForId(int64 id) const {
290 gfx::Display* display =
291 const_cast<DisplayManager*>(this)->FindDisplayForId(id);
292 return display ? *display : GetInvalidDisplay();
295 const gfx::Display& DisplayManager::FindDisplayContainingPoint(
296 const gfx::Point& point_in_screen) const {
297 int index =
298 FindDisplayIndexContainingPoint(active_display_list_, point_in_screen);
299 return index < 0 ? GetInvalidDisplay() : active_display_list_[index];
302 bool DisplayManager::UpdateWorkAreaOfDisplay(int64 display_id,
303 const gfx::Insets& insets) {
304 gfx::Display* display = FindDisplayForId(display_id);
305 DCHECK(display);
306 gfx::Rect old_work_area = display->work_area();
307 display->UpdateWorkAreaFromInsets(insets);
308 return old_work_area != display->work_area();
311 void DisplayManager::SetOverscanInsets(int64 display_id,
312 const gfx::Insets& insets_in_dip) {
313 bool update = false;
314 DisplayInfoList display_info_list;
315 for (const auto& display : active_display_list_) {
316 DisplayInfo info = GetDisplayInfo(display.id());
317 if (info.id() == display_id) {
318 if (insets_in_dip.empty()) {
319 info.set_clear_overscan_insets(true);
320 } else {
321 info.set_clear_overscan_insets(false);
322 info.SetOverscanInsets(insets_in_dip);
324 update = true;
326 display_info_list.push_back(info);
328 if (update) {
329 AddMirrorDisplayInfoIfAny(&display_info_list);
330 UpdateDisplays(display_info_list);
331 } else {
332 display_info_[display_id].SetOverscanInsets(insets_in_dip);
336 void DisplayManager::SetDisplayRotation(int64 display_id,
337 gfx::Display::Rotation rotation,
338 gfx::Display::RotationSource source) {
339 DisplayInfoList display_info_list;
340 bool is_active = false;
341 for (const auto& display : active_display_list_) {
342 DisplayInfo info = GetDisplayInfo(display.id());
343 if (info.id() == display_id) {
344 if (info.GetRotation(source) == rotation &&
345 info.GetActiveRotation() == rotation) {
346 return;
348 info.SetRotation(rotation, source);
349 is_active = true;
351 display_info_list.push_back(info);
353 if (is_active) {
354 AddMirrorDisplayInfoIfAny(&display_info_list);
355 UpdateDisplays(display_info_list);
356 } else if (display_info_.find(display_id) != display_info_.end()) {
357 // Inactive displays can reactivate, ensure they have been updated.
358 display_info_[display_id].SetRotation(rotation, source);
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 (const auto& display : active_display_list_) {
372 DisplayInfo info = GetDisplayInfo(display.id());
373 if (info.id() == display_id) {
374 found = true;
375 if (info.configured_ui_scale() == ui_scale)
376 return true;
377 if (!HasDisplayModeForUIScale(info, ui_scale))
378 return false;
379 info.set_configured_ui_scale(ui_scale);
381 display_info_list.push_back(info);
383 if (found) {
384 AddMirrorDisplayInfoIfAny(&display_info_list);
385 UpdateDisplays(display_info_list);
386 return true;
388 return false;
391 void DisplayManager::SetDisplayResolution(int64 display_id,
392 const gfx::Size& resolution) {
393 DCHECK_NE(gfx::Display::InternalDisplayId(), display_id);
394 if (gfx::Display::InternalDisplayId() == display_id)
395 return;
396 const DisplayInfo& display_info = GetDisplayInfo(display_id);
397 const std::vector<DisplayMode>& modes = display_info.display_modes();
398 DCHECK_NE(0u, modes.size());
399 DisplayMode target_mode;
400 target_mode.size = resolution;
401 std::vector<DisplayMode>::const_iterator iter =
402 std::find_if(modes.begin(), modes.end(), DisplayModeMatcher(target_mode));
403 if (iter == modes.end()) {
404 LOG(WARNING) << "Unsupported resolution was requested:"
405 << resolution.ToString();
406 return;
408 display_modes_[display_id] = *iter;
409 #if defined(OS_CHROMEOS)
410 if (base::SysInfo::IsRunningOnChromeOS())
411 Shell::GetInstance()->display_configurator()->OnConfigurationChanged();
412 #endif
415 bool DisplayManager::SetDisplayMode(int64 display_id,
416 const DisplayMode& display_mode) {
417 if (IsInternalDisplayId(display_id)) {
418 SetDisplayUIScale(display_id, display_mode.ui_scale);
419 return false;
422 DisplayInfoList display_info_list;
423 bool display_property_changed = false;
424 bool resolution_changed = false;
425 for (const auto& display : active_display_list_) {
426 DisplayInfo info = GetDisplayInfo(display.id());
427 if (info.id() == display_id) {
428 const std::vector<DisplayMode>& modes = info.display_modes();
429 std::vector<DisplayMode>::const_iterator iter =
430 std::find_if(modes.begin(),
431 modes.end(),
432 DisplayModeMatcher(display_mode));
433 if (iter == modes.end()) {
434 LOG(WARNING) << "Unsupported resolution was requested:"
435 << display_mode.size.ToString();
436 return false;
438 display_modes_[display_id] = *iter;
439 if (info.bounds_in_native().size() != display_mode.size)
440 resolution_changed = true;
441 if (info.device_scale_factor() != display_mode.device_scale_factor) {
442 info.set_device_scale_factor(display_mode.device_scale_factor);
443 display_property_changed = true;
446 display_info_list.push_back(info);
448 if (display_property_changed) {
449 AddMirrorDisplayInfoIfAny(&display_info_list);
450 UpdateDisplays(display_info_list);
452 #if defined(OS_CHROMEOS)
453 if (resolution_changed && base::SysInfo::IsRunningOnChromeOS())
454 Shell::GetInstance()->display_configurator()->OnConfigurationChanged();
455 #endif
456 return resolution_changed;
459 void DisplayManager::RegisterDisplayProperty(
460 int64 display_id,
461 gfx::Display::Rotation rotation,
462 float ui_scale,
463 const gfx::Insets* overscan_insets,
464 const gfx::Size& resolution_in_pixels,
465 float device_scale_factor,
466 ui::ColorCalibrationProfile color_profile) {
467 if (display_info_.find(display_id) == display_info_.end())
468 display_info_[display_id] = DisplayInfo(display_id, std::string(), false);
470 display_info_[display_id].SetRotation(rotation,
471 gfx::Display::ROTATION_SOURCE_USER);
472 display_info_[display_id].SetRotation(rotation,
473 gfx::Display::ROTATION_SOURCE_ACTIVE);
474 display_info_[display_id].SetColorProfile(color_profile);
475 // Just in case the preference file was corrupted.
476 // TODO(mukai): register |display_modes_| here as well, so the lookup for the
477 // default mode in GetActiveModeForDisplayId() gets much simpler.
478 if (0.5f <= ui_scale && ui_scale <= 2.0f)
479 display_info_[display_id].set_configured_ui_scale(ui_scale);
480 if (overscan_insets)
481 display_info_[display_id].SetOverscanInsets(*overscan_insets);
482 if (!resolution_in_pixels.IsEmpty()) {
483 DCHECK(!IsInternalDisplayId(display_id));
484 // Default refresh rate, until OnNativeDisplaysChanged() updates us with the
485 // actual display info, is 60 Hz.
486 DisplayMode mode(resolution_in_pixels, 60.0f, false, false);
487 mode.device_scale_factor = device_scale_factor;
488 display_modes_[display_id] = mode;
492 DisplayMode DisplayManager::GetActiveModeForDisplayId(int64 display_id) const {
493 DisplayMode selected_mode;
494 if (GetSelectedModeForDisplayId(display_id, &selected_mode))
495 return selected_mode;
497 // If 'selected' mode is empty, it should return the default mode. This means
498 // the native mode for the external display. Unfortunately this is not true
499 // for the internal display because restoring UI-scale doesn't register the
500 // restored mode to |display_mode_|, so it needs to look up the mode whose
501 // UI-scale value matches. See the TODO in RegisterDisplayProperty().
502 const DisplayInfo& info = GetDisplayInfo(display_id);
503 const std::vector<DisplayMode>& display_modes = info.display_modes();
505 if (IsInternalDisplayId(display_id)) {
506 for (size_t i = 0; i < display_modes.size(); ++i) {
507 if (info.configured_ui_scale() == display_modes[i].ui_scale)
508 return display_modes[i];
510 } else {
511 for (size_t i = 0; i < display_modes.size(); ++i) {
512 if (display_modes[i].native)
513 return display_modes[i];
516 return selected_mode;
519 void DisplayManager::RegisterDisplayRotationProperties(bool rotation_lock,
520 gfx::Display::Rotation rotation) {
521 if (delegate_)
522 delegate_->PreDisplayConfigurationChange(false);
523 registered_internal_display_rotation_lock_ = rotation_lock;
524 registered_internal_display_rotation_ = rotation;
525 if (delegate_)
526 delegate_->PostDisplayConfigurationChange();
529 bool DisplayManager::GetSelectedModeForDisplayId(int64 id,
530 DisplayMode* mode_out) const {
531 std::map<int64, DisplayMode>::const_iterator iter = display_modes_.find(id);
532 if (iter == display_modes_.end())
533 return false;
534 *mode_out = iter->second;
535 return true;
538 bool DisplayManager::IsDisplayUIScalingEnabled() const {
539 return GetDisplayIdForUIScaling() != gfx::Display::kInvalidDisplayID;
542 gfx::Insets DisplayManager::GetOverscanInsets(int64 display_id) const {
543 std::map<int64, DisplayInfo>::const_iterator it =
544 display_info_.find(display_id);
545 return (it != display_info_.end()) ?
546 it->second.overscan_insets_in_dip() : gfx::Insets();
549 void DisplayManager::SetColorCalibrationProfile(
550 int64 display_id,
551 ui::ColorCalibrationProfile profile) {
552 #if defined(OS_CHROMEOS)
553 if (!display_info_[display_id].IsColorProfileAvailable(profile))
554 return;
556 if (delegate_)
557 delegate_->PreDisplayConfigurationChange(false);
558 // Just sets color profile if it's not running on ChromeOS (like tests).
559 if (!base::SysInfo::IsRunningOnChromeOS() ||
560 Shell::GetInstance()->display_configurator()->SetColorCalibrationProfile(
561 display_id, profile)) {
562 display_info_[display_id].SetColorProfile(profile);
563 UMA_HISTOGRAM_ENUMERATION(
564 "ChromeOS.Display.ColorProfile", profile, ui::NUM_COLOR_PROFILES);
566 if (delegate_)
567 delegate_->PostDisplayConfigurationChange();
568 #endif
571 void DisplayManager::OnNativeDisplaysChanged(
572 const std::vector<DisplayInfo>& updated_displays) {
573 if (updated_displays.empty()) {
574 VLOG(1) << "OnNativeDisplaysChanged(0): # of current displays="
575 << active_display_list_.size();
576 // If the device is booted without display, or chrome is started
577 // without --ash-host-window-bounds on linux desktop, use the
578 // default display.
579 if (active_display_list_.empty()) {
580 std::vector<DisplayInfo> init_displays;
581 init_displays.push_back(DisplayInfo::CreateFromSpec(std::string()));
582 MaybeInitInternalDisplay(&init_displays[0]);
583 OnNativeDisplaysChanged(init_displays);
584 } else {
585 // Otherwise don't update the displays when all displays are disconnected.
586 // This happens when:
587 // - the device is idle and powerd requested to turn off all displays.
588 // - the device is suspended. (kernel turns off all displays)
589 // - the internal display's brightness is set to 0 and no external
590 // display is connected.
591 // - the internal display's brightness is 0 and external display is
592 // disconnected.
593 // The display will be updated when one of displays is turned on, and the
594 // display list will be updated correctly.
596 return;
598 first_display_id_ = updated_displays[0].id();
599 std::set<gfx::Point> origins;
601 if (updated_displays.size() == 1) {
602 VLOG(1) << "OnNativeDisplaysChanged(1):" << updated_displays[0].ToString();
603 } else {
604 VLOG(1) << "OnNativeDisplaysChanged(" << updated_displays.size()
605 << ") [0]=" << updated_displays[0].ToString()
606 << ", [1]=" << updated_displays[1].ToString();
609 bool internal_display_connected = false;
610 num_connected_displays_ = updated_displays.size();
611 mirroring_display_id_ = gfx::Display::kInvalidDisplayID;
612 software_mirroring_display_list_.clear();
613 DisplayInfoList new_display_info_list;
614 for (DisplayInfoList::const_iterator iter = updated_displays.begin();
615 iter != updated_displays.end();
616 ++iter) {
617 if (!internal_display_connected)
618 internal_display_connected = IsInternalDisplayId(iter->id());
619 // Mirrored monitors have the same origins.
620 gfx::Point origin = iter->bounds_in_native().origin();
621 if (origins.find(origin) != origins.end()) {
622 InsertAndUpdateDisplayInfo(*iter);
623 mirroring_display_id_ = iter->id();
624 } else {
625 origins.insert(origin);
626 new_display_info_list.push_back(*iter);
629 DisplayMode new_mode;
630 new_mode.size = iter->bounds_in_native().size();
631 new_mode.device_scale_factor = iter->device_scale_factor();
632 new_mode.ui_scale = iter->configured_ui_scale();
633 const std::vector<DisplayMode>& display_modes = iter->display_modes();
634 // This is empty the displays are initialized from InitFromCommandLine.
635 if (!display_modes.size())
636 continue;
637 std::vector<DisplayMode>::const_iterator display_modes_iter =
638 std::find_if(display_modes.begin(),
639 display_modes.end(),
640 DisplayModeMatcher(new_mode));
641 // Update the actual resolution selected as the resolution request may fail.
642 if (display_modes_iter == display_modes.end())
643 display_modes_.erase(iter->id());
644 else if (display_modes_.find(iter->id()) != display_modes_.end())
645 display_modes_[iter->id()] = *display_modes_iter;
647 if (gfx::Display::HasInternalDisplay() && !internal_display_connected) {
648 if (display_info_.find(gfx::Display::InternalDisplayId()) ==
649 display_info_.end()) {
650 // Create a dummy internal display if the chrome restarted
651 // in docked mode.
652 DisplayInfo internal_display_info(
653 gfx::Display::InternalDisplayId(),
654 l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME),
655 false /*Internal display must not have overscan */);
656 internal_display_info.SetBounds(gfx::Rect(0, 0, 800, 600));
657 display_info_[gfx::Display::InternalDisplayId()] = internal_display_info;
658 } else {
659 // Internal display is no longer active. Reset its rotation to user
660 // preference, so that it is restored when the internal display becomes
661 // active again.
662 gfx::Display::Rotation user_rotation =
663 display_info_[gfx::Display::InternalDisplayId()].GetRotation(
664 gfx::Display::ROTATION_SOURCE_USER);
665 display_info_[gfx::Display::InternalDisplayId()].SetRotation(
666 user_rotation, gfx::Display::ROTATION_SOURCE_USER);
670 #if defined(OS_CHROMEOS)
671 if (new_display_info_list.size() > 1) {
672 std::sort(new_display_info_list.begin(), new_display_info_list.end(),
673 DisplayInfoSortFunctor());
674 DisplayIdPair pair = std::make_pair(new_display_info_list[0].id(),
675 new_display_info_list[1].id());
676 DisplayLayout layout = layout_store_->GetRegisteredDisplayLayout(pair);
677 default_multi_display_mode_ =
678 (layout.default_unified && switches::UnifiedDesktopEnabled())
679 ? UNIFIED
680 : EXTENDED;
681 // Mirror mode is set by DisplayConfigurator on the device.
682 // Emulate it when running on linux desktop.
683 if (!base::SysInfo::IsRunningOnChromeOS() && layout.mirrored)
684 SetMultiDisplayMode(MIRRORING);
686 #endif
688 UpdateDisplays(new_display_info_list);
691 void DisplayManager::UpdateDisplays() {
692 DisplayInfoList display_info_list;
693 for (const auto& display : active_display_list_)
694 display_info_list.push_back(GetDisplayInfo(display.id()));
695 AddMirrorDisplayInfoIfAny(&display_info_list);
696 UpdateDisplays(display_info_list);
699 void DisplayManager::UpdateDisplays(
700 const std::vector<DisplayInfo>& updated_display_info_list) {
701 #if defined(OS_WIN)
702 DCHECK_EQ(1u, updated_display_info_list.size()) <<
703 ": Multiple display test does not work on Windows bots. Please "
704 "skip (don't disable) the test using SupportsMultipleDisplays()";
705 #endif
707 DisplayInfoList new_display_info_list = updated_display_info_list;
708 std::sort(active_display_list_.begin(), active_display_list_.end(),
709 DisplaySortFunctor());
710 std::sort(new_display_info_list.begin(),
711 new_display_info_list.end(),
712 DisplayInfoSortFunctor());
714 if (multi_display_mode_ != MIRRORING)
715 multi_display_mode_ = default_multi_display_mode_;
717 CreateSoftwareMirroringDisplayInfo(&new_display_info_list);
719 // Close the mirroring window if any here to avoid creating two compositor on
720 // one display.
721 if (delegate_)
722 delegate_->CloseMirroringDisplayIfNotNecessary();
724 DisplayList new_displays;
725 DisplayList removed_displays;
726 std::map<size_t, uint32_t> display_changes;
727 std::vector<size_t> added_display_indices;
729 DisplayList::iterator curr_iter = active_display_list_.begin();
730 DisplayInfoList::const_iterator new_info_iter = new_display_info_list.begin();
732 while (curr_iter != active_display_list_.end() ||
733 new_info_iter != new_display_info_list.end()) {
734 if (curr_iter == active_display_list_.end()) {
735 // more displays in new list.
736 added_display_indices.push_back(new_displays.size());
737 InsertAndUpdateDisplayInfo(*new_info_iter);
738 new_displays.push_back(
739 CreateDisplayFromDisplayInfoById(new_info_iter->id()));
740 ++new_info_iter;
741 } else if (new_info_iter == new_display_info_list.end()) {
742 // more displays in current list.
743 removed_displays.push_back(*curr_iter);
744 ++curr_iter;
745 } else if (curr_iter->id() == new_info_iter->id()) {
746 const gfx::Display& current_display = *curr_iter;
747 // Copy the info because |CreateDisplayFromInfo| updates the instance.
748 const DisplayInfo current_display_info =
749 GetDisplayInfo(current_display.id());
750 InsertAndUpdateDisplayInfo(*new_info_iter);
751 gfx::Display new_display =
752 CreateDisplayFromDisplayInfoById(new_info_iter->id());
753 const DisplayInfo& new_display_info = GetDisplayInfo(new_display.id());
755 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_NONE;
757 // At that point the new Display objects we have are not entirely updated,
758 // they are missing the translation related to the Display disposition in
759 // the layout.
760 // Using display.bounds() and display.work_area() would fail most of the
761 // time.
762 if (force_bounds_changed_ ||
763 (current_display_info.bounds_in_native() !=
764 new_display_info.bounds_in_native()) ||
765 (current_display_info.GetOverscanInsetsInPixel() !=
766 new_display_info.GetOverscanInsetsInPixel()) ||
767 current_display.size() != new_display.size()) {
768 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
769 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
772 if (current_display.device_scale_factor() !=
773 new_display.device_scale_factor()) {
774 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
777 if (current_display.rotation() != new_display.rotation())
778 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_ROTATION;
780 if (metrics != gfx::DisplayObserver::DISPLAY_METRIC_NONE) {
781 display_changes.insert(
782 std::pair<size_t, uint32_t>(new_displays.size(), metrics));
785 new_display.UpdateWorkAreaFromInsets(current_display.GetWorkAreaInsets());
786 new_displays.push_back(new_display);
787 ++curr_iter;
788 ++new_info_iter;
789 } else if (curr_iter->id() < new_info_iter->id()) {
790 // more displays in current list between ids, which means it is deleted.
791 removed_displays.push_back(*curr_iter);
792 ++curr_iter;
793 } else {
794 // more displays in new list between ids, which means it is added.
795 added_display_indices.push_back(new_displays.size());
796 InsertAndUpdateDisplayInfo(*new_info_iter);
797 new_displays.push_back(
798 CreateDisplayFromDisplayInfoById(new_info_iter->id()));
799 ++new_info_iter;
802 gfx::Display old_primary;
803 if (delegate_)
804 old_primary = screen_->GetPrimaryDisplay();
806 // Clear focus if the display has been removed, but don't clear focus if
807 // the destkop has been moved from one display to another
808 // (mirror -> docked, docked -> single internal).
809 bool clear_focus =
810 !removed_displays.empty() &&
811 !(removed_displays.size() == 1 && added_display_indices.size() == 1);
812 if (delegate_)
813 delegate_->PreDisplayConfigurationChange(clear_focus);
815 std::vector<size_t> updated_indices;
816 if (UpdateNonPrimaryDisplayBoundsForLayout(&new_displays, &updated_indices)) {
817 for (std::vector<size_t>::iterator it = updated_indices.begin();
818 it != updated_indices.end(); ++it) {
819 size_t updated_index = *it;
820 if (std::find(added_display_indices.begin(),
821 added_display_indices.end(),
822 updated_index) == added_display_indices.end()) {
823 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
824 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
825 if (display_changes.find(updated_index) != display_changes.end())
826 metrics |= display_changes[updated_index];
828 display_changes[updated_index] = metrics;
833 active_display_list_ = new_displays;
835 RefreshFontParams();
836 base::AutoReset<bool> resetter(&change_display_upon_host_resize_, false);
838 int active_display_list_size = active_display_list_.size();
839 // Temporarily add displays to be removed because display object
840 // being removed are accessed during shutting down the root.
841 active_display_list_.insert(active_display_list_.end(),
842 removed_displays.begin(), removed_displays.end());
844 for (const auto& display : removed_displays)
845 screen_->NotifyDisplayRemoved(display);
847 for (size_t index : added_display_indices)
848 screen_->NotifyDisplayAdded(active_display_list_[index]);
850 active_display_list_.resize(active_display_list_size);
852 bool notify_primary_change =
853 delegate_ ? old_primary.id() != screen_->GetPrimaryDisplay().id() : false;
855 for (std::map<size_t, uint32_t>::iterator iter = display_changes.begin();
856 iter != display_changes.end();
857 ++iter) {
858 uint32_t metrics = iter->second;
859 const gfx::Display& updated_display = active_display_list_[iter->first];
861 if (notify_primary_change &&
862 updated_display.id() == screen_->GetPrimaryDisplay().id()) {
863 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_PRIMARY;
864 notify_primary_change = false;
866 screen_->NotifyMetricsChanged(updated_display, metrics);
869 if (notify_primary_change) {
870 // This happens when a primary display has moved to anther display without
871 // bounds change.
872 const gfx::Display& primary = screen_->GetPrimaryDisplay();
873 if (primary.id() != old_primary.id()) {
874 uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_PRIMARY;
875 if (primary.size() != old_primary.size()) {
876 metrics |= (gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
877 gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
879 if (primary.device_scale_factor() != old_primary.device_scale_factor())
880 metrics |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
882 screen_->NotifyMetricsChanged(primary, metrics);
886 if (delegate_)
887 delegate_->PostDisplayConfigurationChange();
889 #if defined(USE_X11) && defined(OS_CHROMEOS)
890 if (!display_changes.empty() && base::SysInfo::IsRunningOnChromeOS())
891 ui::ClearX11DefaultRootWindow();
892 #endif
894 // Create the mirroring window asynchronously after all displays
895 // are added so that it can mirror the display newly added. This can
896 // happen when switching from dock mode to software mirror mode.
897 CreateMirrorWindowAsyncIfAny();
900 const gfx::Display& DisplayManager::GetDisplayAt(size_t index) const {
901 DCHECK_LT(index, active_display_list_.size());
902 return active_display_list_[index];
905 const gfx::Display& DisplayManager::GetPrimaryDisplayCandidate() const {
906 if (GetNumDisplays() != 2)
907 return active_display_list_[0];
908 DisplayLayout layout = layout_store_->GetRegisteredDisplayLayout(
909 GetCurrentDisplayIdPair());
910 return GetDisplayForId(layout.primary_id);
913 size_t DisplayManager::GetNumDisplays() const {
914 return active_display_list_.size();
917 bool DisplayManager::IsInMirrorMode() const {
918 return mirroring_display_id_ != gfx::Display::kInvalidDisplayID;
921 bool DisplayManager::IsInUnifiedMode() const {
922 return multi_display_mode_ == UNIFIED &&
923 !software_mirroring_display_list_.empty();
926 const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const {
927 DCHECK_NE(gfx::Display::kInvalidDisplayID, display_id);
929 std::map<int64, DisplayInfo>::const_iterator iter =
930 display_info_.find(display_id);
931 CHECK(iter != display_info_.end()) << display_id;
932 return iter->second;
935 const gfx::Display DisplayManager::GetMirroringDisplayById(
936 int64 display_id) const {
937 auto iter = std::find_if(software_mirroring_display_list_.begin(),
938 software_mirroring_display_list_.end(),
939 [display_id](const gfx::Display& display) {
940 return display.id() == display_id;
942 return iter == software_mirroring_display_list_.end() ? gfx::Display()
943 : *iter;
946 std::string DisplayManager::GetDisplayNameForId(int64 id) {
947 if (id == gfx::Display::kInvalidDisplayID)
948 return l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME);
950 std::map<int64, DisplayInfo>::const_iterator iter = display_info_.find(id);
951 if (iter != display_info_.end() && !iter->second.name().empty())
952 return iter->second.name();
954 return base::StringPrintf("Display %d", static_cast<int>(id));
957 int64 DisplayManager::GetDisplayIdForUIScaling() const {
958 // UI Scaling is effective only on internal display.
959 int64 display_id = gfx::Display::InternalDisplayId();
960 #if defined(OS_WIN)
961 display_id = first_display_id();
962 #endif
963 return display_id;
966 void DisplayManager::SetMirrorMode(bool mirror) {
967 #if defined(OS_CHROMEOS)
968 if (num_connected_displays() <= 1)
969 return;
971 if (base::SysInfo::IsRunningOnChromeOS()) {
972 ui::MultipleDisplayState new_state =
973 mirror ? ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR
974 : ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
975 Shell::GetInstance()->display_configurator()->SetDisplayMode(new_state);
976 return;
979 // This is fallback path to emulate mirroroing on desktop and unit test.
980 DisplayInfoList display_info_list;
981 for (DisplayList::const_iterator iter = active_display_list_.begin();
982 (display_info_list.size() < 2 && iter != active_display_list_.end());
983 ++iter) {
984 if (iter->id() == kUnifiedDisplayId)
985 continue;
986 display_info_list.push_back(GetDisplayInfo(iter->id()));
988 for (auto iter = software_mirroring_display_list_.begin();
989 (display_info_list.size() < 2 &&
990 iter != software_mirroring_display_list_.end());
991 ++iter) {
992 display_info_list.push_back(GetDisplayInfo(iter->id()));
994 multi_display_mode_ = mirror ? MIRRORING : default_multi_display_mode_;
995 ReconfigureDisplays();
996 if (Shell::GetInstance()->display_configurator_animation()) {
997 Shell::GetInstance()->display_configurator_animation()->
998 StartFadeInAnimation();
1000 RunPendingTasksForTest();
1001 #endif
1004 void DisplayManager::AddRemoveDisplay() {
1005 DCHECK(!active_display_list_.empty());
1006 std::vector<DisplayInfo> new_display_info_list;
1007 const DisplayInfo& first_display =
1008 IsInUnifiedMode()
1009 ? GetDisplayInfo(software_mirroring_display_list_[0].id())
1010 : GetDisplayInfo(active_display_list_[0].id());
1011 new_display_info_list.push_back(first_display);
1012 // Add if there is only one display connected.
1013 if (num_connected_displays() == 1) {
1014 const int kVerticalOffsetPx = 100;
1015 // Layout the 2nd display below the primary as with the real device.
1016 gfx::Rect host_bounds = first_display.bounds_in_native();
1017 new_display_info_list.push_back(
1018 DisplayInfo::CreateFromSpec(base::StringPrintf(
1019 "%d+%d-600x%d", host_bounds.x(),
1020 host_bounds.bottom() + kVerticalOffsetPx, host_bounds.height())));
1022 num_connected_displays_ = new_display_info_list.size();
1023 mirroring_display_id_ = gfx::Display::kInvalidDisplayID;
1024 software_mirroring_display_list_.clear();
1025 UpdateDisplays(new_display_info_list);
1028 void DisplayManager::ToggleDisplayScaleFactor() {
1029 DCHECK(!active_display_list_.empty());
1030 std::vector<DisplayInfo> new_display_info_list;
1031 for (DisplayList::const_iterator iter = active_display_list_.begin();
1032 iter != active_display_list_.end(); ++iter) {
1033 DisplayInfo display_info = GetDisplayInfo(iter->id());
1034 display_info.set_device_scale_factor(
1035 display_info.device_scale_factor() == 1.0f ? 2.0f : 1.0f);
1036 new_display_info_list.push_back(display_info);
1038 AddMirrorDisplayInfoIfAny(&new_display_info_list);
1039 UpdateDisplays(new_display_info_list);
1042 #if defined(OS_CHROMEOS)
1043 void DisplayManager::SetSoftwareMirroring(bool enabled) {
1044 SetMultiDisplayMode(enabled ? MIRRORING : default_multi_display_mode_);
1047 bool DisplayManager::SoftwareMirroringEnabled() const {
1048 return software_mirroring_enabled();
1050 #endif
1052 void DisplayManager::SetMultiDisplayMode(MultiDisplayMode mode) {
1053 multi_display_mode_ = mode;
1054 mirroring_display_id_ = gfx::Display::kInvalidDisplayID;
1055 software_mirroring_display_list_.clear();
1058 void DisplayManager::SetDefaultMultiDisplayMode(MultiDisplayMode mode) {
1059 DCHECK_NE(mode, MIRRORING);
1060 default_multi_display_mode_ = mode;
1063 void DisplayManager::ReconfigureDisplays() {
1064 DisplayInfoList display_info_list;
1065 for (DisplayList::const_iterator iter = active_display_list_.begin();
1066 (display_info_list.size() < 2 && iter != active_display_list_.end());
1067 ++iter) {
1068 if (iter->id() == kUnifiedDisplayId)
1069 continue;
1070 display_info_list.push_back(GetDisplayInfo(iter->id()));
1072 for (auto iter = software_mirroring_display_list_.begin();
1073 (display_info_list.size() < 2 &&
1074 iter != software_mirroring_display_list_.end());
1075 ++iter) {
1076 display_info_list.push_back(GetDisplayInfo(iter->id()));
1078 mirroring_display_id_ = gfx::Display::kInvalidDisplayID;
1079 software_mirroring_display_list_.clear();
1080 UpdateDisplays(display_info_list);
1083 bool DisplayManager::UpdateDisplayBounds(int64 display_id,
1084 const gfx::Rect& new_bounds) {
1085 if (change_display_upon_host_resize_) {
1086 display_info_[display_id].SetBounds(new_bounds);
1087 // Don't notify observers if the mirrored window has changed.
1088 if (software_mirroring_enabled() && mirroring_display_id_ == display_id)
1089 return false;
1090 gfx::Display* display = FindDisplayForId(display_id);
1091 display->SetSize(display_info_[display_id].size_in_pixel());
1092 screen_->NotifyMetricsChanged(*display,
1093 gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS);
1094 return true;
1096 return false;
1099 void DisplayManager::CreateMirrorWindowAsyncIfAny() {
1100 // Do not post a task if the software mirroring doesn't exist, or
1101 // during initialization when compositor's init task isn't posted yet.
1102 // ash::Shell::Init() will call this after the compositor is initialized.
1103 if (software_mirroring_display_list_.empty() || !delegate_)
1104 return;
1105 base::MessageLoopForUI::current()->PostTask(
1106 FROM_HERE,
1107 base::Bind(&DisplayManager::CreateMirrorWindowIfAny,
1108 weak_ptr_factory_.GetWeakPtr()));
1111 scoped_ptr<MouseWarpController> DisplayManager::CreateMouseWarpController(
1112 aura::Window* drag_source) const {
1113 if (IsInUnifiedMode() && num_connected_displays() >= 2)
1114 return make_scoped_ptr(new UnifiedMouseWarpController());
1115 // Extra check for |num_connected_displays()| is for SystemDisplayApiTest
1116 // that injects MockScreen.
1117 if (GetNumDisplays() < 2 || num_connected_displays() < 2)
1118 return make_scoped_ptr(new NullMouseWarpController());
1119 return make_scoped_ptr(new ExtendedMouseWarpController(drag_source));
1122 void DisplayManager::CreateScreenForShutdown() const {
1123 bool native_is_ash =
1124 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE) == screen_.get();
1125 delete screen_for_shutdown;
1126 screen_for_shutdown = screen_->CloneForShutdown();
1127 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE,
1128 screen_for_shutdown);
1129 if (native_is_ash) {
1130 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE,
1131 screen_for_shutdown);
1135 void DisplayManager::UpdateInternalDisplayModeListForTest() {
1136 if (display_info_.count(gfx::Display::InternalDisplayId()) == 0)
1137 return;
1138 DisplayInfo* info = &display_info_[gfx::Display::InternalDisplayId()];
1139 SetInternalDisplayModeList(info);
1142 void DisplayManager::CreateSoftwareMirroringDisplayInfo(
1143 DisplayInfoList* display_info_list) {
1144 // Use the internal display or 1st as the mirror source, then scale
1145 // the root window so that it matches the external display's
1146 // resolution. This is necessary in order for scaling to work while
1147 // mirrored.
1148 if (display_info_list->size() == 2) {
1149 switch (multi_display_mode_) {
1150 case MIRRORING: {
1151 bool zero_is_source =
1152 first_display_id_ == (*display_info_list)[0].id() ||
1153 gfx::Display::InternalDisplayId() == (*display_info_list)[0].id();
1154 DCHECK_EQ(MIRRORING, multi_display_mode_);
1155 mirroring_display_id_ =
1156 (*display_info_list)[zero_is_source ? 1 : 0].id();
1158 int64 display_id = mirroring_display_id_;
1159 auto iter =
1160 std::find_if(display_info_list->begin(), display_info_list->end(),
1161 [display_id](const DisplayInfo& info) {
1162 return info.id() == display_id;
1164 DCHECK(iter != display_info_list->end());
1166 DisplayInfo info = *iter;
1167 info.SetOverscanInsets(gfx::Insets());
1168 InsertAndUpdateDisplayInfo(info);
1169 software_mirroring_display_list_.push_back(
1170 CreateDisplayFromDisplayInfoById(mirroring_display_id_));
1171 display_info_list->erase(iter);
1172 break;
1174 case UNIFIED: {
1175 // TODO(oshima): Suport displays that have different heights.
1176 // TODO(oshima): Currently, all displays are laid out horizontally,
1177 // from left to right. Allow more flexible layouts, such as
1178 // right to left, or vertical layouts.
1179 gfx::Rect unified_bounds;
1180 software_mirroring_display_list_.clear();
1181 for (auto& info : *display_info_list) {
1182 InsertAndUpdateDisplayInfo(info);
1183 gfx::Display display = CreateDisplayFromDisplayInfoById(info.id());
1184 gfx::Point origin(unified_bounds.right(), 0);
1185 display.set_bounds(gfx::Rect(origin, info.size_in_pixel()));
1186 display.UpdateWorkAreaFromInsets(gfx::Insets());
1187 unified_bounds.Union(display.bounds());
1188 software_mirroring_display_list_.push_back(display);
1190 DisplayInfo info(kUnifiedDisplayId, "Unified Desktop", false);
1191 info.SetBounds(unified_bounds);
1192 display_info_list->clear();
1193 display_info_list->push_back(info);
1194 break;
1196 case EXTENDED:
1197 break;
1202 gfx::Display* DisplayManager::FindDisplayForId(int64 id) {
1203 auto iter = std::find_if(
1204 active_display_list_.begin(), active_display_list_.end(),
1205 [id](const gfx::Display& display) { return display.id() == id; });
1206 if (iter != active_display_list_.end())
1207 return &(*iter);
1208 // TODO(oshima): This happens when a windows in unified desktop have
1209 // been moved to normal window. Fix this.
1210 if (id != kUnifiedDisplayId)
1211 DLOG(WARNING) << "Could not find display:" << id;
1212 return NULL;
1215 void DisplayManager::AddMirrorDisplayInfoIfAny(
1216 std::vector<DisplayInfo>* display_info_list) {
1217 if (software_mirroring_enabled() && IsInMirrorMode())
1218 display_info_list->push_back(GetDisplayInfo(mirroring_display_id_));
1221 void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo& new_info) {
1222 std::map<int64, DisplayInfo>::iterator info =
1223 display_info_.find(new_info.id());
1224 if (info != display_info_.end()) {
1225 info->second.Copy(new_info);
1226 } else {
1227 display_info_[new_info.id()] = new_info;
1228 display_info_[new_info.id()].set_native(false);
1230 display_info_[new_info.id()].UpdateDisplaySize();
1231 OnDisplayInfoUpdated(display_info_[new_info.id()]);
1234 void DisplayManager::OnDisplayInfoUpdated(const DisplayInfo& display_info) {
1235 #if defined(OS_CHROMEOS)
1236 ui::ColorCalibrationProfile color_profile = display_info.color_profile();
1237 if (color_profile != ui::COLOR_PROFILE_STANDARD) {
1238 Shell::GetInstance()->display_configurator()->SetColorCalibrationProfile(
1239 display_info.id(), color_profile);
1241 #endif
1244 gfx::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64 id) {
1245 DCHECK(display_info_.find(id) != display_info_.end()) << "id=" << id;
1246 const DisplayInfo& display_info = display_info_[id];
1248 gfx::Display new_display(display_info.id());
1249 gfx::Rect bounds_in_native(display_info.size_in_pixel());
1250 float device_scale_factor = display_info.GetEffectiveDeviceScaleFactor();
1252 // Simply set the origin to (0,0). The primary display's origin is
1253 // always (0,0) and the bounds of non-primary display(s) will be updated
1254 // in |UpdateNonPrimaryDisplayBoundsForLayout| called in |UpdateDisplay|.
1255 new_display.SetScaleAndBounds(
1256 device_scale_factor, gfx::Rect(bounds_in_native.size()));
1257 new_display.set_rotation(display_info.GetActiveRotation());
1258 new_display.set_touch_support(display_info.touch_support());
1259 return new_display;
1262 bool DisplayManager::UpdateNonPrimaryDisplayBoundsForLayout(
1263 DisplayList* displays,
1264 std::vector<size_t>* updated_indices) const {
1266 if (displays->size() < 2U)
1267 return false;
1269 if (displays->size() > 2U) {
1270 // For more than 2 displays, always use horizontal layout.
1271 int x_offset = displays->at(0).bounds().width();
1272 for (size_t i = 1; i < displays->size(); ++i) {
1273 gfx::Display& display = displays->at(i);
1274 const gfx::Rect& bounds = display.bounds();
1275 gfx::Point origin = gfx::Point(x_offset, 0);
1276 gfx::Insets insets = display.GetWorkAreaInsets();
1277 display.set_bounds(gfx::Rect(origin, bounds.size()));
1278 display.UpdateWorkAreaFromInsets(insets);
1279 x_offset += bounds.width();
1280 updated_indices->push_back(i);
1282 return true;
1285 int64 id_at_zero = displays->at(0).id();
1286 DisplayIdPair pair =
1287 (id_at_zero == first_display_id_ ||
1288 id_at_zero == gfx::Display::InternalDisplayId()) ?
1289 std::make_pair(id_at_zero, displays->at(1).id()) :
1290 std::make_pair(displays->at(1).id(), id_at_zero);
1291 DisplayLayout layout =
1292 layout_store_->ComputeDisplayLayoutForDisplayIdPair(pair);
1294 // Ignore if a user has a old format (should be extremely rare)
1295 // and this will be replaced with DCHECK.
1296 if (layout.primary_id != gfx::Display::kInvalidDisplayID) {
1297 size_t primary_index, secondary_index;
1298 if (displays->at(0).id() == layout.primary_id) {
1299 primary_index = 0;
1300 secondary_index = 1;
1301 } else {
1302 primary_index = 1;
1303 secondary_index = 0;
1305 // This function may be called before the secondary display is
1306 // registered. The bounds is empty in that case and will
1307 // return true.
1308 gfx::Rect bounds =
1309 GetDisplayForId(displays->at(secondary_index).id()).bounds();
1310 UpdateDisplayBoundsForLayout(
1311 layout, displays->at(primary_index), &displays->at(secondary_index));
1312 updated_indices->push_back(secondary_index);
1313 return bounds != displays->at(secondary_index).bounds();
1315 return false;
1318 void DisplayManager::CreateMirrorWindowIfAny() {
1319 if (software_mirroring_display_list_.empty() || !delegate_)
1320 return;
1321 DisplayInfoList list;
1322 for (auto& display : software_mirroring_display_list_)
1323 list.push_back(GetDisplayInfo(display.id()));
1324 delegate_->CreateOrUpdateMirroringDisplay(list);
1327 // static
1328 void DisplayManager::UpdateDisplayBoundsForLayout(
1329 const DisplayLayout& layout,
1330 const gfx::Display& primary_display,
1331 gfx::Display* secondary_display) {
1332 DCHECK_EQ("0,0", primary_display.bounds().origin().ToString());
1334 const gfx::Rect& primary_bounds = primary_display.bounds();
1335 const gfx::Rect& secondary_bounds = secondary_display->bounds();
1336 gfx::Point new_secondary_origin = primary_bounds.origin();
1338 DisplayLayout::Position position = layout.position;
1340 // Ignore the offset in case the secondary display doesn't share edges with
1341 // the primary display.
1342 int offset = layout.offset;
1343 if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM) {
1344 offset = std::min(
1345 offset, primary_bounds.width() - kMinimumOverlapForInvalidOffset);
1346 offset = std::max(
1347 offset, -secondary_bounds.width() + kMinimumOverlapForInvalidOffset);
1348 } else {
1349 offset = std::min(
1350 offset, primary_bounds.height() - kMinimumOverlapForInvalidOffset);
1351 offset = std::max(
1352 offset, -secondary_bounds.height() + kMinimumOverlapForInvalidOffset);
1354 switch (position) {
1355 case DisplayLayout::TOP:
1356 new_secondary_origin.Offset(offset, -secondary_bounds.height());
1357 break;
1358 case DisplayLayout::RIGHT:
1359 new_secondary_origin.Offset(primary_bounds.width(), offset);
1360 break;
1361 case DisplayLayout::BOTTOM:
1362 new_secondary_origin.Offset(offset, primary_bounds.height());
1363 break;
1364 case DisplayLayout::LEFT:
1365 new_secondary_origin.Offset(-secondary_bounds.width(), offset);
1366 break;
1368 gfx::Insets insets = secondary_display->GetWorkAreaInsets();
1369 secondary_display->set_bounds(
1370 gfx::Rect(new_secondary_origin, secondary_bounds.size()));
1371 secondary_display->UpdateWorkAreaFromInsets(insets);
1374 void DisplayManager::RunPendingTasksForTest() {
1375 if (!software_mirroring_display_list_.empty())
1376 base::RunLoop().RunUntilIdle();
1379 } // namespace ash