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