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 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()->display_controller()->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 DisplayController outlives
197 host
->AddObserver(Shell::GetInstance()->display_controller());
198 host
->AddObserver(this);
199 // TODO(oshima): TouchHUD is using idkey.
200 InitRootWindowSettings(host
->window())->display_id
= display_info
.id();
203 if (!display_manager
->IsInUnifiedMode())
204 DisableInput(host
->GetAcceleratedWidget());
207 #if defined(OS_CHROMEOS)
208 if (display_manager
->IsInUnifiedMode()) {
209 host_info
->ash_host
->ConfineCursorToRootWindow();
210 AshWindowTreeHost
* unified_ash_host
=
212 ->display_controller()
213 ->GetAshWindowTreeHostForDisplayId(
214 Shell::GetScreen()->GetPrimaryDisplay().id());
215 unified_ash_host
->RegisterMirroringHost(host_info
->ash_host
.get());
216 aura::client::SetScreenPositionClient(host
->window(),
217 screen_position_client_
.get());
221 aura::client::SetCaptureClient(host
->window(), new NoneCaptureClient());
224 aura::Window
* mirror_window
= host_info
->mirror_window
=
225 new aura::Window(nullptr);
226 mirror_window
->Init(ui::LAYER_SOLID_COLOR
);
227 host
->window()->AddChild(mirror_window
);
228 host_info
->ash_host
->SetRootWindowTransformer(transformer
.Pass());
229 mirror_window
->SetBounds(host
->window()->bounds());
230 mirror_window
->Show();
232 reflector_
->AddMirroringLayer(mirror_window
->layer());
235 aura::Env::GetInstance()->context_factory()->CreateReflector(
236 Shell::GetPrimaryRootWindow()->GetHost()->compositor(),
237 mirror_window
->layer());
240 AshWindowTreeHost
* ash_host
=
241 mirroring_host_info_map_
[display_info
.id()]->ash_host
.get();
242 aura::WindowTreeHost
* host
= ash_host
->AsWindowTreeHost();
243 GetRootWindowSettings(host
->window())->display_id
= display_info
.id();
244 ash_host
->SetRootWindowTransformer(transformer
.Pass());
245 host
->SetBounds(display_info
.bounds_in_native());
249 // Deleting WTHs for disconnected displays.
250 if (mirroring_host_info_map_
.size() > display_info_list
.size()) {
251 for (MirroringHostInfoMap::iterator iter
= mirroring_host_info_map_
.begin();
252 iter
!= mirroring_host_info_map_
.end();) {
253 if (std::find_if(display_info_list
.begin(), display_info_list
.end(),
254 [iter
](const DisplayInfo
& info
) {
255 return info
.id() == iter
->first
;
256 }) == display_info_list
.end()) {
257 CloseAndDeleteHost(iter
->second
, true);
258 iter
= mirroring_host_info_map_
.erase(iter
);
266 void MirrorWindowController::UpdateWindow() {
267 if (!mirroring_host_info_map_
.size())
269 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
270 std::vector
<DisplayInfo
> display_info_list
;
271 for (auto& pair
: mirroring_host_info_map_
)
272 display_info_list
.push_back(display_manager
->GetDisplayInfo(pair
.first
));
273 UpdateWindow(display_info_list
);
276 void MirrorWindowController::CloseIfNotNecessary() {
277 DisplayManager::MultiDisplayMode new_mode
= GetCurrentMultiDisplayMode();
278 if (multi_display_mode_
!= new_mode
)
280 multi_display_mode_
= new_mode
;
283 void MirrorWindowController::Close(bool delay_host_deletion
) {
284 for (auto& info
: mirroring_host_info_map_
)
285 CloseAndDeleteHost(info
.second
, delay_host_deletion
);
287 mirroring_host_info_map_
.clear();
289 aura::Env::GetInstance()->context_factory()->RemoveReflector(
295 void MirrorWindowController::OnHostResized(const aura::WindowTreeHost
* host
) {
296 for (auto& pair
: mirroring_host_info_map_
) {
297 MirroringHostInfo
* info
= pair
.second
;
298 if (info
->ash_host
->AsWindowTreeHost() == host
) {
299 if (info
->mirror_window_host_size
== host
->GetBounds().size())
301 info
->mirror_window_host_size
= host
->GetBounds().size();
302 reflector_
->OnMirroringCompositorResized();
303 // No need to update the transformer as new transformer is already set
306 ->display_controller()
307 ->cursor_window_controller()
314 aura::Window
* MirrorWindowController::GetWindow() {
315 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
316 if (!display_manager
->IsInMirrorMode() || mirroring_host_info_map_
.empty())
318 DCHECK_EQ(1U, mirroring_host_info_map_
.size());
319 return mirroring_host_info_map_
.begin()
320 ->second
->ash_host
->AsWindowTreeHost()
324 gfx::Display
MirrorWindowController::GetDisplayForRootWindow(
325 const aura::Window
* root
) const {
326 for (const auto& pair
: mirroring_host_info_map_
) {
327 if (pair
.second
->ash_host
->AsWindowTreeHost()->window() == root
) {
328 // Sanity check to catch an error early.
329 int64 id
= pair
.first
;
330 const DisplayManager::DisplayList
& list
=
333 ->software_mirroring_display_list();
334 auto iter
= std::find_if(
335 list
.begin(), list
.end(),
336 [id
](const gfx::Display
& display
) { return display
.id() == id
; });
337 DCHECK(iter
!= list
.end());
338 if (iter
!= list
.end())
342 return gfx::Display();
345 AshWindowTreeHost
* MirrorWindowController::GetAshWindowTreeHostForDisplayId(
347 CHECK_EQ(1u, mirroring_host_info_map_
.count(id
));
348 return mirroring_host_info_map_
[id
]->ash_host
.get();
351 aura::Window::Windows
MirrorWindowController::GetAllRootWindows() const {
352 aura::Window::Windows root_windows
;
353 for (const auto& pair
: mirroring_host_info_map_
)
354 root_windows
.push_back(pair
.second
->ash_host
->AsWindowTreeHost()->window());
358 void MirrorWindowController::CloseAndDeleteHost(MirroringHostInfo
* host_info
,
359 bool delay_host_deletion
) {
360 aura::WindowTreeHost
* host
= host_info
->ash_host
->AsWindowTreeHost();
362 aura::client::SetScreenPositionClient(host
->window(), nullptr);
364 NoneCaptureClient
* capture_client
= static_cast<NoneCaptureClient
*>(
365 aura::client::GetCaptureClient(host
->window()));
366 aura::client::SetCaptureClient(host
->window(), nullptr);
367 delete capture_client
;
369 host
->RemoveObserver(Shell::GetInstance()->display_controller());
370 host
->RemoveObserver(this);
371 host_info
->ash_host
->PrepareForShutdown();
372 reflector_
->RemoveMirroringLayer(host_info
->mirror_window
->layer());
374 // EventProcessor may be accessed after this call if the mirroring window
375 // was deleted as a result of input event (e.g. shortcut), so don't delete
377 if (delay_host_deletion
)
378 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, host_info
);