OLD | NEW |
| (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 | |
OLD | NEW |