Introduce about flags for chrome hosted mode
[chromium-blink-merge.git] / ash / display / mirror_window_controller.cc
blobfc88b79dd7ae837bf94c7e9aabcf56e0b261999a
1 // Copyright (c) 2013 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.
5 #include "ash/display/mirror_window_controller.h"
7 #if defined(USE_X11)
8 #include <X11/Xlib.h>
9 #include <X11/extensions/XInput2.h>
11 // Xlib.h defines RootWindow.
12 #undef RootWindow
13 #endif
15 #include "ash/display/cursor_window_controller.h"
16 #include "ash/display/display_controller.h"
17 #include "ash/display/display_info.h"
18 #include "ash/display/display_manager.h"
19 #include "ash/display/root_window_transformers.h"
20 #include "ash/display/screen_position_controller.h"
21 #include "ash/host/ash_window_tree_host.h"
22 #include "ash/host/ash_window_tree_host_init_params.h"
23 #include "ash/host/root_window_transformer.h"
24 #include "ash/root_window_settings.h"
25 #include "ash/shell.h"
26 #include "base/strings/stringprintf.h"
27 #include "ui/aura/client/capture_client.h"
28 #include "ui/aura/env.h"
29 #include "ui/aura/window_delegate.h"
30 #include "ui/aura/window_event_dispatcher.h"
31 #include "ui/aura/window_tree_host.h"
32 #include "ui/base/layout.h"
33 #include "ui/compositor/reflector.h"
34 #include "ui/gfx/canvas.h"
35 #include "ui/gfx/native_widget_types.h"
37 #if defined(USE_X11)
38 #include "ui/gfx/x/x11_types.h"
39 #endif
41 namespace ash {
42 namespace {
44 #if defined(USE_X11)
45 // Mirror window shouldn't handle input events.
46 void DisableInput(XID window) {
47 long event_mask = ExposureMask | VisibilityChangeMask |
48 StructureNotifyMask | PropertyChangeMask;
49 XSelectInput(gfx::GetXDisplay(), window, event_mask);
50 unsigned char mask[XIMaskLen(XI_LASTEVENT)] = {0};
51 XIEventMask evmask;
52 evmask.deviceid = XIAllDevices;
53 evmask.mask_len = sizeof(mask);
54 evmask.mask = mask;
55 XISelectEvents(gfx::GetXDisplay(), window, &evmask, 1);
57 #endif
59 // ScreenPositionClient for mirroring windows.
60 class MirroringScreenPositionClient
61 : public aura::client::ScreenPositionClient {
62 public:
63 explicit MirroringScreenPositionClient(MirrorWindowController* controller)
64 : controller_(controller) {}
66 void ConvertPointToScreen(const aura::Window* window,
67 gfx::Point* point) override {
68 const aura::Window* root = window->GetRootWindow();
69 aura::Window::ConvertPointToTarget(window, root, point);
70 const gfx::Display& display = controller_->GetDisplayForRootWindow(root);
71 const gfx::Point display_origin = display.bounds().origin();
72 point->Offset(display_origin.x(), display_origin.y());
75 void ConvertPointFromScreen(const aura::Window* window,
76 gfx::Point* point) override {
77 const aura::Window* root = window->GetRootWindow();
78 const gfx::Display& display = controller_->GetDisplayForRootWindow(root);
79 const gfx::Point display_origin = display.bounds().origin();
80 point->Offset(-display_origin.x(), -display_origin.y());
81 aura::Window::ConvertPointToTarget(root, window, point);
84 void ConvertHostPointToScreen(aura::Window* root_window,
85 gfx::Point* point) override {
86 aura::Window* not_used;
87 ScreenPositionController::ConvertHostPointToRelativeToRootWindow(
88 root_window, controller_->GetAllRootWindows(), point, &not_used);
89 ConvertPointToScreen(root_window, point);
92 void SetBounds(aura::Window* window,
93 const gfx::Rect& bounds,
94 const gfx::Display& display) override {
95 NOTREACHED();
98 private:
99 MirrorWindowController* controller_; // not owned.
101 DISALLOW_COPY_AND_ASSIGN(MirroringScreenPositionClient);
104 class NoneCaptureClient : public aura::client::CaptureClient {
105 public:
106 NoneCaptureClient() {}
107 ~NoneCaptureClient() override {}
109 private:
110 // Does a capture on the |window|.
111 void SetCapture(aura::Window* window) override {}
113 // Releases a capture from the |window|.
114 void ReleaseCapture(aura::Window* window) override {}
116 // Returns the current capture window.
117 aura::Window* GetCaptureWindow() override { return NULL; }
118 aura::Window* GetGlobalCaptureWindow() override { return NULL; }
120 DISALLOW_COPY_AND_ASSIGN(NoneCaptureClient);
123 DisplayManager::MultiDisplayMode GetCurrentMultiDisplayMode() {
124 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
125 return display_manager->IsInUnifiedMode()
126 ? DisplayManager::UNIFIED
127 : (display_manager->IsInMirrorMode() ? DisplayManager::MIRRORING
128 : DisplayManager::EXTENDED);
131 } // namespace
133 struct MirrorWindowController::MirroringHostInfo {
134 MirroringHostInfo();
135 ~MirroringHostInfo();
136 scoped_ptr<AshWindowTreeHost> ash_host;
137 gfx::Size mirror_window_host_size;
138 aura::Window* mirror_window = nullptr;
141 MirrorWindowController::MirroringHostInfo::MirroringHostInfo() {
143 MirrorWindowController::MirroringHostInfo::~MirroringHostInfo() {
146 MirrorWindowController::MirrorWindowController()
147 : multi_display_mode_(DisplayManager::EXTENDED),
148 screen_position_client_(new MirroringScreenPositionClient(this)) {
151 MirrorWindowController::~MirrorWindowController() {
152 // Make sure the root window gets deleted before cursor_window_delegate.
153 Close(false);
156 void MirrorWindowController::UpdateWindow(
157 const std::vector<DisplayInfo>& display_info_list) {
158 static int mirror_host_count = 0;
159 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
160 const gfx::Display& primary = Shell::GetScreen()->GetPrimaryDisplay();
161 const DisplayInfo& source_display_info =
162 display_manager->GetDisplayInfo(primary.id());
164 multi_display_mode_ = GetCurrentMultiDisplayMode();
166 gfx::Point mirroring_origin;
167 for (const DisplayInfo& display_info : display_info_list) {
168 if (mirroring_host_info_map_.find(display_info.id()) ==
169 mirroring_host_info_map_.end()) {
170 AshWindowTreeHostInitParams init_params;
171 init_params.initial_bounds = display_info.bounds_in_native();
172 MirroringHostInfo* host_info = new MirroringHostInfo;
173 host_info->ash_host.reset(AshWindowTreeHost::Create(init_params));
174 mirroring_host_info_map_[display_info.id()] = host_info;
176 aura::WindowTreeHost* host = host_info->ash_host->AsWindowTreeHost();
177 host->window()->SetName(
178 base::StringPrintf("MirrorRootWindow-%d", mirror_host_count++));
179 host->compositor()->SetBackgroundColor(SK_ColorBLACK);
180 // No need to remove the observer because the DisplayController outlives
181 // the
182 // host.
183 host->AddObserver(Shell::GetInstance()->display_controller());
184 host->AddObserver(this);
185 // TODO(oshima): TouchHUD is using idkey.
186 InitRootWindowSettings(host->window())->display_id = display_info.id();
187 host->InitHost();
188 #if defined(USE_X11)
189 if (!display_manager->IsInUnifiedMode())
190 DisableInput(host->GetAcceleratedWidget());
191 #endif
193 #if defined(OS_CHROMEOS)
194 if (display_manager->IsInUnifiedMode()) {
195 host_info->ash_host->ConfineCursorToRootWindow();
196 AshWindowTreeHost* unified_ash_host =
197 Shell::GetInstance()
198 ->display_controller()
199 ->GetAshWindowTreeHostForDisplayId(
200 Shell::GetScreen()->GetPrimaryDisplay().id());
201 unified_ash_host->RegisterMirroringHost(host_info->ash_host.get());
202 aura::client::SetScreenPositionClient(host->window(),
203 screen_position_client_.get());
205 #endif
207 aura::client::SetCaptureClient(host->window(), new NoneCaptureClient());
208 host->Show();
210 aura::Window* mirror_window = host_info->mirror_window =
211 new aura::Window(nullptr);
212 mirror_window->Init(ui::LAYER_SOLID_COLOR);
213 host->window()->AddChild(mirror_window);
214 mirror_window->SetBounds(host->window()->bounds());
215 mirror_window->Show();
216 if (reflector_) {
217 reflector_->AddMirroringLayer(mirror_window->layer());
218 } else {
219 reflector_ =
220 aura::Env::GetInstance()->context_factory()->CreateReflector(
221 Shell::GetPrimaryRootWindow()->GetHost()->compositor(),
222 mirror_window->layer());
224 } else {
225 aura::WindowTreeHost* host = mirroring_host_info_map_[display_info.id()]
226 ->ash_host->AsWindowTreeHost();
227 GetRootWindowSettings(host->window())->display_id = display_info.id();
228 host->SetBounds(display_info.bounds_in_native());
231 AshWindowTreeHost* mirroring_ash_host =
232 mirroring_host_info_map_[display_info.id()]->ash_host.get();
233 if (display_manager->IsInMirrorMode()) {
234 scoped_ptr<RootWindowTransformer> transformer(
235 CreateRootWindowTransformerForMirroredDisplay(source_display_info,
236 display_info));
237 mirroring_ash_host->SetRootWindowTransformer(transformer.Pass());
238 } else if (display_manager->IsInUnifiedMode()) {
239 gfx::Display display;
240 display.SetScaleAndBounds(
241 1.0f,
242 gfx::Rect(mirroring_origin, display_info.bounds_in_native().size()));
243 mirroring_origin.SetPoint(display.bounds().right(), 0);
244 scoped_ptr<RootWindowTransformer> transformer(
245 CreateRootWindowTransformerForUnifiedDesktop(primary.bounds(),
246 display));
247 mirroring_ash_host->SetRootWindowTransformer(transformer.Pass());
248 } else {
249 NOTREACHED();
253 // Deleting WTHs for disconnected displays.
254 if (mirroring_host_info_map_.size() > display_info_list.size()) {
255 for (MirroringHostInfoMap::iterator iter = mirroring_host_info_map_.begin();
256 iter != mirroring_host_info_map_.end();) {
257 if (std::find_if(display_info_list.begin(), display_info_list.end(),
258 [iter](const DisplayInfo& info) {
259 return info.id() == iter->first;
260 }) == display_info_list.end()) {
261 CloseAndDeleteHost(iter->second, true);
262 iter = mirroring_host_info_map_.erase(iter);
263 } else {
264 ++iter;
270 void MirrorWindowController::UpdateWindow() {
271 if (!mirroring_host_info_map_.size())
272 return;
273 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
274 std::vector<DisplayInfo> display_info_list;
275 for (auto& pair : mirroring_host_info_map_)
276 display_info_list.push_back(display_manager->GetDisplayInfo(pair.first));
277 UpdateWindow(display_info_list);
280 void MirrorWindowController::CloseIfNotNecessary() {
281 DisplayManager::MultiDisplayMode new_mode = GetCurrentMultiDisplayMode();
282 if (multi_display_mode_ != new_mode)
283 Close(true);
284 multi_display_mode_ = new_mode;
287 void MirrorWindowController::Close(bool delay_host_deletion) {
288 for (auto& info : mirroring_host_info_map_)
289 CloseAndDeleteHost(info.second, delay_host_deletion);
291 mirroring_host_info_map_.clear();
292 if (reflector_) {
293 aura::Env::GetInstance()->context_factory()->RemoveReflector(
294 reflector_.get());
295 reflector_.reset();
299 void MirrorWindowController::OnHostResized(const aura::WindowTreeHost* host) {
300 for (auto& pair : mirroring_host_info_map_) {
301 MirroringHostInfo* info = pair.second;
302 if (info->ash_host->AsWindowTreeHost() == host) {
303 if (info->mirror_window_host_size == host->GetBounds().size())
304 return;
305 info->mirror_window_host_size = host->GetBounds().size();
306 reflector_->OnMirroringCompositorResized();
307 info->ash_host->SetRootWindowTransformer(
308 CreateRootWindowTransformer().Pass());
309 Shell::GetInstance()
310 ->display_controller()
311 ->cursor_window_controller()
312 ->UpdateLocation();
313 return;
318 aura::Window* MirrorWindowController::GetWindow() {
319 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
320 // TODO(oshima): Support software cursor in Unified Mode.
321 if (!display_manager->IsInMirrorMode() || mirroring_host_info_map_.empty())
322 return nullptr;
323 DCHECK_EQ(1U, mirroring_host_info_map_.size());
324 return mirroring_host_info_map_.begin()
325 ->second->ash_host->AsWindowTreeHost()
326 ->window();
329 gfx::Display MirrorWindowController::GetDisplayForRootWindow(
330 const aura::Window* root) const {
331 for (const auto& pair : mirroring_host_info_map_) {
332 if (pair.second->ash_host->AsWindowTreeHost()->window() == root) {
333 // Sanity check to catch an error early.
334 int64 id = pair.first;
335 const DisplayManager::DisplayList& list =
336 Shell::GetInstance()
337 ->display_manager()
338 ->software_mirroring_display_list();
339 auto iter = std::find_if(
340 list.begin(), list.end(),
341 [id](const gfx::Display& display) { return display.id() == id; });
342 DCHECK(iter != list.end());
343 if (iter != list.end())
344 return *iter;
347 return gfx::Display();
350 AshWindowTreeHost* MirrorWindowController::GetAshWindowTreeHostForDisplayId(
351 int64 id) {
352 CHECK_EQ(1u, mirroring_host_info_map_.count(id));
353 return mirroring_host_info_map_[id]->ash_host.get();
356 aura::Window::Windows MirrorWindowController::GetAllRootWindows() const {
357 aura::Window::Windows root_windows;
358 for (const auto& pair : mirroring_host_info_map_)
359 root_windows.push_back(pair.second->ash_host->AsWindowTreeHost()->window());
360 return root_windows;
363 void MirrorWindowController::CloseAndDeleteHost(MirroringHostInfo* host_info,
364 bool delay_host_deletion) {
365 aura::WindowTreeHost* host = host_info->ash_host->AsWindowTreeHost();
367 aura::client::SetScreenPositionClient(host->window(), nullptr);
369 NoneCaptureClient* capture_client = static_cast<NoneCaptureClient*>(
370 aura::client::GetCaptureClient(host->window()));
371 aura::client::SetCaptureClient(host->window(), nullptr);
372 delete capture_client;
374 host->RemoveObserver(Shell::GetInstance()->display_controller());
375 host->RemoveObserver(this);
376 host_info->ash_host->PrepareForShutdown();
377 reflector_->RemoveMirroringLayer(host_info->mirror_window->layer());
379 // EventProcessor may be accessed after this call if the mirroring window
380 // was deleted as a result of input event (e.g. shortcut), so don't delete
381 // now.
382 if (delay_host_deletion)
383 base::MessageLoop::current()->DeleteSoon(FROM_HERE, host_info);
384 else
385 delete host_info;
388 scoped_ptr<RootWindowTransformer>
389 MirrorWindowController::CreateRootWindowTransformer() const {
390 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
391 const DisplayInfo& mirror_display_info =
392 display_manager->GetDisplayInfo(display_manager->mirroring_display_id());
393 const DisplayInfo& source_display_info = display_manager->GetDisplayInfo(
394 Shell::GetScreen()->GetPrimaryDisplay().id());
395 DCHECK(display_manager->IsInMirrorMode());
396 return scoped_ptr<RootWindowTransformer>(
397 CreateRootWindowTransformerForMirroredDisplay(source_display_info,
398 mirror_display_info));
401 } // namespace ash