mirror_window_controller.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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/display_info.h"
15#include "ash/display/display_manager.h"
16#include "ash/host/root_window_host_factory.h"
17#include "ash/shell.h"
18#include "base/stringprintf.h"
19#include "ui/aura/client/capture_client.h"
20#include "ui/aura/env.h"
21#include "ui/aura/root_window.h"
22#include "ui/aura/window_delegate.h"
23#include "ui/base/cursor/cursors_aura.h"
24#include "ui/base/hit_test.h"
25#include "ui/base/layout.h"
26#include "ui/base/resource/resource_bundle.h"
27#include "ui/compositor/compositor.h"
28#include "ui/gfx/canvas.h"
29#include "ui/gfx/image/image_skia.h"
30#include "ui/gfx/native_widget_types.h"
31
32namespace ash {
33namespace internal {
34namespace {
35
36#if defined(USE_X11)
37// Mirror window shouldn't handle input events.
38void DisableInput(XID window) {
39  long event_mask = ExposureMask | VisibilityChangeMask |
40      StructureNotifyMask | PropertyChangeMask;
41  XSelectInput(base::MessagePumpAuraX11::GetDefaultXDisplay(),
42               window, event_mask);
43}
44#endif
45
46class NoneCaptureClient : public aura::client::CaptureClient {
47 public:
48  NoneCaptureClient() {}
49  virtual ~NoneCaptureClient() {}
50
51 private:
52  // Does a capture on the |window|.
53  virtual void SetCapture(aura::Window* window) OVERRIDE {}
54
55  // Releases a capture from the |window|.
56  virtual void ReleaseCapture(aura::Window* window) OVERRIDE {}
57
58  // Returns the current capture window.
59  virtual aura::Window* GetCaptureWindow() OVERRIDE {
60    return NULL;
61  }
62
63  DISALLOW_COPY_AND_ASSIGN(NoneCaptureClient);
64};
65
66}  // namespace
67
68class CursorWindowDelegate : public aura::WindowDelegate {
69 public:
70  CursorWindowDelegate() {}
71  virtual ~CursorWindowDelegate() {}
72
73  // aura::WindowDelegate overrides:
74  virtual gfx::Size GetMinimumSize() const OVERRIDE {
75    return cursor_image_.size();
76  }
77  virtual gfx::Size GetMaximumSize() const OVERRIDE {
78    return cursor_image_.size();
79  }
80  virtual void OnBoundsChanged(const gfx::Rect& old_bounds,
81                               const gfx::Rect& new_bounds) OVERRIDE {
82  }
83  virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE {
84    return gfx::kNullCursor;
85  }
86  virtual int GetNonClientComponent(
87      const gfx::Point& point) const OVERRIDE {
88    return HTNOWHERE;
89  }
90  virtual bool ShouldDescendIntoChildForEventHandling(
91      aura::Window* child,
92      const gfx::Point& location) OVERRIDE {
93    return false;
94  }
95  virtual bool CanFocus() OVERRIDE {
96    return false;
97  }
98  virtual void OnCaptureLost() OVERRIDE {
99  }
100  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
101    canvas->DrawImageInt(cursor_image_, 0, 0);
102  }
103  virtual void OnDeviceScaleFactorChanged(
104      float device_scale_factor) OVERRIDE {
105  }
106  virtual void OnWindowDestroying() OVERRIDE {}
107  virtual void OnWindowDestroyed() OVERRIDE {}
108  virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE {
109  }
110  virtual bool HasHitTestMask() const OVERRIDE {
111    return false;
112  }
113  virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {}
114  virtual scoped_refptr<ui::Texture> CopyTexture() OVERRIDE {
115    NOTREACHED();
116    return scoped_refptr<ui::Texture>();
117  }
118
119  void SetCursorImage(const gfx::ImageSkia& image) {
120    cursor_image_ = image;
121  }
122
123 private:
124  gfx::ImageSkia cursor_image_;
125
126  DISALLOW_COPY_AND_ASSIGN(CursorWindowDelegate);
127};
128
129MirrorWindowController::MirrorWindowController()
130    : current_cursor_type_(ui::kCursorNone),
131      cursor_window_(NULL),
132      cursor_window_delegate_(new CursorWindowDelegate) {
133}
134
135MirrorWindowController::~MirrorWindowController() {
136  // Make sure the root window gets deleted before cursor_window_delegate.
137  root_window_.reset();
138}
139
140void MirrorWindowController::UpdateWindow(const DisplayInfo& display_info) {
141  static int mirror_root_window_count = 0;
142  if (root_window_.get()) {
143    root_window_->SetHostBounds(display_info.bounds_in_pixel());
144    return;
145  }
146  Shell* shell = Shell::GetInstance();
147  const gfx::Rect& bounds_in_pixel = display_info.bounds_in_pixel();
148  aura::RootWindow::CreateParams params(bounds_in_pixel);
149  params.host = shell->root_window_host_factory()->
150      CreateRootWindowHost(bounds_in_pixel);
151  root_window_.reset(new aura::RootWindow(params));
152  root_window_->SetName(
153      base::StringPrintf("MirrorRootWindow-%d", mirror_root_window_count++));
154  root_window_->compositor()->SetBackgroundColor(SK_ColorBLACK);
155  // No need to remove RootWindowObserver because
156  // the DisplayManager object outlives RootWindow objects.
157  root_window_->AddRootWindowObserver(shell->display_manager());
158  // TODO(oshima): TouchHUD is using idkey.
159  root_window_->SetProperty(internal::kDisplayIdKey, display_info.id());
160  root_window_->Init();
161#if defined(USE_X11)
162  DisableInput(root_window_->GetAcceleratedWidget());
163#endif
164  aura::client::SetCaptureClient(root_window_.get(), new NoneCaptureClient());
165  root_window_->ShowRootWindow();
166
167  cursor_window_ = new aura::Window(cursor_window_delegate_.get());
168  cursor_window_->SetTransparent(true);
169  cursor_window_->Init(ui::LAYER_TEXTURED);
170  root_window_->AddChild(cursor_window_);
171  cursor_window_->Show();
172}
173
174void MirrorWindowController::Close() {
175  if (root_window_.get()) {
176    NoneCaptureClient* capture_client = static_cast<NoneCaptureClient*>(
177        aura::client::GetCaptureClient(root_window_.get()));
178    delete capture_client;
179    root_window_.reset();
180    cursor_window_ = NULL;
181  }
182}
183
184void MirrorWindowController::UpdateCursorLocation() {
185  if (cursor_window_) {
186    gfx::Point point = aura::Env::GetInstance()->last_mouse_location();
187    point.Offset(-hot_point_.x(), -hot_point_.y());
188    gfx::Rect bounds = cursor_window_->bounds();
189    bounds.set_origin(point);
190    cursor_window_->SetBounds(bounds);
191  }
192}
193
194void MirrorWindowController::SetMirroredCursor(gfx::NativeCursor cursor) {
195  if (current_cursor_type_ == cursor.native_type())
196    return;
197  current_cursor_type_ = cursor.native_type();
198  int resource_id;
199  bool success = ui::GetCursorDataFor(
200      current_cursor_type_, 1.0, &resource_id, &hot_point_);
201  if (!success)
202    return;
203  const gfx::ImageSkia* image =
204      ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id);
205  cursor_window_delegate_->SetCursorImage(*image);
206  if (cursor_window_) {
207    cursor_window_->SchedulePaintInRect(
208        gfx::Rect(cursor_window_->bounds().size()));
209    UpdateCursorLocation();
210  }
211}
212
213void MirrorWindowController::SetMirroredCursorVisibility(bool visible) {
214  if (cursor_window_)
215    visible ? cursor_window_->Show() : cursor_window_->Hide();
216}
217
218}  // namespace internal
219}  // namespace ash
220