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