| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 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 "services/ui/display/screen_manager_ozone.h" | |
| 6 | |
| 7 #include <string> | |
| 8 #include <utility> | |
| 9 | |
| 10 #include "base/command_line.h" | |
| 11 #include "base/memory/ptr_util.h" | |
| 12 #include "base/threading/thread_task_runner_handle.h" | |
| 13 #include "chromeos/system/devicemode.h" | |
| 14 #include "services/service_manager/public/cpp/interface_registry.h" | |
| 15 #include "third_party/skia/include/core/SkColor.h" | |
| 16 #include "ui/display/manager/chromeos/display_change_observer.h" | |
| 17 #include "ui/display/manager/chromeos/touch_transform_controller.h" | |
| 18 #include "ui/display/manager/display_layout_store.h" | |
| 19 #include "ui/display/manager/display_manager_utilities.h" | |
| 20 #include "ui/display/screen.h" | |
| 21 #include "ui/display/screen_base.h" | |
| 22 #include "ui/display/types/display_snapshot.h" | |
| 23 #include "ui/display/types/fake_display_controller.h" | |
| 24 #include "ui/display/types/native_display_delegate.h" | |
| 25 #include "ui/gfx/geometry/rect.h" | |
| 26 #include "ui/ozone/public/ozone_platform.h" | |
| 27 | |
| 28 namespace display { | |
| 29 namespace { | |
| 30 | |
| 31 // Needed for DisplayConfigurator::ForceInitialConfigure. | |
| 32 const SkColor kChromeOsBootColor = SkColorSetRGB(0xfe, 0xfe, 0xfe); | |
| 33 | |
| 34 // Recursively swaps the displays in a DisplayLayout to change the primary | |
| 35 // display but keep the same relative display layout. | |
| 36 // TODO(kylechar): This is copied from WindowTreeHostManager. The concept of | |
| 37 // getting the same relative display layout with a different primary display id | |
| 38 // should become a function on DisplayLayout itself to avoid reimplementing it | |
| 39 // here. | |
| 40 void SwapRecursive(const std::map<int64_t, DisplayPlacement*>& id_to_placement, | |
| 41 int64_t current_primary_id, | |
| 42 int64_t display_id) { | |
| 43 if (display_id == current_primary_id) | |
| 44 return; | |
| 45 | |
| 46 DCHECK(id_to_placement.count(display_id)); | |
| 47 DisplayPlacement* placement = id_to_placement.at(display_id); | |
| 48 DCHECK(placement); | |
| 49 SwapRecursive(id_to_placement, current_primary_id, | |
| 50 placement->parent_display_id); | |
| 51 placement->Swap(); | |
| 52 } | |
| 53 | |
| 54 } // namespace | |
| 55 | |
| 56 // static | |
| 57 std::unique_ptr<ScreenManager> ScreenManager::Create() { | |
| 58 return base::MakeUnique<ScreenManagerOzone>(); | |
| 59 } | |
| 60 | |
| 61 ScreenManagerOzone::ScreenManagerOzone() {} | |
| 62 | |
| 63 ScreenManagerOzone::~ScreenManagerOzone() { | |
| 64 // We are shutting down and don't want to make anymore display changes. | |
| 65 fake_display_controller_ = nullptr; | |
| 66 | |
| 67 touch_transform_controller_.reset(); | |
| 68 | |
| 69 if (display_manager_) | |
| 70 display_manager_->RemoveObserver(this); | |
| 71 | |
| 72 if (display_change_observer_) { | |
| 73 display_configurator_.RemoveObserver(display_change_observer_.get()); | |
| 74 display_change_observer_.reset(); | |
| 75 } | |
| 76 | |
| 77 if (display_manager_) | |
| 78 display_manager_.reset(); | |
| 79 } | |
| 80 | |
| 81 void ScreenManagerOzone::SetPrimaryDisplayId(int64_t display_id) { | |
| 82 DCHECK_NE(kInvalidDisplayId, display_id); | |
| 83 if (primary_display_id_ == display_id) | |
| 84 return; | |
| 85 | |
| 86 const Display& new_primary_display = | |
| 87 display_manager_->GetDisplayForId(display_id); | |
| 88 if (!new_primary_display.is_valid()) { | |
| 89 LOG(ERROR) << "Invalid or non-existent display is requested:" | |
| 90 << new_primary_display.ToString(); | |
| 91 return; | |
| 92 } | |
| 93 | |
| 94 int64_t old_primary_display_id = primary_display_id_; | |
| 95 | |
| 96 const DisplayLayout& layout = display_manager_->GetCurrentDisplayLayout(); | |
| 97 // The requested primary id can be same as one in the stored layout | |
| 98 // when the primary id is set after new displays are connected. | |
| 99 // Only update the layout if it is requested to swap primary display. | |
| 100 if (layout.primary_id != new_primary_display.id()) { | |
| 101 std::unique_ptr<DisplayLayout> swapped_layout(layout.Copy()); | |
| 102 | |
| 103 std::map<int64_t, DisplayPlacement*> id_to_placement; | |
| 104 for (auto& placement : swapped_layout->placement_list) | |
| 105 id_to_placement[placement.display_id] = &placement; | |
| 106 SwapRecursive(id_to_placement, primary_display_id_, | |
| 107 new_primary_display.id()); | |
| 108 | |
| 109 std::sort(swapped_layout->placement_list.begin(), | |
| 110 swapped_layout->placement_list.end(), | |
| 111 [](const DisplayPlacement& d1, const DisplayPlacement& d2) { | |
| 112 return d1.display_id < d2.display_id; | |
| 113 }); | |
| 114 | |
| 115 swapped_layout->primary_id = new_primary_display.id(); | |
| 116 DisplayIdList list = display_manager_->GetCurrentDisplayIdList(); | |
| 117 display_manager_->layout_store()->RegisterLayoutForDisplayIdList( | |
| 118 list, std::move(swapped_layout)); | |
| 119 } | |
| 120 | |
| 121 primary_display_id_ = new_primary_display.id(); | |
| 122 screen_->display_list().UpdateDisplay(new_primary_display, | |
| 123 DisplayList::Type::PRIMARY); | |
| 124 | |
| 125 // Force updating display bounds for new primary display. | |
| 126 display_manager_->set_force_bounds_changed(true); | |
| 127 display_manager_->UpdateDisplays(); | |
| 128 display_manager_->set_force_bounds_changed(false); | |
| 129 | |
| 130 DVLOG(1) << "Primary display changed from " << old_primary_display_id | |
| 131 << " to " << primary_display_id_; | |
| 132 delegate_->OnPrimaryDisplayChanged(primary_display_id_); | |
| 133 } | |
| 134 | |
| 135 void ScreenManagerOzone::AddInterfaces( | |
| 136 service_manager::InterfaceRegistry* registry) { | |
| 137 registry->AddInterface<mojom::DisplayController>(this); | |
| 138 registry->AddInterface<mojom::TestDisplayController>(this); | |
| 139 } | |
| 140 | |
| 141 void ScreenManagerOzone::Init(ScreenManagerDelegate* delegate) { | |
| 142 DCHECK(delegate); | |
| 143 delegate_ = delegate; | |
| 144 | |
| 145 // Tests may inject a NativeDisplayDelegate, otherwise get it from | |
| 146 // OzonePlatform. | |
| 147 if (!native_display_delegate_) { | |
| 148 native_display_delegate_ = | |
| 149 ui::OzonePlatform::GetInstance()->CreateNativeDisplayDelegate(); | |
| 150 } | |
| 151 | |
| 152 // The FakeDisplayController gives us a way to make the NativeDisplayDelegate | |
| 153 // pretend something display related has happened. | |
| 154 if (!chromeos::IsRunningAsSystemCompositor()) { | |
| 155 fake_display_controller_ = | |
| 156 native_display_delegate_->GetFakeDisplayController(); | |
| 157 } | |
| 158 | |
| 159 // Create a new Screen instance. | |
| 160 std::unique_ptr<ScreenBase> screen = base::MakeUnique<ScreenBase>(); | |
| 161 Screen::SetScreenInstance(screen.get()); | |
| 162 screen_ = screen.get(); | |
| 163 | |
| 164 // Configure display manager. ScreenManager acts as an observer to find out | |
| 165 // display changes and as a delegate to find out when changes start/stop. | |
| 166 display_manager_ = base::MakeUnique<DisplayManager>(std::move(screen)); | |
| 167 display_manager_->set_configure_displays(true); | |
| 168 display_manager_->AddObserver(this); | |
| 169 display_manager_->set_delegate(this); | |
| 170 | |
| 171 // DisplayChangeObserver observes DisplayConfigurator and sends updates to | |
| 172 // DisplayManager. | |
| 173 display_change_observer_ = base::MakeUnique<DisplayChangeObserver>( | |
| 174 &display_configurator_, display_manager_.get()); | |
| 175 | |
| 176 // We want display configuration to happen even off device to keep the control | |
| 177 // flow similar. | |
| 178 display_configurator_.set_configure_display(true); | |
| 179 display_configurator_.AddObserver(display_change_observer_.get()); | |
| 180 display_configurator_.set_state_controller(display_change_observer_.get()); | |
| 181 display_configurator_.set_mirroring_controller(display_manager_.get()); | |
| 182 | |
| 183 // Perform initial configuration. | |
| 184 display_configurator_.Init(std::move(native_display_delegate_), false); | |
| 185 display_configurator_.ForceInitialConfigure(kChromeOsBootColor); | |
| 186 | |
| 187 touch_transform_controller_ = base::MakeUnique<TouchTransformController>( | |
| 188 &display_configurator_, display_manager_.get()); | |
| 189 } | |
| 190 | |
| 191 void ScreenManagerOzone::RequestCloseDisplay(int64_t display_id) { | |
| 192 if (!fake_display_controller_) | |
| 193 return; | |
| 194 | |
| 195 // Tell the NDD to remove the display. ScreenManager will get an update | |
| 196 // that the display configuration has changed and the display will be gone. | |
| 197 fake_display_controller_->RemoveDisplay(display_id); | |
| 198 } | |
| 199 | |
| 200 int64_t ScreenManagerOzone::GetPrimaryDisplayId() const { | |
| 201 return primary_display_id_; | |
| 202 } | |
| 203 | |
| 204 void ScreenManagerOzone::ToggleAddRemoveDisplay() { | |
| 205 if (!fake_display_controller_) | |
| 206 return; | |
| 207 DVLOG(1) << "ToggleAddRemoveDisplay"; | |
| 208 | |
| 209 int num_displays = display_manager_->GetNumDisplays(); | |
| 210 if (num_displays == 1) { | |
| 211 const gfx::Size& pixel_size = | |
| 212 display_manager_->GetDisplayInfo(display_manager_->GetDisplayAt(0).id()) | |
| 213 .bounds_in_native() | |
| 214 .size(); | |
| 215 fake_display_controller_->AddDisplay(pixel_size); | |
| 216 } else if (num_displays > 1) { | |
| 217 DisplayIdList displays = display_manager_->GetCurrentDisplayIdList(); | |
| 218 fake_display_controller_->RemoveDisplay(displays.back()); | |
| 219 } | |
| 220 } | |
| 221 | |
| 222 void ScreenManagerOzone::ToggleDisplayResolution() { | |
| 223 if (primary_display_id_ == kInvalidDisplayId) | |
| 224 return; | |
| 225 | |
| 226 // Internal displays don't have alternate resolutions. | |
| 227 if (Display::HasInternalDisplay() && | |
| 228 primary_display_id_ == Display::InternalDisplayId()) | |
| 229 return; | |
| 230 | |
| 231 DVLOG(1) << "ToggleDisplayResolution"; | |
| 232 | |
| 233 const ManagedDisplayInfo& info = | |
| 234 display_manager_->GetDisplayInfo(primary_display_id_); | |
| 235 scoped_refptr<ManagedDisplayMode> mode = | |
| 236 GetDisplayModeForNextResolution(info, true); | |
| 237 | |
| 238 // Loop back to first mode from last. | |
| 239 if (mode->size() == info.bounds_in_native().size()) | |
| 240 mode = info.display_modes()[0]; | |
| 241 | |
| 242 // Set mode only if it's different from current. | |
| 243 if (mode->size() != info.bounds_in_native().size()) | |
| 244 display_manager_->SetDisplayMode(primary_display_id_, mode); | |
| 245 } | |
| 246 | |
| 247 void ScreenManagerOzone::IncreaseInternalDisplayZoom() { | |
| 248 if (Display::HasInternalDisplay()) | |
| 249 display_manager_->ZoomInternalDisplay(false); | |
| 250 } | |
| 251 | |
| 252 void ScreenManagerOzone::DecreaseInternalDisplayZoom() { | |
| 253 if (Display::HasInternalDisplay()) | |
| 254 display_manager_->ZoomInternalDisplay(true); | |
| 255 } | |
| 256 | |
| 257 void ScreenManagerOzone::ResetInternalDisplayZoom() { | |
| 258 if (Display::HasInternalDisplay()) | |
| 259 display_manager_->ResetInternalDisplayZoom(); | |
| 260 } | |
| 261 | |
| 262 void ScreenManagerOzone::RotateCurrentDisplayCW() { | |
| 263 NOTIMPLEMENTED(); | |
| 264 } | |
| 265 | |
| 266 void ScreenManagerOzone::SwapPrimaryDisplay() { | |
| 267 // Can't swap if there is only 1 display and swapping isn't supported for 3 or | |
| 268 // more displays. | |
| 269 if (display_manager_->GetNumDisplays() != 2) | |
| 270 return; | |
| 271 | |
| 272 DVLOG(1) << "SwapPrimaryDisplay()"; | |
| 273 | |
| 274 DisplayIdList display_ids = display_manager_->GetCurrentDisplayIdList(); | |
| 275 | |
| 276 // Find the next primary display. | |
| 277 if (primary_display_id_ == display_ids[0]) | |
| 278 SetPrimaryDisplayId(display_ids[1]); | |
| 279 else | |
| 280 SetPrimaryDisplayId(display_ids[0]); | |
| 281 } | |
| 282 | |
| 283 void ScreenManagerOzone::ToggleMirrorMode() { | |
| 284 NOTIMPLEMENTED(); | |
| 285 } | |
| 286 | |
| 287 void ScreenManagerOzone::SetDisplayWorkArea(int64_t display_id, | |
| 288 const gfx::Size& size, | |
| 289 const gfx::Insets& insets) { | |
| 290 // TODO(kylechar): Check the size of the display matches the current size. | |
| 291 display_manager_->UpdateWorkAreaOfDisplay(display_id, insets); | |
| 292 } | |
| 293 | |
| 294 void ScreenManagerOzone::TakeDisplayControl( | |
| 295 const TakeDisplayControlCallback& callback) { | |
| 296 display_configurator_.TakeControl(callback); | |
| 297 } | |
| 298 | |
| 299 void ScreenManagerOzone::RelinquishDisplayControl( | |
| 300 const RelinquishDisplayControlCallback& callback) { | |
| 301 display_configurator_.RelinquishControl(callback); | |
| 302 } | |
| 303 | |
| 304 void ScreenManagerOzone::OnDisplayAdded(const Display& display) { | |
| 305 ViewportMetrics metrics = GetViewportMetricsForDisplay(display); | |
| 306 DVLOG(1) << "OnDisplayAdded: " << display.ToString() << "\n " | |
| 307 << metrics.ToString(); | |
| 308 screen_->display_list().AddDisplay(display, DisplayList::Type::NOT_PRIMARY); | |
| 309 delegate_->OnDisplayAdded(display.id(), metrics); | |
| 310 } | |
| 311 | |
| 312 void ScreenManagerOzone::OnDisplayRemoved(const Display& display) { | |
| 313 // TODO(kylechar): If we're removing the primary display we need to first set | |
| 314 // a new primary display. This will crash until then. | |
| 315 | |
| 316 DVLOG(1) << "OnDisplayRemoved: " << display.ToString(); | |
| 317 screen_->display_list().RemoveDisplay(display.id()); | |
| 318 delegate_->OnDisplayRemoved(display.id()); | |
| 319 } | |
| 320 | |
| 321 void ScreenManagerOzone::OnDisplayMetricsChanged(const Display& display, | |
| 322 uint32_t changed_metrics) { | |
| 323 ViewportMetrics metrics = GetViewportMetricsForDisplay(display); | |
| 324 DVLOG(1) << "OnDisplayModified: " << display.ToString() << "\n " | |
| 325 << metrics.ToString(); | |
| 326 screen_->display_list().UpdateDisplay(display); | |
| 327 delegate_->OnDisplayModified(display.id(), metrics); | |
| 328 } | |
| 329 | |
| 330 ViewportMetrics ScreenManagerOzone::GetViewportMetricsForDisplay( | |
| 331 const Display& display) { | |
| 332 const ManagedDisplayInfo& managed_info = | |
| 333 display_manager_->GetDisplayInfo(display.id()); | |
| 334 | |
| 335 ViewportMetrics metrics; | |
| 336 metrics.bounds = display.bounds(); | |
| 337 metrics.work_area = display.work_area(); | |
| 338 metrics.pixel_size = managed_info.bounds_in_native().size(); | |
| 339 metrics.rotation = display.rotation(); | |
| 340 metrics.touch_support = display.touch_support(); | |
| 341 metrics.device_scale_factor = display.device_scale_factor(); | |
| 342 metrics.ui_scale_factor = managed_info.configured_ui_scale(); | |
| 343 | |
| 344 return metrics; | |
| 345 } | |
| 346 | |
| 347 void ScreenManagerOzone::CreateOrUpdateMirroringDisplay( | |
| 348 const DisplayInfoList& display_info_list) { | |
| 349 NOTIMPLEMENTED(); | |
| 350 } | |
| 351 | |
| 352 void ScreenManagerOzone::CloseMirroringDisplayIfNotNecessary() { | |
| 353 NOTIMPLEMENTED(); | |
| 354 } | |
| 355 | |
| 356 void ScreenManagerOzone::PreDisplayConfigurationChange(bool clear_focus) { | |
| 357 DVLOG(1) << "PreDisplayConfigurationChange"; | |
| 358 } | |
| 359 | |
| 360 void ScreenManagerOzone::PostDisplayConfigurationChange( | |
| 361 bool must_clear_window) { | |
| 362 // Set primary display if not set yet. | |
| 363 if (primary_display_id_ == kInvalidDisplayId) { | |
| 364 const Display& primary_display = | |
| 365 display_manager_->GetPrimaryDisplayCandidate(); | |
| 366 if (primary_display.is_valid()) { | |
| 367 primary_display_id_ = primary_display.id(); | |
| 368 DVLOG(1) << "Set primary display to " << primary_display_id_; | |
| 369 screen_->display_list().UpdateDisplay(primary_display, | |
| 370 DisplayList::Type::PRIMARY); | |
| 371 delegate_->OnPrimaryDisplayChanged(primary_display_id_); | |
| 372 } | |
| 373 } | |
| 374 | |
| 375 touch_transform_controller_->UpdateTouchTransforms(); | |
| 376 | |
| 377 DVLOG(1) << "PostDisplayConfigurationChange"; | |
| 378 } | |
| 379 | |
| 380 DisplayConfigurator* ScreenManagerOzone::display_configurator() { | |
| 381 return &display_configurator_; | |
| 382 } | |
| 383 | |
| 384 void ScreenManagerOzone::Create( | |
| 385 const service_manager::Identity& remote_identity, | |
| 386 mojom::DisplayControllerRequest request) { | |
| 387 controller_bindings_.AddBinding(this, std::move(request)); | |
| 388 } | |
| 389 | |
| 390 void ScreenManagerOzone::Create( | |
| 391 const service_manager::Identity& remote_identity, | |
| 392 mojom::TestDisplayControllerRequest request) { | |
| 393 test_bindings_.AddBinding(this, std::move(request)); | |
| 394 } | |
| 395 | |
| 396 } // namespace display | |
| OLD | NEW |