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
);
125 struct MirrorWindowController::MirroringHostInfo
{
127 ~MirroringHostInfo();
128 scoped_ptr
<AshWindowTreeHost
> ash_host
;
129 gfx::Size mirror_window_host_size
;
130 aura::Window
* mirror_window
= nullptr;
133 MirrorWindowController::MirroringHostInfo::MirroringHostInfo() {
135 MirrorWindowController::MirroringHostInfo::~MirroringHostInfo() {
138 MirrorWindowController::MirrorWindowController()
139 : screen_position_client_(new MirroringScreenPositionClient(this)) {
142 MirrorWindowController::~MirrorWindowController() {
143 // Make sure the root window gets deleted before cursor_window_delegate.
147 void MirrorWindowController::UpdateWindow(
148 const std::vector
<DisplayInfo
>& display_info_list
) {
149 static int mirror_host_count
= 0;
150 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
151 const gfx::Display
& primary
= Shell::GetScreen()->GetPrimaryDisplay();
152 const DisplayInfo
& source_display_info
=
153 display_manager
->GetDisplayInfo(primary
.id());
155 gfx::Point mirroring_origin
;
156 for (const DisplayInfo
& display_info
: display_info_list
) {
157 if (mirroring_host_info_map_
.find(display_info
.id()) ==
158 mirroring_host_info_map_
.end()) {
159 AshWindowTreeHostInitParams init_params
;
160 init_params
.initial_bounds
= display_info
.bounds_in_native();
161 MirroringHostInfo
* host_info
= new MirroringHostInfo
;
162 host_info
->ash_host
.reset(AshWindowTreeHost::Create(init_params
));
163 mirroring_host_info_map_
[display_info
.id()] = host_info
;
165 aura::WindowTreeHost
* host
= host_info
->ash_host
->AsWindowTreeHost();
166 host
->window()->SetName(
167 base::StringPrintf("MirrorRootWindow-%d", mirror_host_count
++));
168 host
->compositor()->SetBackgroundColor(SK_ColorBLACK
);
169 // No need to remove the observer because the DisplayController outlives
172 host
->AddObserver(Shell::GetInstance()->display_controller());
173 host
->AddObserver(this);
174 // TODO(oshima): TouchHUD is using idkey.
175 InitRootWindowSettings(host
->window())->display_id
= display_info
.id();
178 if (!display_manager
->IsInUnifiedMode())
179 DisableInput(host
->GetAcceleratedWidget());
182 #if defined(OS_CHROMEOS)
183 if (display_manager
->IsInUnifiedMode()) {
184 host_info
->ash_host
->ConfineCursorToRootWindow();
185 AshWindowTreeHost
* unified_ash_host
=
187 ->display_controller()
188 ->GetAshWindowTreeHostForDisplayId(
189 Shell::GetScreen()->GetPrimaryDisplay().id());
190 unified_ash_host
->RegisterMirroringHost(host_info
->ash_host
.get());
191 aura::client::SetScreenPositionClient(host
->window(),
192 screen_position_client_
.get());
196 aura::client::SetCaptureClient(host
->window(), new NoneCaptureClient());
199 aura::Window
* mirror_window
= host_info
->mirror_window
=
200 new aura::Window(nullptr);
201 mirror_window
->Init(ui::LAYER_SOLID_COLOR
);
202 host
->window()->AddChild(mirror_window
);
203 mirror_window
->SetBounds(host
->window()->bounds());
204 mirror_window
->Show();
206 reflector_
->AddMirroringLayer(mirror_window
->layer());
209 aura::Env::GetInstance()->context_factory()->CreateReflector(
210 Shell::GetPrimaryRootWindow()->GetHost()->compositor(),
211 mirror_window
->layer());
214 aura::WindowTreeHost
* host
= mirroring_host_info_map_
[display_info
.id()]
215 ->ash_host
->AsWindowTreeHost();
216 GetRootWindowSettings(host
->window())->display_id
= display_info
.id();
217 host
->SetBounds(display_info
.bounds_in_native());
220 AshWindowTreeHost
* mirroring_ash_host
=
221 mirroring_host_info_map_
[display_info
.id()]->ash_host
.get();
222 if (display_manager
->IsInMirrorMode()) {
223 scoped_ptr
<RootWindowTransformer
> transformer(
224 CreateRootWindowTransformerForMirroredDisplay(source_display_info
,
226 mirroring_ash_host
->SetRootWindowTransformer(transformer
.Pass());
227 } else if (display_manager
->IsInUnifiedMode()) {
228 gfx::Display display
;
229 display
.SetScaleAndBounds(
231 gfx::Rect(mirroring_origin
, display_info
.bounds_in_native().size()));
232 mirroring_origin
.SetPoint(display
.bounds().right(), 0);
233 scoped_ptr
<RootWindowTransformer
> transformer(
234 CreateRootWindowTransformerForUnifiedDesktop(primary
.bounds(),
236 mirroring_ash_host
->SetRootWindowTransformer(transformer
.Pass());
242 // Deleting WTHs for disconnected displays.
243 if (mirroring_host_info_map_
.size() > display_info_list
.size()) {
244 for (MirroringHostInfoMap::iterator iter
= mirroring_host_info_map_
.begin();
245 iter
!= mirroring_host_info_map_
.end();) {
246 if (std::find_if(display_info_list
.begin(), display_info_list
.end(),
247 [iter
](const DisplayInfo
& info
) {
248 return info
.id() == iter
->first
;
249 }) == display_info_list
.end()) {
250 CloseAndDeleteHost(iter
->second
);
251 iter
= mirroring_host_info_map_
.erase(iter
);
259 void MirrorWindowController::UpdateWindow() {
260 if (!mirroring_host_info_map_
.size())
262 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
263 std::vector
<DisplayInfo
> display_info_list
;
264 for (auto& pair
: mirroring_host_info_map_
)
265 display_info_list
.push_back(display_manager
->GetDisplayInfo(pair
.first
));
266 UpdateWindow(display_info_list
);
269 void MirrorWindowController::Close() {
270 for (auto& info
: mirroring_host_info_map_
) {
271 CloseAndDeleteHost(info
.second
);
273 mirroring_host_info_map_
.clear();
275 aura::Env::GetInstance()->context_factory()->RemoveReflector(
281 void MirrorWindowController::OnHostResized(const aura::WindowTreeHost
* host
) {
282 for (auto& pair
: mirroring_host_info_map_
) {
283 MirroringHostInfo
* info
= pair
.second
;
284 if (info
->ash_host
->AsWindowTreeHost() == host
) {
285 if (info
->mirror_window_host_size
== host
->GetBounds().size())
287 info
->mirror_window_host_size
= host
->GetBounds().size();
288 reflector_
->OnMirroringCompositorResized();
289 info
->ash_host
->SetRootWindowTransformer(
290 CreateRootWindowTransformer().Pass());
292 ->display_controller()
293 ->cursor_window_controller()
300 aura::Window
* MirrorWindowController::GetWindow() {
301 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
302 // TODO(oshima): Support software cursor in Unified Mode.
303 if (!display_manager
->IsInMirrorMode() || mirroring_host_info_map_
.empty())
305 DCHECK_EQ(1U, mirroring_host_info_map_
.size());
306 return mirroring_host_info_map_
.begin()
307 ->second
->ash_host
->AsWindowTreeHost()
311 gfx::Display
MirrorWindowController::GetDisplayForRootWindow(
312 const aura::Window
* root
) const {
313 for (const auto& pair
: mirroring_host_info_map_
) {
314 if (pair
.second
->ash_host
->AsWindowTreeHost()->window() == root
) {
315 // Sanity check to catch an error early.
316 int64 id
= pair
.first
;
317 const DisplayManager::DisplayList
& list
=
320 ->software_mirroring_display_list();
321 auto iter
= std::find_if(
322 list
.begin(), list
.end(),
323 [id
](const gfx::Display
& display
) { return display
.id() == id
; });
324 DCHECK(iter
!= list
.end());
325 if (iter
!= list
.end())
329 return gfx::Display();
332 AshWindowTreeHost
* MirrorWindowController::GetAshWindowTreeHostForDisplayId(
334 CHECK_EQ(1u, mirroring_host_info_map_
.count(id
));
335 return mirroring_host_info_map_
[id
]->ash_host
.get();
338 aura::Window::Windows
MirrorWindowController::GetAllRootWindows() const {
339 aura::Window::Windows root_windows
;
340 for (const auto& pair
: mirroring_host_info_map_
)
341 root_windows
.push_back(pair
.second
->ash_host
->AsWindowTreeHost()->window());
345 void MirrorWindowController::CloseAndDeleteHost(MirroringHostInfo
* host_info
) {
346 aura::WindowTreeHost
* host
= host_info
->ash_host
->AsWindowTreeHost();
348 aura::client::SetScreenPositionClient(host
->window(), nullptr);
350 NoneCaptureClient
* capture_client
= static_cast<NoneCaptureClient
*>(
351 aura::client::GetCaptureClient(host
->window()));
352 aura::client::SetCaptureClient(host
->window(), nullptr);
353 delete capture_client
;
355 host
->RemoveObserver(Shell::GetInstance()->display_controller());
356 host
->RemoveObserver(this);
357 host_info
->ash_host
->PrepareForShutdown();
358 reflector_
->RemoveMirroringLayer(host_info
->mirror_window
->layer());
363 scoped_ptr
<RootWindowTransformer
>
364 MirrorWindowController::CreateRootWindowTransformer() const {
365 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
366 const DisplayInfo
& mirror_display_info
=
367 display_manager
->GetDisplayInfo(display_manager
->mirroring_display_id());
368 const DisplayInfo
& source_display_info
= display_manager
->GetDisplayInfo(
369 Shell::GetScreen()->GetPrimaryDisplay().id());
370 DCHECK(display_manager
->IsInMirrorMode());
371 return scoped_ptr
<RootWindowTransformer
>(
372 CreateRootWindowTransformerForMirroredDisplay(source_display_info
,
373 mirror_display_info
));