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/host/ash_window_tree_host.h"
21 #include "ash/host/ash_window_tree_host_init_params.h"
22 #include "ash/host/root_window_transformer.h"
23 #include "ash/root_window_settings.h"
24 #include "ash/shell.h"
25 #include "base/strings/stringprintf.h"
26 #include "ui/aura/client/capture_client.h"
27 #include "ui/aura/env.h"
28 #include "ui/aura/window_delegate.h"
29 #include "ui/aura/window_event_dispatcher.h"
30 #include "ui/aura/window_tree_host.h"
31 #include "ui/base/layout.h"
32 #include "ui/compositor/reflector.h"
33 #include "ui/gfx/canvas.h"
34 #include "ui/gfx/native_widget_types.h"
37 #include "ui/gfx/x/x11_types.h"
44 // Mirror window shouldn't handle input events.
45 void DisableInput(XID window
) {
46 long event_mask
= ExposureMask
| VisibilityChangeMask
|
47 StructureNotifyMask
| PropertyChangeMask
;
48 XSelectInput(gfx::GetXDisplay(), window
, event_mask
);
49 unsigned char mask
[XIMaskLen(XI_LASTEVENT
)] = {0};
51 evmask
.deviceid
= XIAllDevices
;
52 evmask
.mask_len
= sizeof(mask
);
54 XISelectEvents(gfx::GetXDisplay(), window
, &evmask
, 1);
58 class NoneCaptureClient
: public aura::client::CaptureClient
{
60 NoneCaptureClient() {}
61 virtual ~NoneCaptureClient() {}
64 // Does a capture on the |window|.
65 virtual void SetCapture(aura::Window
* window
) OVERRIDE
{}
67 // Releases a capture from the |window|.
68 virtual void ReleaseCapture(aura::Window
* window
) OVERRIDE
{}
70 // Returns the current capture window.
71 virtual aura::Window
* GetCaptureWindow() OVERRIDE
{
74 virtual aura::Window
* GetGlobalCaptureWindow() OVERRIDE
{
78 DISALLOW_COPY_AND_ASSIGN(NoneCaptureClient
);
83 MirrorWindowController::MirrorWindowController() {}
85 MirrorWindowController::~MirrorWindowController() {
86 // Make sure the root window gets deleted before cursor_window_delegate.
90 void MirrorWindowController::UpdateWindow(const DisplayInfo
& display_info
) {
91 static int mirror_host_count
= 0;
92 if (!ash_host_
.get()) {
93 AshWindowTreeHostInitParams init_params
;
94 init_params
.initial_bounds
= display_info
.bounds_in_native();
95 ash_host_
.reset(AshWindowTreeHost::Create(init_params
));
96 aura::WindowTreeHost
* host
= ash_host_
->AsWindowTreeHost();
97 host
->window()->SetName(
98 base::StringPrintf("MirrorRootWindow-%d", mirror_host_count
++));
99 host
->compositor()->SetBackgroundColor(SK_ColorBLACK
);
100 // No need to remove the observer because the DisplayController outlives the
102 host
->AddObserver(Shell::GetInstance()->display_controller());
103 host
->AddObserver(this);
104 // TODO(oshima): TouchHUD is using idkey.
105 InitRootWindowSettings(host
->window())->display_id
= display_info
.id();
108 DisableInput(host
->GetAcceleratedWidget());
111 aura::client::SetCaptureClient(host
->window(), new NoneCaptureClient());
114 // TODO(oshima): Start mirroring.
115 aura::Window
* mirror_window
= new aura::Window(NULL
);
116 mirror_window
->Init(aura::WINDOW_LAYER_TEXTURED
);
117 host
->window()->AddChild(mirror_window
);
118 mirror_window
->SetBounds(host
->window()->bounds());
119 mirror_window
->Show();
120 reflector_
= aura::Env::GetInstance()->context_factory()->CreateReflector(
121 Shell::GetPrimaryRootWindow()->GetHost()->compositor(),
122 mirror_window
->layer());
124 aura::WindowTreeHost
* host
= ash_host_
->AsWindowTreeHost();
125 GetRootWindowSettings(host
->window())->display_id
= display_info
.id();
126 host
->SetBounds(display_info
.bounds_in_native());
129 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
130 const DisplayInfo
& source_display_info
= display_manager
->GetDisplayInfo(
131 Shell::GetScreen()->GetPrimaryDisplay().id());
132 DCHECK(display_manager
->IsMirrored());
133 scoped_ptr
<RootWindowTransformer
> transformer(
134 CreateRootWindowTransformerForMirroredDisplay(source_display_info
,
136 ash_host_
->SetRootWindowTransformer(transformer
.Pass());
139 void MirrorWindowController::UpdateWindow() {
140 if (ash_host_
.get()) {
141 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
142 const DisplayInfo
& mirror_display_info
= display_manager
->GetDisplayInfo(
143 display_manager
->mirrored_display_id());
144 UpdateWindow(mirror_display_info
);
148 void MirrorWindowController::Close() {
149 if (ash_host_
.get()) {
150 aura::WindowTreeHost
* host
= ash_host_
->AsWindowTreeHost();
151 aura::Env::GetInstance()->context_factory()->RemoveReflector(reflector_
);
153 NoneCaptureClient
* capture_client
= static_cast<NoneCaptureClient
*>(
154 aura::client::GetCaptureClient(host
->window()));
155 aura::client::SetCaptureClient(host
->window(), NULL
);
156 delete capture_client
;
158 host
->RemoveObserver(Shell::GetInstance()->display_controller());
159 host
->RemoveObserver(this);
164 void MirrorWindowController::OnHostResized(const aura::WindowTreeHost
* host
) {
165 if (mirror_window_host_size_
== host
->GetBounds().size())
167 mirror_window_host_size_
= host
->GetBounds().size();
168 reflector_
->OnMirroringCompositorResized();
169 ash_host_
->SetRootWindowTransformer(CreateRootWindowTransformer().Pass());
170 Shell::GetInstance()->display_controller()->cursor_window_controller()->
174 aura::Window
* MirrorWindowController::GetWindow() {
175 return ash_host_
.get() ? ash_host_
->AsWindowTreeHost()->window() : NULL
;
178 scoped_ptr
<RootWindowTransformer
>
179 MirrorWindowController::CreateRootWindowTransformer() const {
180 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
181 const DisplayInfo
& mirror_display_info
= display_manager
->GetDisplayInfo(
182 display_manager
->mirrored_display_id());
183 const DisplayInfo
& source_display_info
= display_manager
->GetDisplayInfo(
184 Shell::GetScreen()->GetPrimaryDisplay().id());
185 DCHECK(display_manager
->IsMirrored());
186 return scoped_ptr
<RootWindowTransformer
>(
187 CreateRootWindowTransformerForMirroredDisplay(source_display_info
,
188 mirror_display_info
));