Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: ash/display/display_manager.cc

Issue 2445583002: Relocate display_manager from ash to ui (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "ash/display/display_manager.h"
6
7 #include <algorithm>
8 #include <cmath>
9 #include <limits>
10 #include <map>
11 #include <set>
12 #include <string>
13 #include <utility>
14 #include <vector>
15
16 #include "base/auto_reset.h"
17 #include "base/bind.h"
18 #include "base/command_line.h"
19 #include "base/logging.h"
20 #include "base/memory/ptr_util.h"
21 #include "base/metrics/histogram.h"
22 #include "base/run_loop.h"
23 #include "base/strings/string_number_conversions.h"
24 #include "base/strings/string_split.h"
25 #include "base/strings/stringprintf.h"
26 #include "base/strings/utf_string_conversions.h"
27 #include "base/threading/thread_task_runner_handle.h"
28 #include "ui/display/display.h"
29 #include "ui/display/display_observer.h"
30 #include "ui/display/display_switches.h"
31 #include "ui/display/manager/display_layout_store.h"
32 #include "ui/display/manager/display_manager_utilities.h"
33 #include "ui/display/manager/managed_display_info.h"
34 #include "ui/display/screen.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
39 #if defined(USE_X11)
40 #include "ui/base/x/x11_util.h" // nogncheck
41 #endif
42
43 #if defined(OS_CHROMEOS)
44 #include "base/sys_info.h"
45 #endif
46
47 #if defined(OS_WIN)
48 #include "base/win/windows_version.h"
49 #endif
50
51 namespace ash {
52
53 namespace {
54
55 // The number of pixels to overlap between the primary and secondary displays,
56 // in case that the offset value is too large.
57 const int kMinimumOverlapForInvalidOffset = 100;
58
59 struct DisplaySortFunctor {
60 bool operator()(const display::Display& a, const display::Display& b) {
61 return display::CompareDisplayIds(a.id(), b.id());
62 }
63 };
64
65 struct DisplayInfoSortFunctor {
66 bool operator()(const display::ManagedDisplayInfo& a,
67 const display::ManagedDisplayInfo& b) {
68 return display::CompareDisplayIds(a.id(), b.id());
69 }
70 };
71
72 display::Display& GetInvalidDisplay() {
73 static display::Display* invalid_display = new display::Display();
74 return *invalid_display;
75 }
76
77 display::ManagedDisplayInfo::ManagedDisplayModeList::const_iterator
78 FindDisplayMode(const display::ManagedDisplayInfo& info,
79 const scoped_refptr<display::ManagedDisplayMode>& target_mode) {
80 const display::ManagedDisplayInfo::ManagedDisplayModeList& modes =
81 info.display_modes();
82 return std::find_if(
83 modes.begin(), modes.end(),
84 [target_mode](const scoped_refptr<display::ManagedDisplayMode>& mode) {
85 return target_mode->IsEquivalent(mode);
86 });
87 }
88
89 void SetInternalManagedDisplayModeList(display::ManagedDisplayInfo* info) {
90 scoped_refptr<display::ManagedDisplayMode> native_mode =
91 new display::ManagedDisplayMode(
92 info->bounds_in_native().size(), 0.0 /* refresh_rate */,
93 false /* interlaced */, false /* native_mode */, 1.0 /* ui_scale */,
94 info->device_scale_factor());
95 info->SetManagedDisplayModes(
96 display::CreateInternalManagedDisplayModeList(native_mode));
97 }
98
99 void MaybeInitInternalDisplay(display::ManagedDisplayInfo* info) {
100 int64_t id = info->id();
101 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
102 if (command_line->HasSwitch(::switches::kUseFirstDisplayAsInternal)) {
103 display::Display::SetInternalDisplayId(id);
104 SetInternalManagedDisplayModeList(info);
105 }
106 }
107
108 gfx::Size GetMaxNativeSize(const display::ManagedDisplayInfo& info) {
109 gfx::Size size;
110 for (auto& mode : info.display_modes()) {
111 if (mode->size().GetArea() > size.GetArea())
112 size = mode->size();
113 }
114 return size;
115 }
116
117 scoped_refptr<display::ManagedDisplayMode> GetDisplayModeForUIScale(
118 const display::ManagedDisplayInfo& info,
119 float ui_scale) {
120 const display::ManagedDisplayInfo::ManagedDisplayModeList& modes =
121 info.display_modes();
122 auto iter = std::find_if(
123 modes.begin(), modes.end(),
124 [ui_scale](const scoped_refptr<display::ManagedDisplayMode>& mode) {
125 return mode->ui_scale() == ui_scale;
126 });
127 if (iter == modes.end())
128 return scoped_refptr<display::ManagedDisplayMode>();
129 return *iter;
130 }
131
132 } // namespace
133
134 using std::string;
135 using std::vector;
136
137 // static
138 int64_t DisplayManager::kUnifiedDisplayId = -10;
139
140 DisplayManager::DisplayManager(std::unique_ptr<display::Screen> screen)
141 : delegate_(nullptr),
142 screen_(std::move(screen)),
143 layout_store_(new display::DisplayLayoutStore),
144 first_display_id_(display::Display::kInvalidDisplayID),
145 num_connected_displays_(0),
146 force_bounds_changed_(false),
147 change_display_upon_host_resize_(false),
148 multi_display_mode_(EXTENDED),
149 current_default_multi_display_mode_(EXTENDED),
150 mirroring_display_id_(display::Display::kInvalidDisplayID),
151 registered_internal_display_rotation_lock_(false),
152 registered_internal_display_rotation_(display::Display::ROTATE_0),
153 unified_desktop_enabled_(false),
154 weak_ptr_factory_(this) {
155 #if defined(OS_CHROMEOS)
156 change_display_upon_host_resize_ = !base::SysInfo::IsRunningOnChromeOS();
157 unified_desktop_enabled_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
158 ::switches::kEnableUnifiedDesktop);
159 #endif
160 }
161
162 DisplayManager::~DisplayManager() {
163 #if defined(OS_CHROMEOS)
164 // Reset the font params.
165 gfx::SetFontRenderParamsDeviceScaleFactor(1.0f);
166 #endif
167 }
168
169 bool DisplayManager::InitFromCommandLine() {
170 DisplayInfoList info_list;
171 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
172 if (!command_line->HasSwitch(::switches::kHostWindowBounds))
173 return false;
174 const string size_str =
175 command_line->GetSwitchValueASCII(::switches::kHostWindowBounds);
176 for (const std::string& part : base::SplitString(
177 size_str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
178 info_list.push_back(display::ManagedDisplayInfo::CreateFromSpec(part));
179 info_list.back().set_native(true);
180 }
181 MaybeInitInternalDisplay(&info_list[0]);
182 if (info_list.size() > 1 &&
183 command_line->HasSwitch(::switches::kEnableSoftwareMirroring)) {
184 SetMultiDisplayMode(MIRRORING);
185 }
186 OnNativeDisplaysChanged(info_list);
187 return true;
188 }
189
190 void DisplayManager::InitDefaultDisplay() {
191 DisplayInfoList info_list;
192 info_list.push_back(
193 display::ManagedDisplayInfo::CreateFromSpec(std::string()));
194 info_list.back().set_native(true);
195 MaybeInitInternalDisplay(&info_list[0]);
196 OnNativeDisplaysChanged(info_list);
197 }
198
199 void DisplayManager::RefreshFontParams() {
200 #if defined(OS_CHROMEOS)
201 // Use the largest device scale factor among currently active displays. Non
202 // internal display may have bigger scale factor in case the external display
203 // is an 4K display.
204 float largest_device_scale_factor = 1.0f;
205 for (const display::Display& display : active_display_list_) {
206 const display::ManagedDisplayInfo& info = display_info_[display.id()];
207 largest_device_scale_factor = std::max(
208 largest_device_scale_factor, info.GetEffectiveDeviceScaleFactor());
209 }
210 gfx::SetFontRenderParamsDeviceScaleFactor(largest_device_scale_factor);
211 #endif // OS_CHROMEOS
212 }
213
214 const display::DisplayLayout& DisplayManager::GetCurrentDisplayLayout() const {
215 DCHECK_LE(2U, num_connected_displays());
216 if (num_connected_displays() > 1) {
217 display::DisplayIdList list = GetCurrentDisplayIdList();
218 return layout_store_->GetRegisteredDisplayLayout(list);
219 }
220 LOG(ERROR) << "DisplayLayout is requested for single display";
221 // On release build, just fallback to default instead of blowing up.
222 static display::DisplayLayout layout;
223 layout.primary_id = active_display_list_[0].id();
224 return layout;
225 }
226
227 display::DisplayIdList DisplayManager::GetCurrentDisplayIdList() const {
228 if (IsInUnifiedMode()) {
229 return display::CreateDisplayIdList(software_mirroring_display_list_);
230 } else if (IsInMirrorMode()) {
231 if (software_mirroring_enabled()) {
232 CHECK_EQ(2u, num_connected_displays());
233 // This comment is to make it easy to distinguish the crash
234 // between two checks.
235 CHECK_EQ(1u, active_display_list_.size());
236 }
237 int64_t ids[] = {active_display_list_[0].id(), mirroring_display_id_};
238 return display::GenerateDisplayIdList(std::begin(ids), std::end(ids));
239 } else {
240 CHECK_LE(2u, active_display_list_.size());
241 return display::CreateDisplayIdList(active_display_list_);
242 }
243 }
244
245 void DisplayManager::SetLayoutForCurrentDisplays(
246 std::unique_ptr<display::DisplayLayout> layout) {
247 if (GetNumDisplays() == 1)
248 return;
249 const display::DisplayIdList list = GetCurrentDisplayIdList();
250
251 DCHECK(display::DisplayLayout::Validate(list, *layout));
252
253 const display::DisplayLayout& current_layout =
254 layout_store_->GetRegisteredDisplayLayout(list);
255
256 if (layout->HasSamePlacementList(current_layout))
257 return;
258
259 layout_store_->RegisterLayoutForDisplayIdList(list, std::move(layout));
260 if (delegate_)
261 delegate_->PreDisplayConfigurationChange(false);
262
263 // TODO(oshima): Call UpdateDisplays instead.
264 std::vector<int64_t> updated_ids;
265 ApplyDisplayLayout(GetCurrentDisplayLayout(), &active_display_list_,
266 &updated_ids);
267 for (int64_t id : updated_ids) {
268 NotifyMetricsChanged(
269 GetDisplayForId(id),
270 display::DisplayObserver::DISPLAY_METRIC_BOUNDS |
271 display::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
272 }
273
274 if (delegate_)
275 delegate_->PostDisplayConfigurationChange();
276 }
277
278 const display::Display& DisplayManager::GetDisplayForId(int64_t id) const {
279 display::Display* display =
280 const_cast<DisplayManager*>(this)->FindDisplayForId(id);
281 return display ? *display : GetInvalidDisplay();
282 }
283
284 const display::Display& DisplayManager::FindDisplayContainingPoint(
285 const gfx::Point& point_in_screen) const {
286 int index = display::FindDisplayIndexContainingPoint(active_display_list_,
287 point_in_screen);
288 return index < 0 ? GetInvalidDisplay() : active_display_list_[index];
289 }
290
291 bool DisplayManager::UpdateWorkAreaOfDisplay(int64_t display_id,
292 const gfx::Insets& insets) {
293 display::Display* display = FindDisplayForId(display_id);
294 DCHECK(display);
295 gfx::Rect old_work_area = display->work_area();
296 display->UpdateWorkAreaFromInsets(insets);
297 bool workarea_changed = old_work_area != display->work_area();
298 if (workarea_changed) {
299 NotifyMetricsChanged(*display,
300 display::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
301 }
302 return workarea_changed;
303 }
304
305 void DisplayManager::SetOverscanInsets(int64_t display_id,
306 const gfx::Insets& insets_in_dip) {
307 bool update = false;
308 DisplayInfoList display_info_list;
309 for (const auto& display : active_display_list_) {
310 display::ManagedDisplayInfo info = GetDisplayInfo(display.id());
311 if (info.id() == display_id) {
312 if (insets_in_dip.IsEmpty()) {
313 info.set_clear_overscan_insets(true);
314 } else {
315 info.set_clear_overscan_insets(false);
316 info.SetOverscanInsets(insets_in_dip);
317 }
318 update = true;
319 }
320 display_info_list.push_back(info);
321 }
322 if (update) {
323 AddMirrorDisplayInfoIfAny(&display_info_list);
324 UpdateDisplaysWith(display_info_list);
325 } else {
326 display_info_[display_id].SetOverscanInsets(insets_in_dip);
327 }
328 }
329
330 void DisplayManager::SetDisplayRotation(
331 int64_t display_id,
332 display::Display::Rotation rotation,
333 display::Display::RotationSource source) {
334 if (IsInUnifiedMode())
335 return;
336
337 DisplayInfoList display_info_list;
338 bool is_active = false;
339 for (const auto& display : active_display_list_) {
340 display::ManagedDisplayInfo info = GetDisplayInfo(display.id());
341 if (info.id() == display_id) {
342 if (info.GetRotation(source) == rotation &&
343 info.GetActiveRotation() == rotation) {
344 return;
345 }
346 info.SetRotation(rotation, source);
347 is_active = true;
348 }
349 display_info_list.push_back(info);
350 }
351 if (is_active) {
352 AddMirrorDisplayInfoIfAny(&display_info_list);
353 UpdateDisplaysWith(display_info_list);
354 } else if (display_info_.find(display_id) != display_info_.end()) {
355 // Inactive displays can reactivate, ensure they have been updated.
356 display_info_[display_id].SetRotation(rotation, source);
357 }
358 }
359
360 bool DisplayManager::SetDisplayMode(
361 int64_t display_id,
362 const scoped_refptr<display::ManagedDisplayMode>& display_mode) {
363 bool change_ui_scale = GetDisplayIdForUIScaling() == display_id;
364
365 DisplayInfoList display_info_list;
366 bool display_property_changed = false;
367 bool resolution_changed = false;
368 for (const auto& display : active_display_list_) {
369 display::ManagedDisplayInfo info = GetDisplayInfo(display.id());
370 if (info.id() == display_id) {
371 auto iter = FindDisplayMode(info, display_mode);
372 if (iter == info.display_modes().end()) {
373 LOG(WARNING) << "Unsupported display mode was requested:"
374 << "size=" << display_mode->size().ToString()
375 << ", ui scale=" << display_mode->ui_scale()
376 << ", scale factor="
377 << display_mode->device_scale_factor();
378 return false;
379 }
380
381 if (change_ui_scale) {
382 if (info.configured_ui_scale() == display_mode->ui_scale())
383 return true;
384 info.set_configured_ui_scale(display_mode->ui_scale());
385 display_property_changed = true;
386 } else {
387 display_modes_[display_id] = *iter;
388 if (info.bounds_in_native().size() != display_mode->size())
389 resolution_changed = true;
390 if (info.device_scale_factor() != display_mode->device_scale_factor()) {
391 info.set_device_scale_factor(display_mode->device_scale_factor());
392 display_property_changed = true;
393 }
394 }
395 }
396 display_info_list.push_back(info);
397 }
398 if (display_property_changed) {
399 AddMirrorDisplayInfoIfAny(&display_info_list);
400 UpdateDisplaysWith(display_info_list);
401 }
402 if (resolution_changed && IsInUnifiedMode()) {
403 ReconfigureDisplays();
404 #if defined(OS_CHROMEOS)
405 } else if (resolution_changed && base::SysInfo::IsRunningOnChromeOS()) {
406 delegate_->display_configurator()->OnConfigurationChanged();
407 #endif
408 }
409 return resolution_changed || display_property_changed;
410 }
411
412 void DisplayManager::RegisterDisplayProperty(
413 int64_t display_id,
414 display::Display::Rotation rotation,
415 float ui_scale,
416 const gfx::Insets* overscan_insets,
417 const gfx::Size& resolution_in_pixels,
418 float device_scale_factor,
419 ui::ColorCalibrationProfile color_profile) {
420 if (display_info_.find(display_id) == display_info_.end())
421 display_info_[display_id] =
422 display::ManagedDisplayInfo(display_id, std::string(), false);
423
424 // Do not allow rotation in unified desktop mode.
425 if (display_id == kUnifiedDisplayId)
426 rotation = display::Display::ROTATE_0;
427
428 display_info_[display_id].SetRotation(rotation,
429 display::Display::ROTATION_SOURCE_USER);
430 display_info_[display_id].SetRotation(
431 rotation, display::Display::ROTATION_SOURCE_ACTIVE);
432 display_info_[display_id].SetColorProfile(color_profile);
433 // Just in case the preference file was corrupted.
434 // TODO(mukai): register |display_modes_| here as well, so the lookup for the
435 // default mode in GetActiveModeForDisplayId() gets much simpler.
436 if (0.5f <= ui_scale && ui_scale <= 2.0f)
437 display_info_[display_id].set_configured_ui_scale(ui_scale);
438 if (overscan_insets)
439 display_info_[display_id].SetOverscanInsets(*overscan_insets);
440 if (!resolution_in_pixels.IsEmpty()) {
441 DCHECK(!display::Display::IsInternalDisplayId(display_id));
442 // Default refresh rate, until OnNativeDisplaysChanged() updates us with the
443 // actual display info, is 60 Hz.
444 scoped_refptr<display::ManagedDisplayMode> mode =
445 new display::ManagedDisplayMode(resolution_in_pixels, 60.0f, false,
446 false, 1.0, device_scale_factor);
447 display_modes_[display_id] = mode;
448 }
449 }
450
451 scoped_refptr<display::ManagedDisplayMode>
452 DisplayManager::GetActiveModeForDisplayId(int64_t display_id) const {
453 scoped_refptr<display::ManagedDisplayMode> selected_mode(
454 GetSelectedModeForDisplayId(display_id));
455 if (selected_mode)
456 return selected_mode;
457
458 // If 'selected' mode is empty, it should return the default mode. This means
459 // the native mode for the external display. Unfortunately this is not true
460 // for the internal display because restoring UI-scale doesn't register the
461 // restored mode to |display_mode_|, so it needs to look up the mode whose
462 // UI-scale value matches. See the TODO in RegisterDisplayProperty().
463 const display::ManagedDisplayInfo& info = GetDisplayInfo(display_id);
464
465 for (auto& mode : info.display_modes()) {
466 if (GetDisplayIdForUIScaling() == display_id) {
467 if (info.configured_ui_scale() == mode->ui_scale())
468 return mode.get();
469 } else if (mode->native()) {
470 return mode.get();
471 }
472 }
473 return selected_mode;
474 }
475
476 void DisplayManager::RegisterDisplayRotationProperties(
477 bool rotation_lock,
478 display::Display::Rotation rotation) {
479 if (delegate_)
480 delegate_->PreDisplayConfigurationChange(false);
481 registered_internal_display_rotation_lock_ = rotation_lock;
482 registered_internal_display_rotation_ = rotation;
483 if (delegate_)
484 delegate_->PostDisplayConfigurationChange();
485 }
486
487 scoped_refptr<display::ManagedDisplayMode>
488 DisplayManager::GetSelectedModeForDisplayId(int64_t id) const {
489 std::map<int64_t, scoped_refptr<display::ManagedDisplayMode>>::const_iterator
490 iter = display_modes_.find(id);
491 if (iter == display_modes_.end())
492 return scoped_refptr<display::ManagedDisplayMode>();
493 return iter->second;
494 }
495
496 bool DisplayManager::IsDisplayUIScalingEnabled() const {
497 return GetDisplayIdForUIScaling() != display::Display::kInvalidDisplayID;
498 }
499
500 gfx::Insets DisplayManager::GetOverscanInsets(int64_t display_id) const {
501 std::map<int64_t, display::ManagedDisplayInfo>::const_iterator it =
502 display_info_.find(display_id);
503 return (it != display_info_.end()) ? it->second.overscan_insets_in_dip()
504 : gfx::Insets();
505 }
506
507 void DisplayManager::SetColorCalibrationProfile(
508 int64_t display_id,
509 ui::ColorCalibrationProfile profile) {
510 #if defined(OS_CHROMEOS)
511 if (!display_info_[display_id].IsColorProfileAvailable(profile))
512 return;
513
514 if (delegate_)
515 delegate_->PreDisplayConfigurationChange(false);
516 // Just sets color profile if it's not running on ChromeOS (like tests).
517 if (!base::SysInfo::IsRunningOnChromeOS() ||
518 delegate_->display_configurator()->SetColorCalibrationProfile(display_id,
519 profile)) {
520 display_info_[display_id].SetColorProfile(profile);
521 UMA_HISTOGRAM_ENUMERATION("ChromeOS.Display.ColorProfile", profile,
522 ui::NUM_COLOR_PROFILES);
523 }
524 if (delegate_)
525 delegate_->PostDisplayConfigurationChange();
526 #endif
527 }
528
529 void DisplayManager::OnNativeDisplaysChanged(
530 const DisplayInfoList& updated_displays) {
531 if (updated_displays.empty()) {
532 VLOG(1) << "OnNativeDisplaysChanged(0): # of current displays="
533 << active_display_list_.size();
534 // If the device is booted without display, or chrome is started
535 // without --ash-host-window-bounds on linux desktop, use the
536 // default display.
537 if (active_display_list_.empty()) {
538 DisplayInfoList init_displays;
539 init_displays.push_back(
540 display::ManagedDisplayInfo::CreateFromSpec(std::string()));
541 MaybeInitInternalDisplay(&init_displays[0]);
542 OnNativeDisplaysChanged(init_displays);
543 } else {
544 // Otherwise don't update the displays when all displays are disconnected.
545 // This happens when:
546 // - the device is idle and powerd requested to turn off all displays.
547 // - the device is suspended. (kernel turns off all displays)
548 // - the internal display's brightness is set to 0 and no external
549 // display is connected.
550 // - the internal display's brightness is 0 and external display is
551 // disconnected.
552 // The display will be updated when one of displays is turned on, and the
553 // display list will be updated correctly.
554 }
555 return;
556 }
557 first_display_id_ = updated_displays[0].id();
558 std::set<gfx::Point> origins;
559
560 if (updated_displays.size() == 1) {
561 VLOG(1) << "OnNativeDisplaysChanged(1):" << updated_displays[0].ToString();
562 } else {
563 VLOG(1) << "OnNativeDisplaysChanged(" << updated_displays.size()
564 << ") [0]=" << updated_displays[0].ToString()
565 << ", [1]=" << updated_displays[1].ToString();
566 }
567
568 bool internal_display_connected = false;
569 num_connected_displays_ = updated_displays.size();
570 mirroring_display_id_ = display::Display::kInvalidDisplayID;
571 software_mirroring_display_list_.clear();
572 DisplayInfoList new_display_info_list;
573 for (DisplayInfoList::const_iterator iter = updated_displays.begin();
574 iter != updated_displays.end(); ++iter) {
575 if (!internal_display_connected)
576 internal_display_connected =
577 display::Display::IsInternalDisplayId(iter->id());
578 // Mirrored monitors have the same origins.
579 gfx::Point origin = iter->bounds_in_native().origin();
580 if (origins.find(origin) != origins.end()) {
581 InsertAndUpdateDisplayInfo(*iter);
582 mirroring_display_id_ = iter->id();
583 } else {
584 origins.insert(origin);
585 new_display_info_list.push_back(*iter);
586 }
587
588 scoped_refptr<display::ManagedDisplayMode> new_mode(
589 new display::ManagedDisplayMode(
590 iter->bounds_in_native().size(), 0.0 /* refresh rate */,
591 false /* interlaced */, false /* native */,
592 iter->configured_ui_scale(), iter->device_scale_factor()));
593 const display::ManagedDisplayInfo::ManagedDisplayModeList& display_modes =
594 iter->display_modes();
595 // This is empty the displays are initialized from InitFromCommandLine.
596 if (display_modes.empty())
597 continue;
598 auto display_modes_iter = FindDisplayMode(*iter, new_mode);
599 // Update the actual resolution selected as the resolution request may fail.
600 if (display_modes_iter == display_modes.end())
601 display_modes_.erase(iter->id());
602 else if (display_modes_.find(iter->id()) != display_modes_.end())
603 display_modes_[iter->id()] = *display_modes_iter;
604 }
605 if (display::Display::HasInternalDisplay() && !internal_display_connected) {
606 if (display_info_.find(display::Display::InternalDisplayId()) ==
607 display_info_.end()) {
608 // Create a dummy internal display if the chrome restarted
609 // in docked mode.
610 display::ManagedDisplayInfo internal_display_info(
611 display::Display::InternalDisplayId(),
612 delegate_->GetInternalDisplayNameString(),
613 false /*Internal display must not have overscan */);
614 internal_display_info.SetBounds(gfx::Rect(0, 0, 800, 600));
615 display_info_[display::Display::InternalDisplayId()] =
616 internal_display_info;
617 } else {
618 // Internal display is no longer active. Reset its rotation to user
619 // preference, so that it is restored when the internal display becomes
620 // active again.
621 display::Display::Rotation user_rotation =
622 display_info_[display::Display::InternalDisplayId()].GetRotation(
623 display::Display::ROTATION_SOURCE_USER);
624 display_info_[display::Display::InternalDisplayId()].SetRotation(
625 user_rotation, display::Display::ROTATION_SOURCE_USER);
626 }
627 }
628
629 #if defined(OS_CHROMEOS)
630 if (!base::SysInfo::IsRunningOnChromeOS() &&
631 new_display_info_list.size() > 1) {
632 display::DisplayIdList list = GenerateDisplayIdList(
633 new_display_info_list.begin(), new_display_info_list.end(),
634 [](const display::ManagedDisplayInfo& info) { return info.id(); });
635
636 const display::DisplayLayout& layout =
637 layout_store_->GetRegisteredDisplayLayout(list);
638 // Mirror mode is set by DisplayConfigurator on the device.
639 // Emulate it when running on linux desktop.
640 if (layout.mirrored)
641 SetMultiDisplayMode(MIRRORING);
642 }
643 #endif
644
645 UpdateDisplaysWith(new_display_info_list);
646 }
647
648 void DisplayManager::UpdateDisplays() {
649 DisplayInfoList display_info_list;
650 for (const auto& display : active_display_list_)
651 display_info_list.push_back(GetDisplayInfo(display.id()));
652 AddMirrorDisplayInfoIfAny(&display_info_list);
653 UpdateDisplaysWith(display_info_list);
654 }
655
656 void DisplayManager::UpdateDisplaysWith(
657 const DisplayInfoList& updated_display_info_list) {
658 #if defined(OS_WIN)
659 DCHECK_EQ(1u, updated_display_info_list.size())
660 << ": Multiple display test does not work on Windows bots. Please "
661 "skip (don't disable) the test using SupportsMultipleDisplays()";
662 #endif
663
664 DisplayInfoList new_display_info_list = updated_display_info_list;
665 std::sort(active_display_list_.begin(), active_display_list_.end(),
666 DisplaySortFunctor());
667 std::sort(new_display_info_list.begin(), new_display_info_list.end(),
668 DisplayInfoSortFunctor());
669
670 if (new_display_info_list.size() > 1) {
671 display::DisplayIdList list = GenerateDisplayIdList(
672 new_display_info_list.begin(), new_display_info_list.end(),
673 [](const display::ManagedDisplayInfo& info) { return info.id(); });
674 const display::DisplayLayout& layout =
675 layout_store_->GetRegisteredDisplayLayout(list);
676 current_default_multi_display_mode_ =
677 (layout.default_unified && unified_desktop_enabled_) ? UNIFIED
678 : EXTENDED;
679 }
680
681 if (multi_display_mode_ != MIRRORING)
682 multi_display_mode_ = current_default_multi_display_mode_;
683
684 CreateSoftwareMirroringDisplayInfo(&new_display_info_list);
685
686 // Close the mirroring window if any here to avoid creating two compositor on
687 // one display.
688 if (delegate_)
689 delegate_->CloseMirroringDisplayIfNotNecessary();
690
691 display::Displays new_displays;
692 display::Displays removed_displays;
693 std::map<size_t, uint32_t> display_changes;
694 std::vector<size_t> added_display_indices;
695
696 display::Displays::iterator curr_iter = active_display_list_.begin();
697 DisplayInfoList::const_iterator new_info_iter = new_display_info_list.begin();
698
699 while (curr_iter != active_display_list_.end() ||
700 new_info_iter != new_display_info_list.end()) {
701 if (curr_iter == active_display_list_.end()) {
702 // more displays in new list.
703 added_display_indices.push_back(new_displays.size());
704 InsertAndUpdateDisplayInfo(*new_info_iter);
705 new_displays.push_back(
706 CreateDisplayFromDisplayInfoById(new_info_iter->id()));
707 ++new_info_iter;
708 } else if (new_info_iter == new_display_info_list.end()) {
709 // more displays in current list.
710 removed_displays.push_back(*curr_iter);
711 ++curr_iter;
712 } else if (curr_iter->id() == new_info_iter->id()) {
713 const display::Display& current_display = *curr_iter;
714 // Copy the info because |InsertAndUpdateDisplayInfo| updates the
715 // instance.
716 const display::ManagedDisplayInfo current_display_info =
717 GetDisplayInfo(current_display.id());
718 InsertAndUpdateDisplayInfo(*new_info_iter);
719 display::Display new_display =
720 CreateDisplayFromDisplayInfoById(new_info_iter->id());
721 const display::ManagedDisplayInfo& new_display_info =
722 GetDisplayInfo(new_display.id());
723
724 uint32_t metrics = display::DisplayObserver::DISPLAY_METRIC_NONE;
725
726 // At that point the new Display objects we have are not entirely updated,
727 // they are missing the translation related to the Display disposition in
728 // the layout.
729 // Using display.bounds() and display.work_area() would fail most of the
730 // time.
731 if (force_bounds_changed_ || (current_display_info.bounds_in_native() !=
732 new_display_info.bounds_in_native()) ||
733 (current_display_info.GetOverscanInsetsInPixel() !=
734 new_display_info.GetOverscanInsetsInPixel()) ||
735 current_display.size() != new_display.size()) {
736 metrics |= display::DisplayObserver::DISPLAY_METRIC_BOUNDS |
737 display::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
738 }
739
740 if (current_display.device_scale_factor() !=
741 new_display.device_scale_factor()) {
742 metrics |= display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
743 }
744
745 if (current_display.rotation() != new_display.rotation())
746 metrics |= display::DisplayObserver::DISPLAY_METRIC_ROTATION;
747
748 if (metrics != display::DisplayObserver::DISPLAY_METRIC_NONE) {
749 display_changes.insert(
750 std::pair<size_t, uint32_t>(new_displays.size(), metrics));
751 }
752
753 new_display.UpdateWorkAreaFromInsets(current_display.GetWorkAreaInsets());
754 new_displays.push_back(new_display);
755 ++curr_iter;
756 ++new_info_iter;
757 } else if (curr_iter->id() < new_info_iter->id()) {
758 // more displays in current list between ids, which means it is deleted.
759 removed_displays.push_back(*curr_iter);
760 ++curr_iter;
761 } else {
762 // more displays in new list between ids, which means it is added.
763 added_display_indices.push_back(new_displays.size());
764 InsertAndUpdateDisplayInfo(*new_info_iter);
765 new_displays.push_back(
766 CreateDisplayFromDisplayInfoById(new_info_iter->id()));
767 ++new_info_iter;
768 }
769 }
770 display::Display old_primary;
771 if (delegate_)
772 old_primary = screen_->GetPrimaryDisplay();
773
774 // Clear focus if the display has been removed, but don't clear focus if
775 // the destkop has been moved from one display to another
776 // (mirror -> docked, docked -> single internal).
777 bool clear_focus =
778 !removed_displays.empty() &&
779 !(removed_displays.size() == 1 && added_display_indices.size() == 1);
780 if (delegate_)
781 delegate_->PreDisplayConfigurationChange(clear_focus);
782
783 std::vector<size_t> updated_indices;
784 UpdateNonPrimaryDisplayBoundsForLayout(&new_displays, &updated_indices);
785 for (size_t updated_index : updated_indices) {
786 if (std::find(added_display_indices.begin(), added_display_indices.end(),
787 updated_index) == added_display_indices.end()) {
788 uint32_t metrics = display::DisplayObserver::DISPLAY_METRIC_BOUNDS |
789 display::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
790 if (display_changes.find(updated_index) != display_changes.end())
791 metrics |= display_changes[updated_index];
792
793 display_changes[updated_index] = metrics;
794 }
795 }
796
797 active_display_list_ = new_displays;
798 active_only_display_list_ = active_display_list_;
799
800 RefreshFontParams();
801 base::AutoReset<bool> resetter(&change_display_upon_host_resize_, false);
802
803 int active_display_list_size = active_display_list_.size();
804 is_updating_display_list_ = true;
805 // Temporarily add displays to be removed because display object
806 // being removed are accessed during shutting down the root.
807 active_display_list_.insert(active_display_list_.end(),
808 removed_displays.begin(), removed_displays.end());
809
810 for (const auto& display : removed_displays)
811 NotifyDisplayRemoved(display);
812
813 for (size_t index : added_display_indices)
814 NotifyDisplayAdded(active_display_list_[index]);
815
816 active_display_list_.resize(active_display_list_size);
817 is_updating_display_list_ = false;
818
819 bool notify_primary_change =
820 delegate_ ? old_primary.id() != screen_->GetPrimaryDisplay().id() : false;
821
822 for (std::map<size_t, uint32_t>::iterator iter = display_changes.begin();
823 iter != display_changes.end(); ++iter) {
824 uint32_t metrics = iter->second;
825 const display::Display& updated_display = active_display_list_[iter->first];
826
827 if (notify_primary_change &&
828 updated_display.id() == screen_->GetPrimaryDisplay().id()) {
829 metrics |= display::DisplayObserver::DISPLAY_METRIC_PRIMARY;
830 notify_primary_change = false;
831 }
832 NotifyMetricsChanged(updated_display, metrics);
833 }
834
835 if (notify_primary_change) {
836 // This happens when a primary display has moved to anther display without
837 // bounds change.
838 const display::Display& primary = screen_->GetPrimaryDisplay();
839 if (primary.id() != old_primary.id()) {
840 uint32_t metrics = display::DisplayObserver::DISPLAY_METRIC_PRIMARY;
841 if (primary.size() != old_primary.size()) {
842 metrics |= (display::DisplayObserver::DISPLAY_METRIC_BOUNDS |
843 display::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
844 }
845 if (primary.device_scale_factor() != old_primary.device_scale_factor())
846 metrics |= display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
847
848 NotifyMetricsChanged(primary, metrics);
849 }
850 }
851
852 if (delegate_)
853 delegate_->PostDisplayConfigurationChange();
854
855 #if defined(USE_X11) && defined(OS_CHROMEOS)
856 if (!display_changes.empty() && base::SysInfo::IsRunningOnChromeOS())
857 ui::ClearX11DefaultRootWindow();
858 #endif
859
860 // Create the mirroring window asynchronously after all displays
861 // are added so that it can mirror the display newly added. This can
862 // happen when switching from dock mode to software mirror mode.
863 CreateMirrorWindowAsyncIfAny();
864 }
865
866 const display::Display& DisplayManager::GetDisplayAt(size_t index) const {
867 DCHECK_LT(index, active_display_list_.size());
868 return active_display_list_[index];
869 }
870
871 const display::Display& DisplayManager::GetPrimaryDisplayCandidate() const {
872 if (GetNumDisplays() != 2)
873 return active_display_list_[0];
874 const display::DisplayLayout& layout =
875 layout_store_->GetRegisteredDisplayLayout(GetCurrentDisplayIdList());
876 return GetDisplayForId(layout.primary_id);
877 }
878
879 size_t DisplayManager::GetNumDisplays() const {
880 return active_display_list_.size();
881 }
882
883 bool DisplayManager::IsActiveDisplayId(int64_t display_id) const {
884 return std::find_if(active_display_list_.begin(), active_display_list_.end(),
885 [display_id](const display::Display& display) {
886 return display.id() == display_id;
887 }) != active_display_list_.end();
888 }
889
890 bool DisplayManager::IsInMirrorMode() const {
891 return mirroring_display_id_ != display::Display::kInvalidDisplayID;
892 }
893
894 void DisplayManager::SetUnifiedDesktopEnabled(bool enable) {
895 unified_desktop_enabled_ = enable;
896 // There is no need to update the displays in mirror mode. Doing
897 // this in hardware mirroring mode can cause crash because display
898 // info in hardware mirroring comes from DisplayConfigurator.
899 if (!IsInMirrorMode())
900 ReconfigureDisplays();
901 }
902
903 bool DisplayManager::IsInUnifiedMode() const {
904 return multi_display_mode_ == UNIFIED &&
905 !software_mirroring_display_list_.empty();
906 }
907
908 const display::ManagedDisplayInfo& DisplayManager::GetDisplayInfo(
909 int64_t display_id) const {
910 DCHECK_NE(display::Display::kInvalidDisplayID, display_id);
911
912 std::map<int64_t, display::ManagedDisplayInfo>::const_iterator iter =
913 display_info_.find(display_id);
914 CHECK(iter != display_info_.end()) << display_id;
915 return iter->second;
916 }
917
918 const display::Display DisplayManager::GetMirroringDisplayById(
919 int64_t display_id) const {
920 auto iter = std::find_if(software_mirroring_display_list_.begin(),
921 software_mirroring_display_list_.end(),
922 [display_id](const display::Display& display) {
923 return display.id() == display_id;
924 });
925 return iter == software_mirroring_display_list_.end() ? display::Display()
926 : *iter;
927 }
928
929 std::string DisplayManager::GetDisplayNameForId(int64_t id) {
930 if (id == display::Display::kInvalidDisplayID)
931 return delegate_->GetInternalDisplayNameString();
932
933 std::map<int64_t, display::ManagedDisplayInfo>::const_iterator iter =
934 display_info_.find(id);
935 if (iter != display_info_.end() && !iter->second.name().empty())
936 return iter->second.name();
937
938 return base::StringPrintf("Display %d", static_cast<int>(id));
939 }
940
941 int64_t DisplayManager::GetDisplayIdForUIScaling() const {
942 // UI Scaling is effective on internal display.
943 return display::Display::HasInternalDisplay()
944 ? display::Display::InternalDisplayId()
945 : display::Display::kInvalidDisplayID;
946 }
947
948 void DisplayManager::SetMirrorMode(bool mirror) {
949 // TODO(oshima): Enable mirror mode for 2> displays. crbug.com/589319.
950 if (num_connected_displays() != 2)
951 return;
952
953 #if defined(OS_CHROMEOS)
954 if (base::SysInfo::IsRunningOnChromeOS()) {
955 ui::MultipleDisplayState new_state =
956 mirror ? ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR
957 : ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
958 delegate_->display_configurator()->SetDisplayMode(new_state);
959 return;
960 }
961 #endif
962 multi_display_mode_ =
963 mirror ? MIRRORING : current_default_multi_display_mode_;
964 ReconfigureDisplays();
965 }
966
967 void DisplayManager::AddRemoveDisplay() {
968 DCHECK(!active_display_list_.empty());
969 DisplayInfoList new_display_info_list;
970 const display::ManagedDisplayInfo& first_display =
971 IsInUnifiedMode()
972 ? GetDisplayInfo(software_mirroring_display_list_[0].id())
973 : GetDisplayInfo(active_display_list_[0].id());
974 new_display_info_list.push_back(first_display);
975 // Add if there is only one display connected.
976 if (num_connected_displays() == 1) {
977 const int kVerticalOffsetPx = 100;
978 // Layout the 2nd display below the primary as with the real device.
979 gfx::Rect host_bounds = first_display.bounds_in_native();
980 new_display_info_list.push_back(
981 display::ManagedDisplayInfo::CreateFromSpec(base::StringPrintf(
982 "%d+%d-600x%d", host_bounds.x(),
983 host_bounds.bottom() + kVerticalOffsetPx, host_bounds.height())));
984 }
985 num_connected_displays_ = new_display_info_list.size();
986 mirroring_display_id_ = display::Display::kInvalidDisplayID;
987 software_mirroring_display_list_.clear();
988 UpdateDisplaysWith(new_display_info_list);
989 }
990
991 void DisplayManager::ToggleDisplayScaleFactor() {
992 DCHECK(!active_display_list_.empty());
993 DisplayInfoList new_display_info_list;
994 for (display::Displays::const_iterator iter = active_display_list_.begin();
995 iter != active_display_list_.end(); ++iter) {
996 display::ManagedDisplayInfo display_info = GetDisplayInfo(iter->id());
997 display_info.set_device_scale_factor(
998 display_info.device_scale_factor() == 1.0f ? 2.0f : 1.0f);
999 new_display_info_list.push_back(display_info);
1000 }
1001 AddMirrorDisplayInfoIfAny(&new_display_info_list);
1002 UpdateDisplaysWith(new_display_info_list);
1003 }
1004
1005 #if defined(OS_CHROMEOS)
1006 void DisplayManager::SetSoftwareMirroring(bool enabled) {
1007 SetMultiDisplayMode(enabled ? MIRRORING
1008 : current_default_multi_display_mode_);
1009 }
1010
1011 bool DisplayManager::SoftwareMirroringEnabled() const {
1012 return software_mirroring_enabled();
1013 }
1014 #endif
1015
1016 void DisplayManager::SetDefaultMultiDisplayModeForCurrentDisplays(
1017 MultiDisplayMode mode) {
1018 DCHECK_NE(MIRRORING, mode);
1019 display::DisplayIdList list = GetCurrentDisplayIdList();
1020 layout_store_->UpdateMultiDisplayState(list, IsInMirrorMode(),
1021 mode == UNIFIED);
1022 ReconfigureDisplays();
1023 }
1024
1025 void DisplayManager::SetMultiDisplayMode(MultiDisplayMode mode) {
1026 multi_display_mode_ = mode;
1027 mirroring_display_id_ = display::Display::kInvalidDisplayID;
1028 software_mirroring_display_list_.clear();
1029 }
1030
1031 void DisplayManager::ReconfigureDisplays() {
1032 DisplayInfoList display_info_list;
1033 for (const display::Display& display : active_display_list_) {
1034 if (display.id() == kUnifiedDisplayId)
1035 continue;
1036 display_info_list.push_back(GetDisplayInfo(display.id()));
1037 }
1038 for (const display::Display& display : software_mirroring_display_list_)
1039 display_info_list.push_back(GetDisplayInfo(display.id()));
1040 mirroring_display_id_ = display::Display::kInvalidDisplayID;
1041 software_mirroring_display_list_.clear();
1042 UpdateDisplaysWith(display_info_list);
1043 }
1044
1045 bool DisplayManager::UpdateDisplayBounds(int64_t display_id,
1046 const gfx::Rect& new_bounds) {
1047 if (change_display_upon_host_resize_) {
1048 display_info_[display_id].SetBounds(new_bounds);
1049 // Don't notify observers if the mirrored window has changed.
1050 if (software_mirroring_enabled() && mirroring_display_id_ == display_id)
1051 return false;
1052 display::Display* display = FindDisplayForId(display_id);
1053 display->SetSize(display_info_[display_id].size_in_pixel());
1054 NotifyMetricsChanged(*display,
1055 display::DisplayObserver::DISPLAY_METRIC_BOUNDS);
1056 return true;
1057 }
1058 return false;
1059 }
1060
1061 void DisplayManager::CreateMirrorWindowAsyncIfAny() {
1062 // Do not post a task if the software mirroring doesn't exist, or
1063 // during initialization when compositor's init task isn't posted yet.
1064 // ash::Shell::Init() will call this after the compositor is initialized.
1065 if (software_mirroring_display_list_.empty() || !delegate_)
1066 return;
1067 base::ThreadTaskRunnerHandle::Get()->PostTask(
1068 FROM_HERE, base::Bind(&DisplayManager::CreateMirrorWindowIfAny,
1069 weak_ptr_factory_.GetWeakPtr()));
1070 }
1071
1072 void DisplayManager::UpdateInternalManagedDisplayModeListForTest() {
1073 if (!display::Display::HasInternalDisplay() ||
1074 display_info_.count(display::Display::InternalDisplayId()) == 0)
1075 return;
1076 display::ManagedDisplayInfo* info =
1077 &display_info_[display::Display::InternalDisplayId()];
1078 SetInternalManagedDisplayModeList(info);
1079 }
1080
1081 bool DisplayManager::ZoomInternalDisplay(bool up) {
1082 int64_t display_id =
1083 IsInUnifiedMode() ? kUnifiedDisplayId : GetDisplayIdForUIScaling();
1084 const display::ManagedDisplayInfo& display_info = GetDisplayInfo(display_id);
1085
1086 scoped_refptr<display::ManagedDisplayMode> mode;
1087 if (IsInUnifiedMode()) {
1088 mode = GetDisplayModeForNextResolution(display_info, up);
1089 } else {
1090 if (!IsActiveDisplayId(display_info.id()) ||
1091 !display::Display::IsInternalDisplayId(display_info.id())) {
1092 return false;
1093 }
1094 mode = GetDisplayModeForNextUIScale(display_info, up);
1095 }
1096
1097 return mode ? SetDisplayMode(display_id, mode) : false;
1098 }
1099
1100 bool DisplayManager::SetDisplayUIScale(int64_t id, float ui_scale) {
1101 if (!IsActiveDisplayId(id) || !display::Display::IsInternalDisplayId(id)) {
1102 return false;
1103 }
1104 const display::ManagedDisplayInfo& info = GetDisplayInfo(id);
1105
1106 scoped_refptr<display::ManagedDisplayMode> mode =
1107 GetDisplayModeForUIScale(info, ui_scale);
1108 if (!mode)
1109 return false;
1110 return SetDisplayMode(id, mode);
1111 }
1112
1113 void DisplayManager::ResetInternalDisplayZoom() {
1114 if (IsInUnifiedMode()) {
1115 const display::ManagedDisplayInfo& display_info =
1116 GetDisplayInfo(DisplayManager::kUnifiedDisplayId);
1117 const display::ManagedDisplayInfo::ManagedDisplayModeList& modes =
1118 display_info.display_modes();
1119 auto iter = std::find_if(
1120 modes.begin(), modes.end(),
1121 [](const scoped_refptr<display::ManagedDisplayMode>& mode) {
1122 return mode->native();
1123 });
1124 SetDisplayMode(kUnifiedDisplayId, *iter);
1125 } else {
1126 SetDisplayUIScale(GetDisplayIdForUIScaling(), 1.0f);
1127 }
1128 }
1129
1130 void DisplayManager::CreateSoftwareMirroringDisplayInfo(
1131 DisplayInfoList* display_info_list) {
1132 // Use the internal display or 1st as the mirror source, then scale
1133 // the root window so that it matches the external display's
1134 // resolution. This is necessary in order for scaling to work while
1135 // mirrored.
1136 switch (multi_display_mode_) {
1137 case MIRRORING: {
1138 if (display_info_list->size() != 2)
1139 return;
1140 bool zero_is_source =
1141 first_display_id_ == (*display_info_list)[0].id() ||
1142 display::Display::IsInternalDisplayId((*display_info_list)[0].id());
1143 DCHECK_EQ(MIRRORING, multi_display_mode_);
1144 mirroring_display_id_ = (*display_info_list)[zero_is_source ? 1 : 0].id();
1145
1146 int64_t display_id = mirroring_display_id_;
1147 auto iter =
1148 std::find_if(display_info_list->begin(), display_info_list->end(),
1149 [display_id](const display::ManagedDisplayInfo& info) {
1150 return info.id() == display_id;
1151 });
1152 DCHECK(iter != display_info_list->end());
1153
1154 display::ManagedDisplayInfo info = *iter;
1155 info.SetOverscanInsets(gfx::Insets());
1156 InsertAndUpdateDisplayInfo(info);
1157 software_mirroring_display_list_.push_back(
1158 CreateMirroringDisplayFromDisplayInfoById(mirroring_display_id_,
1159 gfx::Point(), 1.0f));
1160 display_info_list->erase(iter);
1161 break;
1162 }
1163 case UNIFIED: {
1164 if (display_info_list->size() == 1)
1165 return;
1166 // TODO(oshima): Currently, all displays are laid out horizontally,
1167 // from left to right. Allow more flexible layouts, such as
1168 // right to left, or vertical layouts.
1169 gfx::Rect unified_bounds;
1170 software_mirroring_display_list_.clear();
1171 // 1st Pass. Find the max size.
1172 int max_height = std::numeric_limits<int>::min();
1173
1174 int default_height = 0;
1175 float default_device_scale_factor = 1.0f;
1176 for (auto& info : *display_info_list) {
1177 max_height = std::max(max_height, info.size_in_pixel().height());
1178 if (!default_height ||
1179 display::Display::IsInternalDisplayId(info.id())) {
1180 default_height = info.size_in_pixel().height();
1181 default_device_scale_factor = info.device_scale_factor();
1182 }
1183 }
1184
1185 display::ManagedDisplayInfo::ManagedDisplayModeList display_mode_list;
1186 std::set<std::pair<float, float>> dsf_scale_list;
1187
1188 // 2nd Pass. Compute the unified display size.
1189 for (auto& info : *display_info_list) {
1190 InsertAndUpdateDisplayInfo(info);
1191 gfx::Point origin(unified_bounds.right(), 0);
1192 float scale =
1193 info.size_in_pixel().height() / static_cast<float>(max_height);
1194 // The display is scaled to fit the unified desktop size.
1195 display::Display display = CreateMirroringDisplayFromDisplayInfoById(
1196 info.id(), origin, 1.0f / scale);
1197 unified_bounds.Union(display.bounds());
1198
1199 dsf_scale_list.insert(
1200 std::make_pair(info.device_scale_factor(), scale));
1201 }
1202
1203 display::ManagedDisplayInfo info(kUnifiedDisplayId, "Unified Desktop",
1204 false);
1205
1206 scoped_refptr<display::ManagedDisplayMode> native_mode(
1207 new display::ManagedDisplayMode(unified_bounds.size(), 60.0f, false,
1208 true, 1.0, 1.0));
1209 display::ManagedDisplayInfo::ManagedDisplayModeList modes =
1210 CreateUnifiedManagedDisplayModeList(native_mode, dsf_scale_list);
1211
1212 // Find the default mode.
1213 auto iter = std::find_if(
1214 modes.begin(), modes.end(),
1215 [default_height, default_device_scale_factor](
1216 const scoped_refptr<display::ManagedDisplayMode>& mode) {
1217 return mode->size().height() == default_height &&
1218 mode->device_scale_factor() == default_device_scale_factor;
1219 });
1220
1221 scoped_refptr<display::ManagedDisplayMode> dm(*iter);
1222 *iter = make_scoped_refptr(new display::ManagedDisplayMode(
1223 dm->size(), dm->refresh_rate(), dm->is_interlaced(),
1224 true /* native */, dm->ui_scale(), dm->device_scale_factor()));
1225
1226 info.SetManagedDisplayModes(modes);
1227 info.set_device_scale_factor(dm->device_scale_factor());
1228 info.SetBounds(gfx::Rect(dm->size()));
1229
1230 // Forget the configured resolution if the original unified
1231 // desktop resolution has changed.
1232 if (display_info_.count(kUnifiedDisplayId) != 0 &&
1233 GetMaxNativeSize(display_info_[kUnifiedDisplayId]) !=
1234 unified_bounds.size()) {
1235 display_modes_.erase(kUnifiedDisplayId);
1236 }
1237
1238 // 3rd Pass. Set the selected mode, then recompute the mirroring
1239 // display size.
1240 scoped_refptr<display::ManagedDisplayMode> mode =
1241 GetSelectedModeForDisplayId(kUnifiedDisplayId);
1242 if (mode && FindDisplayMode(info, mode) != info.display_modes().end()) {
1243 info.set_device_scale_factor(mode->device_scale_factor());
1244 info.SetBounds(gfx::Rect(mode->size()));
1245 } else {
1246 display_modes_.erase(kUnifiedDisplayId);
1247 }
1248
1249 int unified_display_height = info.size_in_pixel().height();
1250 gfx::Point origin;
1251 for (auto& info : *display_info_list) {
1252 float display_scale = info.size_in_pixel().height() /
1253 static_cast<float>(unified_display_height);
1254 display::Display display = CreateMirroringDisplayFromDisplayInfoById(
1255 info.id(), origin, 1.0f / display_scale);
1256 origin.Offset(display.size().width(), 0);
1257 display.UpdateWorkAreaFromInsets(gfx::Insets());
1258 software_mirroring_display_list_.push_back(display);
1259 }
1260
1261 display_info_list->clear();
1262 display_info_list->push_back(info);
1263 InsertAndUpdateDisplayInfo(info);
1264 break;
1265 }
1266 case EXTENDED:
1267 break;
1268 }
1269 }
1270
1271 display::Display* DisplayManager::FindDisplayForId(int64_t id) {
1272 auto iter = std::find_if(
1273 active_display_list_.begin(), active_display_list_.end(),
1274 [id](const display::Display& display) { return display.id() == id; });
1275 if (iter != active_display_list_.end())
1276 return &(*iter);
1277 // TODO(oshima): This happens when windows in unified desktop have
1278 // been moved to a normal window. Fix this.
1279 if (id != kUnifiedDisplayId)
1280 DLOG(WARNING) << "Could not find display:" << id;
1281 return nullptr;
1282 }
1283
1284 void DisplayManager::AddMirrorDisplayInfoIfAny(
1285 DisplayInfoList* display_info_list) {
1286 if (software_mirroring_enabled() && IsInMirrorMode()) {
1287 display_info_list->push_back(GetDisplayInfo(mirroring_display_id_));
1288 software_mirroring_display_list_.clear();
1289 }
1290 }
1291
1292 void DisplayManager::InsertAndUpdateDisplayInfo(
1293 const display::ManagedDisplayInfo& new_info) {
1294 std::map<int64_t, display::ManagedDisplayInfo>::iterator info =
1295 display_info_.find(new_info.id());
1296 if (info != display_info_.end()) {
1297 info->second.Copy(new_info);
1298 } else {
1299 display_info_[new_info.id()] = new_info;
1300 display_info_[new_info.id()].set_native(false);
1301 // FHD with 1.25 DSF behaves differently from other configuration.
1302 // It uses 1.25 DSF only when UI-Scale is set to 0.8.
1303 // For new users, use the UI-scale to 0.8 so that it will use DSF=1.25
1304 // internally.
1305 if (display::Display::IsInternalDisplayId(new_info.id()) &&
1306 new_info.bounds_in_native().height() == 1080 &&
1307 new_info.device_scale_factor() == 1.25f) {
1308 display_info_[new_info.id()].set_configured_ui_scale(0.8f);
1309 }
1310 }
1311 display_info_[new_info.id()].UpdateDisplaySize();
1312 OnDisplayInfoUpdated(display_info_[new_info.id()]);
1313 }
1314
1315 void DisplayManager::OnDisplayInfoUpdated(
1316 const display::ManagedDisplayInfo& display_info) {
1317 #if defined(OS_CHROMEOS)
1318 ui::ColorCalibrationProfile color_profile = display_info.color_profile();
1319 if (color_profile != ui::COLOR_PROFILE_STANDARD) {
1320 delegate_->display_configurator()->SetColorCalibrationProfile(
1321 display_info.id(), color_profile);
1322 }
1323 #endif
1324 }
1325
1326 display::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64_t id) {
1327 DCHECK(display_info_.find(id) != display_info_.end()) << "id=" << id;
1328 const display::ManagedDisplayInfo& display_info = display_info_[id];
1329
1330 display::Display new_display(display_info.id());
1331 gfx::Rect bounds_in_native(display_info.size_in_pixel());
1332 float device_scale_factor = display_info.GetEffectiveDeviceScaleFactor();
1333
1334 // Simply set the origin to (0,0). The primary display's origin is
1335 // always (0,0) and the bounds of non-primary display(s) will be updated
1336 // in |UpdateNonPrimaryDisplayBoundsForLayout| called in |UpdateDisplay|.
1337 new_display.SetScaleAndBounds(device_scale_factor,
1338 gfx::Rect(bounds_in_native.size()));
1339 new_display.set_rotation(display_info.GetActiveRotation());
1340 new_display.set_touch_support(display_info.touch_support());
1341 new_display.set_maximum_cursor_size(display_info.maximum_cursor_size());
1342 return new_display;
1343 }
1344
1345 display::Display DisplayManager::CreateMirroringDisplayFromDisplayInfoById(
1346 int64_t id,
1347 const gfx::Point& origin,
1348 float scale) {
1349 DCHECK(display_info_.find(id) != display_info_.end()) << "id=" << id;
1350 const display::ManagedDisplayInfo& display_info = display_info_[id];
1351
1352 display::Display new_display(display_info.id());
1353 new_display.SetScaleAndBounds(
1354 1.0f, gfx::Rect(origin, gfx::ScaleToFlooredSize(
1355 display_info.size_in_pixel(), scale)));
1356 new_display.set_touch_support(display_info.touch_support());
1357 new_display.set_maximum_cursor_size(display_info.maximum_cursor_size());
1358 return new_display;
1359 }
1360
1361 void DisplayManager::UpdateNonPrimaryDisplayBoundsForLayout(
1362 display::Displays* display_list,
1363 std::vector<size_t>* updated_indices) {
1364 if (display_list->size() == 1u)
1365 return;
1366
1367 const display::DisplayLayout& layout =
1368 layout_store_->GetRegisteredDisplayLayout(
1369 display::CreateDisplayIdList(*display_list));
1370
1371 // Ignore if a user has a old format (should be extremely rare)
1372 // and this will be replaced with DCHECK.
1373 if (layout.primary_id == display::Display::kInvalidDisplayID)
1374 return;
1375
1376 // display_list does not have translation set, so ApplyDisplayLayout cannot
1377 // provide accurate change information. We'll find the changes after the call.
1378 ApplyDisplayLayout(layout, display_list, nullptr);
1379 size_t num_displays = display_list->size();
1380 for (size_t index = 0; index < num_displays; ++index) {
1381 const display::Display& display = (*display_list)[index];
1382 int64_t id = display.id();
1383 const display::Display* active_display = FindDisplayForId(id);
1384 if (!active_display || (active_display->bounds() != display.bounds()))
1385 updated_indices->push_back(index);
1386 }
1387 }
1388
1389 void DisplayManager::CreateMirrorWindowIfAny() {
1390 if (software_mirroring_display_list_.empty() || !delegate_)
1391 return;
1392 DisplayInfoList list;
1393 for (auto& display : software_mirroring_display_list_)
1394 list.push_back(GetDisplayInfo(display.id()));
1395 delegate_->CreateOrUpdateMirroringDisplay(list);
1396 }
1397
1398 void DisplayManager::ApplyDisplayLayout(const display::DisplayLayout& layout,
1399 display::Displays* display_list,
1400 std::vector<int64_t>* updated_ids) {
1401 layout.ApplyToDisplayList(display_list, updated_ids,
1402 kMinimumOverlapForInvalidOffset);
1403 }
1404
1405 void DisplayManager::RunPendingTasksForTest() {
1406 if (!software_mirroring_display_list_.empty())
1407 base::RunLoop().RunUntilIdle();
1408 }
1409
1410 void DisplayManager::NotifyMetricsChanged(const display::Display& display,
1411 uint32_t metrics) {
1412 for (auto& observer : observers_)
1413 observer.OnDisplayMetricsChanged(display, metrics);
1414 }
1415
1416 void DisplayManager::NotifyDisplayAdded(const display::Display& display) {
1417 for (auto& observer : observers_)
1418 observer.OnDisplayAdded(display);
1419 }
1420
1421 void DisplayManager::NotifyDisplayRemoved(const display::Display& display) {
1422 for (auto& observer : observers_)
1423 observer.OnDisplayRemoved(display);
1424 }
1425
1426 void DisplayManager::AddObserver(display::DisplayObserver* observer) {
1427 observers_.AddObserver(observer);
1428 }
1429
1430 void DisplayManager::RemoveObserver(display::DisplayObserver* observer) {
1431 observers_.RemoveObserver(observer);
1432 }
1433
1434 const display::Display& DisplayManager::GetSecondaryDisplay() const {
1435 CHECK_LE(2U, GetNumDisplays());
1436 return GetDisplayAt(0).id() ==
1437 display::Screen::GetScreen()->GetPrimaryDisplay().id()
1438 ? GetDisplayAt(1)
1439 : GetDisplayAt(0);
1440 }
1441
1442 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698