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