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#include <X11/extensions/XInput2.h>
10
11// Xlib.h defines RootWindow.
12#undef RootWindow
13#endif
14
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"
35
36#if defined(USE_X11)
37#include "ui/gfx/x/x11_types.h"
38#endif
39
40namespace ash {
41namespace {
42
43#if defined(USE_X11)
44// Mirror window shouldn't handle input events.
45void 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};
50  XIEventMask evmask;
51  evmask.deviceid = XIAllDevices;
52  evmask.mask_len = sizeof(mask);
53  evmask.mask = mask;
54  XISelectEvents(gfx::GetXDisplay(), window, &evmask, 1);
55}
56#endif
57
58class NoneCaptureClient : public aura::client::CaptureClient {
59 public:
60  NoneCaptureClient() {}
61  virtual ~NoneCaptureClient() {}
62
63 private:
64  // Does a capture on the |window|.
65  virtual void SetCapture(aura::Window* window) OVERRIDE {}
66
67  // Releases a capture from the |window|.
68  virtual void ReleaseCapture(aura::Window* window) OVERRIDE {}
69
70  // Returns the current capture window.
71  virtual aura::Window* GetCaptureWindow() OVERRIDE {
72    return NULL;
73  }
74  virtual aura::Window* GetGlobalCaptureWindow() OVERRIDE {
75    return NULL;
76  }
77
78  DISALLOW_COPY_AND_ASSIGN(NoneCaptureClient);
79};
80
81}  // namespace
82
83MirrorWindowController::MirrorWindowController() {}
84
85MirrorWindowController::~MirrorWindowController() {
86  // Make sure the root window gets deleted before cursor_window_delegate.
87  Close();
88}
89
90void 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
101    // host.
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();
106    host->InitHost();
107#if defined(USE_X11)
108    DisableInput(host->GetAcceleratedWidget());
109#endif
110
111    aura::client::SetCaptureClient(host->window(), new NoneCaptureClient());
112    host->Show();
113
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());
123  } else {
124    aura::WindowTreeHost* host = ash_host_->AsWindowTreeHost();
125    GetRootWindowSettings(host->window())->display_id = display_info.id();
126    host->SetBounds(display_info.bounds_in_native());
127  }
128
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,
135                                                    display_info));
136  ash_host_->SetRootWindowTransformer(transformer.Pass());
137}
138
139void 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);
145  }
146}
147
148void MirrorWindowController::Close() {
149  if (ash_host_.get()) {
150    aura::WindowTreeHost* host = ash_host_->AsWindowTreeHost();
151    aura::Env::GetInstance()->context_factory()->RemoveReflector(reflector_);
152    reflector_ = NULL;
153    NoneCaptureClient* capture_client = static_cast<NoneCaptureClient*>(
154        aura::client::GetCaptureClient(host->window()));
155    aura::client::SetCaptureClient(host->window(), NULL);
156    delete capture_client;
157
158    host->RemoveObserver(Shell::GetInstance()->display_controller());
159    host->RemoveObserver(this);
160    ash_host_.reset();
161  }
162}
163
164void MirrorWindowController::OnHostResized(const aura::WindowTreeHost* host) {
165  if (mirror_window_host_size_ == host->GetBounds().size())
166    return;
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()->
171      UpdateLocation();
172}
173
174aura::Window* MirrorWindowController::GetWindow() {
175  return ash_host_.get() ? ash_host_->AsWindowTreeHost()->window() : NULL;
176}
177
178scoped_ptr<RootWindowTransformer>
179MirrorWindowController::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));
189}
190
191}  // namespace ash
192