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_info.h"
17 #include "ash/display/display_manager.h"
18 #include "ash/display/root_window_transformers.h"
19 #include "ash/display/screen_position_controller.h"
20 #include "ash/display/window_tree_host_manager.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 for (const DisplayInfo
& display_info
: display_info_list
) {
167 scoped_ptr
<RootWindowTransformer
> transformer
;
168 if (display_manager
->IsInMirrorMode()) {
169 transformer
.reset(CreateRootWindowTransformerForMirroredDisplay(
170 source_display_info
, display_info
));
171 } else if (display_manager
->IsInUnifiedMode()) {
172 gfx::Display display
=
173 display_manager
->GetMirroringDisplayById(display_info
.id());
174 transformer
.reset(CreateRootWindowTransformerForUnifiedDesktop(
175 primary
.bounds(), display
));
180 if (mirroring_host_info_map_
.find(display_info
.id()) ==
181 mirroring_host_info_map_
.end()) {
182 AshWindowTreeHostInitParams init_params
;
183 init_params
.initial_bounds
= display_info
.bounds_in_native();
184 MirroringHostInfo
* host_info
= new MirroringHostInfo
;
185 host_info
->ash_host
.reset(AshWindowTreeHost::Create(init_params
));
186 mirroring_host_info_map_
[display_info
.id()] = host_info
;
188 aura::WindowTreeHost
* host
= host_info
->ash_host
->AsWindowTreeHost();
189 host
->SetSharedInputMethod(
190 Shell::GetInstance()->window_tree_host_manager()->input_method());
191 host
->window()->SetName(
192 base::StringPrintf("MirrorRootWindow-%d", mirror_host_count
++));
193 host
->compositor()->SetBackgroundColor(SK_ColorBLACK
);
194 // No need to remove the observer because the WindowTreeHostManager
198 host
->AddObserver(Shell::GetInstance()->window_tree_host_manager());
199 host
->AddObserver(this);
200 // TODO(oshima): TouchHUD is using idkey.
201 InitRootWindowSettings(host
->window())->display_id
= display_info
.id();
204 if (!display_manager
->IsInUnifiedMode())
205 DisableInput(host
->GetAcceleratedWidget());
208 #if defined(OS_CHROMEOS)
209 if (display_manager
->IsInUnifiedMode()) {
210 host_info
->ash_host
->ConfineCursorToRootWindow();
211 AshWindowTreeHost
* unified_ash_host
=
213 ->window_tree_host_manager()
214 ->GetAshWindowTreeHostForDisplayId(
215 Shell::GetScreen()->GetPrimaryDisplay().id());
216 unified_ash_host
->RegisterMirroringHost(host_info
->ash_host
.get());
217 aura::client::SetScreenPositionClient(host
->window(),
218 screen_position_client_
.get());
222 aura::client::SetCaptureClient(host
->window(), new NoneCaptureClient());
225 aura::Window
* mirror_window
= host_info
->mirror_window
=
226 new aura::Window(nullptr);
227 mirror_window
->Init(ui::LAYER_SOLID_COLOR
);
228 host
->window()->AddChild(mirror_window
);
229 host_info
->ash_host
->SetRootWindowTransformer(transformer
.Pass());
230 mirror_window
->SetBounds(host
->window()->bounds());
231 mirror_window
->Show();
233 reflector_
->AddMirroringLayer(mirror_window
->layer());
236 aura::Env::GetInstance()->context_factory()->CreateReflector(
237 Shell::GetPrimaryRootWindow()->GetHost()->compositor(),
238 mirror_window
->layer());
241 AshWindowTreeHost
* ash_host
=
242 mirroring_host_info_map_
[display_info
.id()]->ash_host
.get();
243 aura::WindowTreeHost
* host
= ash_host
->AsWindowTreeHost();
244 GetRootWindowSettings(host
->window())->display_id
= display_info
.id();
245 ash_host
->SetRootWindowTransformer(transformer
.Pass());
246 host
->SetBounds(display_info
.bounds_in_native());
250 // Deleting WTHs for disconnected displays.
251 if (mirroring_host_info_map_
.size() > display_info_list
.size()) {
252 for (MirroringHostInfoMap::iterator iter
= mirroring_host_info_map_
.begin();
253 iter
!= mirroring_host_info_map_
.end();) {
254 if (std::find_if(display_info_list
.begin(), display_info_list
.end(),
255 [iter
](const DisplayInfo
& info
) {
256 return info
.id() == iter
->first
;
257 }) == display_info_list
.end()) {
258 CloseAndDeleteHost(iter
->second
, true);
259 iter
= mirroring_host_info_map_
.erase(iter
);
267 void MirrorWindowController::UpdateWindow() {
268 if (!mirroring_host_info_map_
.size())
270 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
271 std::vector
<DisplayInfo
> display_info_list
;
272 for (auto& pair
: mirroring_host_info_map_
)
273 display_info_list
.push_back(display_manager
->GetDisplayInfo(pair
.first
));
274 UpdateWindow(display_info_list
);
277 void MirrorWindowController::CloseIfNotNecessary() {
278 DisplayManager::MultiDisplayMode new_mode
= GetCurrentMultiDisplayMode();
279 if (multi_display_mode_
!= new_mode
)
281 multi_display_mode_
= new_mode
;
284 void MirrorWindowController::Close(bool delay_host_deletion
) {
285 for (auto& info
: mirroring_host_info_map_
)
286 CloseAndDeleteHost(info
.second
, delay_host_deletion
);
288 mirroring_host_info_map_
.clear();
290 aura::Env::GetInstance()->context_factory()->RemoveReflector(
296 void MirrorWindowController::OnHostResized(const aura::WindowTreeHost
* host
) {
297 for (auto& pair
: mirroring_host_info_map_
) {
298 MirroringHostInfo
* info
= pair
.second
;
299 if (info
->ash_host
->AsWindowTreeHost() == host
) {
300 if (info
->mirror_window_host_size
== host
->GetBounds().size())
302 info
->mirror_window_host_size
= host
->GetBounds().size();
303 reflector_
->OnMirroringCompositorResized();
304 // No need to update the transformer as new transformer is already set
307 ->window_tree_host_manager()
308 ->cursor_window_controller()
315 aura::Window
* MirrorWindowController::GetWindow() {
316 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
317 if (!display_manager
->IsInMirrorMode() || mirroring_host_info_map_
.empty())
319 DCHECK_EQ(1U, mirroring_host_info_map_
.size());
320 return mirroring_host_info_map_
.begin()
321 ->second
->ash_host
->AsWindowTreeHost()
325 gfx::Display
MirrorWindowController::GetDisplayForRootWindow(
326 const aura::Window
* root
) const {
327 for (const auto& pair
: mirroring_host_info_map_
) {
328 if (pair
.second
->ash_host
->AsWindowTreeHost()->window() == root
) {
329 // Sanity check to catch an error early.
330 int64 id
= pair
.first
;
331 const DisplayManager::DisplayList
& list
=
334 ->software_mirroring_display_list();
335 auto iter
= std::find_if(
336 list
.begin(), list
.end(),
337 [id
](const gfx::Display
& display
) { return display
.id() == id
; });
338 DCHECK(iter
!= list
.end());
339 if (iter
!= list
.end())
343 return gfx::Display();
346 AshWindowTreeHost
* MirrorWindowController::GetAshWindowTreeHostForDisplayId(
348 CHECK_EQ(1u, mirroring_host_info_map_
.count(id
));
349 return mirroring_host_info_map_
[id
]->ash_host
.get();
352 aura::Window::Windows
MirrorWindowController::GetAllRootWindows() const {
353 aura::Window::Windows root_windows
;
354 for (const auto& pair
: mirroring_host_info_map_
)
355 root_windows
.push_back(pair
.second
->ash_host
->AsWindowTreeHost()->window());
359 void MirrorWindowController::CloseAndDeleteHost(MirroringHostInfo
* host_info
,
360 bool delay_host_deletion
) {
361 aura::WindowTreeHost
* host
= host_info
->ash_host
->AsWindowTreeHost();
363 aura::client::SetScreenPositionClient(host
->window(), nullptr);
365 NoneCaptureClient
* capture_client
= static_cast<NoneCaptureClient
*>(
366 aura::client::GetCaptureClient(host
->window()));
367 aura::client::SetCaptureClient(host
->window(), nullptr);
368 delete capture_client
;
370 host
->RemoveObserver(Shell::GetInstance()->window_tree_host_manager());
371 host
->RemoveObserver(this);
372 host_info
->ash_host
->PrepareForShutdown();
373 reflector_
->RemoveMirroringLayer(host_info
->mirror_window
->layer());
375 // EventProcessor may be accessed after this call if the mirroring window
376 // was deleted as a result of input event (e.g. shortcut), so don't delete
378 if (delay_host_deletion
)
379 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, host_info
);