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"
9 #include <X11/extensions/XInput2.h>
11 // Xlib.h defines RootWindow.
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"
38 #include "ui/gfx/x/x11_types.h"
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};
52 evmask
.deviceid
= XIAllDevices
;
53 evmask
.mask_len
= sizeof(mask
);
55 XISelectEvents(gfx::GetXDisplay(), window
, &evmask
, 1);
59 // ScreenPositionClient for mirroring windows.
60 class MirroringScreenPositionClient
61 : public aura::client::ScreenPositionClient
{
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
, ¬_used
);
89 ConvertPointToScreen(root_window
, point
);
92 void SetBounds(aura::Window
* window
,
93 const gfx::Rect
& bounds
,
94 const gfx::Display
& display
) override
{
99 MirrorWindowController
* controller_
; // not owned.
101 DISALLOW_COPY_AND_ASSIGN(MirroringScreenPositionClient
);
104 class NoneCaptureClient
: public aura::client::CaptureClient
{
106 NoneCaptureClient() {}
107 ~NoneCaptureClient() override
{}
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
);
133 struct MirrorWindowController::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.
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 scoped_ptr
<RootWindowTransformer
> transformer
;
169 if (display_manager
->IsInMirrorMode()) {
170 transformer
.reset(CreateRootWindowTransformerForMirroredDisplay(
171 source_display_info
, display_info
));
172 } else if (display_manager
->IsInUnifiedMode()) {
173 gfx::Display display
;
174 display
.SetScaleAndBounds(
176 gfx::Rect(mirroring_origin
, display_info
.bounds_in_native().size()));
177 mirroring_origin
.SetPoint(display
.bounds().right(), 0);
178 transformer
.reset(CreateRootWindowTransformerForUnifiedDesktop(
179 primary
.bounds(), display
));
184 if (mirroring_host_info_map_
.find(display_info
.id()) ==
185 mirroring_host_info_map_
.end()) {
186 AshWindowTreeHostInitParams init_params
;
187 init_params
.initial_bounds
= display_info
.bounds_in_native();
188 MirroringHostInfo
* host_info
= new MirroringHostInfo
;
189 host_info
->ash_host
.reset(AshWindowTreeHost::Create(init_params
));
190 mirroring_host_info_map_
[display_info
.id()] = host_info
;
192 aura::WindowTreeHost
* host
= host_info
->ash_host
->AsWindowTreeHost();
193 host
->SetSharedInputMethod(
194 Shell::GetInstance()->display_controller()->input_method());
195 host
->window()->SetName(
196 base::StringPrintf("MirrorRootWindow-%d", mirror_host_count
++));
197 host
->compositor()->SetBackgroundColor(SK_ColorBLACK
);
198 // No need to remove the observer because the DisplayController outlives
201 host
->AddObserver(Shell::GetInstance()->display_controller());
202 host
->AddObserver(this);
203 // TODO(oshima): TouchHUD is using idkey.
204 InitRootWindowSettings(host
->window())->display_id
= display_info
.id();
207 if (!display_manager
->IsInUnifiedMode())
208 DisableInput(host
->GetAcceleratedWidget());
211 #if defined(OS_CHROMEOS)
212 if (display_manager
->IsInUnifiedMode()) {
213 host_info
->ash_host
->ConfineCursorToRootWindow();
214 AshWindowTreeHost
* unified_ash_host
=
216 ->display_controller()
217 ->GetAshWindowTreeHostForDisplayId(
218 Shell::GetScreen()->GetPrimaryDisplay().id());
219 unified_ash_host
->RegisterMirroringHost(host_info
->ash_host
.get());
220 aura::client::SetScreenPositionClient(host
->window(),
221 screen_position_client_
.get());
225 aura::client::SetCaptureClient(host
->window(), new NoneCaptureClient());
228 aura::Window
* mirror_window
= host_info
->mirror_window
=
229 new aura::Window(nullptr);
230 mirror_window
->Init(ui::LAYER_SOLID_COLOR
);
231 host
->window()->AddChild(mirror_window
);
232 host_info
->ash_host
->SetRootWindowTransformer(transformer
.Pass());
233 mirror_window
->SetBounds(host
->window()->bounds());
234 mirror_window
->Show();
236 reflector_
->AddMirroringLayer(mirror_window
->layer());
239 aura::Env::GetInstance()->context_factory()->CreateReflector(
240 Shell::GetPrimaryRootWindow()->GetHost()->compositor(),
241 mirror_window
->layer());
244 AshWindowTreeHost
* ash_host
=
245 mirroring_host_info_map_
[display_info
.id()]->ash_host
.get();
246 aura::WindowTreeHost
* host
= ash_host
->AsWindowTreeHost();
247 GetRootWindowSettings(host
->window())->display_id
= display_info
.id();
248 ash_host
->SetRootWindowTransformer(transformer
.Pass());
249 host
->SetBounds(display_info
.bounds_in_native());
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
);
270 void MirrorWindowController::UpdateWindow() {
271 if (!mirroring_host_info_map_
.size())
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
)
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();
293 aura::Env::GetInstance()->context_factory()->RemoveReflector(
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())
305 info
->mirror_window_host_size
= host
->GetBounds().size();
306 reflector_
->OnMirroringCompositorResized();
307 // No need to update the transformer as new transformer is already set
310 ->display_controller()
311 ->cursor_window_controller()
318 aura::Window
* MirrorWindowController::GetWindow() {
319 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
320 if (!display_manager
->IsInMirrorMode() || mirroring_host_info_map_
.empty())
322 DCHECK_EQ(1U, mirroring_host_info_map_
.size());
323 return mirroring_host_info_map_
.begin()
324 ->second
->ash_host
->AsWindowTreeHost()
328 gfx::Display
MirrorWindowController::GetDisplayForRootWindow(
329 const aura::Window
* root
) const {
330 for (const auto& pair
: mirroring_host_info_map_
) {
331 if (pair
.second
->ash_host
->AsWindowTreeHost()->window() == root
) {
332 // Sanity check to catch an error early.
333 int64 id
= pair
.first
;
334 const DisplayManager::DisplayList
& list
=
337 ->software_mirroring_display_list();
338 auto iter
= std::find_if(
339 list
.begin(), list
.end(),
340 [id
](const gfx::Display
& display
) { return display
.id() == id
; });
341 DCHECK(iter
!= list
.end());
342 if (iter
!= list
.end())
346 return gfx::Display();
349 AshWindowTreeHost
* MirrorWindowController::GetAshWindowTreeHostForDisplayId(
351 CHECK_EQ(1u, mirroring_host_info_map_
.count(id
));
352 return mirroring_host_info_map_
[id
]->ash_host
.get();
355 aura::Window::Windows
MirrorWindowController::GetAllRootWindows() const {
356 aura::Window::Windows root_windows
;
357 for (const auto& pair
: mirroring_host_info_map_
)
358 root_windows
.push_back(pair
.second
->ash_host
->AsWindowTreeHost()->window());
362 void MirrorWindowController::CloseAndDeleteHost(MirroringHostInfo
* host_info
,
363 bool delay_host_deletion
) {
364 aura::WindowTreeHost
* host
= host_info
->ash_host
->AsWindowTreeHost();
366 aura::client::SetScreenPositionClient(host
->window(), nullptr);
368 NoneCaptureClient
* capture_client
= static_cast<NoneCaptureClient
*>(
369 aura::client::GetCaptureClient(host
->window()));
370 aura::client::SetCaptureClient(host
->window(), nullptr);
371 delete capture_client
;
373 host
->RemoveObserver(Shell::GetInstance()->display_controller());
374 host
->RemoveObserver(this);
375 host_info
->ash_host
->PrepareForShutdown();
376 reflector_
->RemoveMirroringLayer(host_info
->mirror_window
->layer());
378 // EventProcessor may be accessed after this call if the mirroring window
379 // was deleted as a result of input event (e.g. shortcut), so don't delete
381 if (delay_host_deletion
)
382 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, host_info
);