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

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

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

Powered by Google App Engine
This is Rietveld 408576698