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 |