mirror_window_controller.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
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.
4
5#include "ash/display/mirror_window_controller.h"
6
7#if defined(USE_X11)
8#include <X11/Xlib.h>
9
10// Xlib.h defines RootWindow.
11#undef RootWindow
12#endif
13
14#include "ash/display/cursor_window_controller.h"
15#include "ash/display/display_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/host/ash_window_tree_host.h"
20#include "ash/host/ash_window_tree_host_init_params.h"
21#include "ash/host/root_window_transformer.h"
22#include "ash/root_window_settings.h"
23#include "ash/shell.h"
24#include "base/strings/stringprintf.h"
25#include "ui/aura/client/capture_client.h"
26#include "ui/aura/env.h"
27#include "ui/aura/window_delegate.h"
28#include "ui/aura/window_event_dispatcher.h"
29#include "ui/aura/window_tree_host.h"
30#include "ui/base/layout.h"
31#include "ui/compositor/reflector.h"
32#include "ui/gfx/canvas.h"
33#include "ui/gfx/native_widget_types.h"
34
35#if defined(USE_X11)
36#include "ui/gfx/x/x11_types.h"
37#endif
38
39namespace ash {
40namespace {
41
42#if defined(USE_X11)
43// Mirror window shouldn't handle input events.
44void DisableInput(XID window) {
45  long event_mask = ExposureMask | VisibilityChangeMask |
46      StructureNotifyMask | PropertyChangeMask;
47  XSelectInput(gfx::GetXDisplay(), window, event_mask);
48}
49#endif
50
51class NoneCaptureClient : public aura::client::CaptureClient {
52 public:
53  NoneCaptureClient() {}
54  virtual ~NoneCaptureClient() {}
55
56 private:
57  // Does a capture on the |window|.
58  virtual void SetCapture(aura::Window* window) OVERRIDE {}
59
60  // Releases a capture from the |window|.
61  virtual void ReleaseCapture(aura::Window* window) OVERRIDE {}
62
63  // Returns the current capture window.
64  virtual aura::Window* GetCaptureWindow() OVERRIDE {
65    return NULL;
66  }
67  virtual aura::Window* GetGlobalCaptureWindow() OVERRIDE {
68    return NULL;
69  }
70
71  DISALLOW_COPY_AND_ASSIGN(NoneCaptureClient);
72};
73
74}  // namespace
75
76MirrorWindowController::MirrorWindowController() {}
77
78MirrorWindowController::~MirrorWindowController() {
79  // Make sure the root window gets deleted before cursor_window_delegate.
80  Close();
81}
82
83void MirrorWindowController::UpdateWindow(const DisplayInfo& display_info) {
84  static int mirror_host_count = 0;
85  if (!ash_host_.get()) {
86    AshWindowTreeHostInitParams init_params;
87    init_params.initial_bounds = display_info.bounds_in_native();
88    ash_host_.reset(AshWindowTreeHost::Create(init_params));
89    aura::WindowTreeHost* host = ash_host_->AsWindowTreeHost();
90    host->window()->SetName(
91        base::StringPrintf("MirrorRootWindow-%d", mirror_host_count++));
92    host->compositor()->SetBackgroundColor(SK_ColorBLACK);
93    // No need to remove the observer because the DisplayController outlives the
94    // host.
95    host->AddObserver(Shell::GetInstance()->display_controller());
96    host->AddObserver(this);
97    // TODO(oshima): TouchHUD is using idkey.
98    InitRootWindowSettings(host->window())->display_id = display_info.id();
99    host->InitHost();
100#if defined(USE_X11)
101    DisableInput(host->GetAcceleratedWidget());
102#endif
103
104    aura::client::SetCaptureClient(host->window(), new NoneCaptureClient());
105    host->Show();
106
107    // TODO(oshima): Start mirroring.
108    aura::Window* mirror_window = new aura::Window(NULL);
109    mirror_window->Init(aura::WINDOW_LAYER_TEXTURED);
110    host->window()->AddChild(mirror_window);
111    mirror_window->SetBounds(host->window()->bounds());
112    mirror_window->Show();
113    reflector_ = aura::Env::GetInstance()->context_factory()->CreateReflector(
114        Shell::GetPrimaryRootWindow()->GetHost()->compositor(),
115        mirror_window->layer());
116  } else {
117    aura::WindowTreeHost* host = ash_host_->AsWindowTreeHost();
118    GetRootWindowSettings(host->window())->display_id = display_info.id();
119    host->SetBounds(display_info.bounds_in_native());
120  }
121
122  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
123  const DisplayInfo& source_display_info = display_manager->GetDisplayInfo(
124      Shell::GetScreen()->GetPrimaryDisplay().id());
125  DCHECK(display_manager->IsMirrored());
126  scoped_ptr<RootWindowTransformer> transformer(
127      CreateRootWindowTransformerForMirroredDisplay(source_display_info,
128                                                    display_info));
129  ash_host_->SetRootWindowTransformer(transformer.Pass());
130}
131
132void MirrorWindowController::UpdateWindow() {
133  if (ash_host_.get()) {
134    DisplayManager* display_manager = Shell::GetInstance()->display_manager();
135    const DisplayInfo& mirror_display_info = display_manager->GetDisplayInfo(
136        display_manager->mirrored_display_id());
137    UpdateWindow(mirror_display_info);
138  }
139}
140
141void MirrorWindowController::Close() {
142  if (ash_host_.get()) {
143    aura::WindowTreeHost* host = ash_host_->AsWindowTreeHost();
144    aura::Env::GetInstance()->context_factory()->RemoveReflector(reflector_);
145    reflector_ = NULL;
146    NoneCaptureClient* capture_client = static_cast<NoneCaptureClient*>(
147        aura::client::GetCaptureClient(host->window()));
148    aura::client::SetCaptureClient(host->window(), NULL);
149    delete capture_client;
150
151    host->RemoveObserver(Shell::GetInstance()->display_controller());
152    host->RemoveObserver(this);
153    ash_host_.reset();
154  }
155}
156
157void MirrorWindowController::OnHostResized(const aura::WindowTreeHost* host) {
158  if (mirror_window_host_size_ == host->GetBounds().size())
159    return;
160  mirror_window_host_size_ = host->GetBounds().size();
161  reflector_->OnMirroringCompositorResized();
162  ash_host_->SetRootWindowTransformer(CreateRootWindowTransformer().Pass());
163  Shell::GetInstance()->display_controller()->cursor_window_controller()->
164      UpdateLocation();
165}
166
167aura::Window* MirrorWindowController::GetWindow() {
168  return ash_host_.get() ? ash_host_->AsWindowTreeHost()->window() : NULL;
169}
170
171scoped_ptr<RootWindowTransformer>
172MirrorWindowController::CreateRootWindowTransformer() const {
173  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
174  const DisplayInfo& mirror_display_info = display_manager->GetDisplayInfo(
175      display_manager->mirrored_display_id());
176  const DisplayInfo& source_display_info = display_manager->GetDisplayInfo(
177      Shell::GetScreen()->GetPrimaryDisplay().id());
178  DCHECK(display_manager->IsMirrored());
179  return scoped_ptr<RootWindowTransformer>(
180      CreateRootWindowTransformerForMirroredDisplay(source_display_info,
181                                                    mirror_display_info));
182}
183
184}  // namespace ash
185