window_tree_host.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
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 "ui/aura/window_tree_host.h"
6
7#include "base/debug/trace_event.h"
8#include "ui/aura/client/capture_client.h"
9#include "ui/aura/client/cursor_client.h"
10#include "ui/aura/env.h"
11#include "ui/aura/window.h"
12#include "ui/aura/window_event_dispatcher.h"
13#include "ui/aura/window_targeter.h"
14#include "ui/aura/window_tree_host_observer.h"
15#include "ui/base/view_prop.h"
16#include "ui/compositor/dip_util.h"
17#include "ui/compositor/layer.h"
18#include "ui/gfx/display.h"
19#include "ui/gfx/insets.h"
20#include "ui/gfx/point.h"
21#include "ui/gfx/point3_f.h"
22#include "ui/gfx/point_conversions.h"
23#include "ui/gfx/screen.h"
24#include "ui/gfx/size_conversions.h"
25
26namespace aura {
27
28const char kWindowTreeHostForAcceleratedWidget[] =
29    "__AURA_WINDOW_TREE_HOST_ACCELERATED_WIDGET__";
30
31float GetDeviceScaleFactorFromDisplay(Window* window) {
32  gfx::Display display = gfx::Screen::GetScreenFor(window)->
33      GetDisplayNearestWindow(window);
34  DCHECK(display.is_valid());
35  return display.device_scale_factor();
36}
37
38////////////////////////////////////////////////////////////////////////////////
39// WindowTreeHost, public:
40
41WindowTreeHost::~WindowTreeHost() {
42  DCHECK(!compositor_) << "compositor must be destroyed before root window";
43}
44
45#if defined(OS_ANDROID)
46// static
47WindowTreeHost* WindowTreeHost::Create(const gfx::Rect& bounds) {
48  // This is only hit for tests and ash, right now these aren't an issue so
49  // adding the CHECK.
50  // TODO(sky): decide if we want a factory.
51  CHECK(false);
52  return NULL;
53}
54#endif
55
56// static
57WindowTreeHost* WindowTreeHost::GetForAcceleratedWidget(
58    gfx::AcceleratedWidget widget) {
59  return reinterpret_cast<WindowTreeHost*>(
60      ui::ViewProp::GetValue(widget, kWindowTreeHostForAcceleratedWidget));
61}
62
63void WindowTreeHost::InitHost() {
64  InitCompositor();
65  UpdateRootWindowSize(GetBounds().size());
66  Env::GetInstance()->NotifyHostInitialized(this);
67  window()->Show();
68}
69
70void WindowTreeHost::InitCompositor() {
71  compositor_->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(window()),
72                               GetBounds().size());
73  compositor_->SetRootLayer(window()->layer());
74}
75
76void WindowTreeHost::AddObserver(WindowTreeHostObserver* observer) {
77  observers_.AddObserver(observer);
78}
79
80void WindowTreeHost::RemoveObserver(WindowTreeHostObserver* observer) {
81  observers_.RemoveObserver(observer);
82}
83
84ui::EventProcessor* WindowTreeHost::event_processor() {
85  return dispatcher();
86}
87
88gfx::Transform WindowTreeHost::GetRootTransform() const {
89  float scale = ui::GetDeviceScaleFactor(window()->layer());
90  gfx::Transform transform;
91  transform.Scale(scale, scale);
92  transform *= window()->layer()->transform();
93  return transform;
94}
95
96void WindowTreeHost::SetRootTransform(const gfx::Transform& transform) {
97  window()->SetTransform(transform);
98  UpdateRootWindowSize(GetBounds().size());
99}
100
101gfx::Transform WindowTreeHost::GetInverseRootTransform() const {
102  gfx::Transform invert;
103  gfx::Transform transform = GetRootTransform();
104  if (!transform.GetInverse(&invert))
105    return transform;
106  return invert;
107}
108
109void WindowTreeHost::UpdateRootWindowSize(const gfx::Size& host_size) {
110  gfx::Rect bounds(host_size);
111  gfx::RectF new_bounds(ui::ConvertRectToDIP(window()->layer(), bounds));
112  window()->layer()->transform().TransformRect(&new_bounds);
113  window()->SetBounds(gfx::Rect(gfx::ToFlooredSize(new_bounds.size())));
114}
115
116void WindowTreeHost::ConvertPointToNativeScreen(gfx::Point* point) const {
117  ConvertPointToHost(point);
118  gfx::Point location = GetLocationOnNativeScreen();
119  point->Offset(location.x(), location.y());
120}
121
122void WindowTreeHost::ConvertPointFromNativeScreen(gfx::Point* point) const {
123  gfx::Point location = GetLocationOnNativeScreen();
124  point->Offset(-location.x(), -location.y());
125  ConvertPointFromHost(point);
126}
127
128void WindowTreeHost::ConvertPointToHost(gfx::Point* point) const {
129  gfx::Point3F point_3f(*point);
130  GetRootTransform().TransformPoint(&point_3f);
131  *point = gfx::ToFlooredPoint(point_3f.AsPointF());
132}
133
134void WindowTreeHost::ConvertPointFromHost(gfx::Point* point) const {
135  gfx::Point3F point_3f(*point);
136  GetInverseRootTransform().TransformPoint(&point_3f);
137  *point = gfx::ToFlooredPoint(point_3f.AsPointF());
138}
139
140void WindowTreeHost::SetCursor(gfx::NativeCursor cursor) {
141  last_cursor_ = cursor;
142  // A lot of code seems to depend on NULL cursors actually showing an arrow,
143  // so just pass everything along to the host.
144  SetCursorNative(cursor);
145}
146
147void WindowTreeHost::OnCursorVisibilityChanged(bool show) {
148  // Clear any existing mouse hover effects when the cursor becomes invisible.
149  // Note we do not need to dispatch a mouse enter when the cursor becomes
150  // visible because that can only happen in response to a mouse event, which
151  // will trigger its own mouse enter.
152  if (!show) {
153    dispatcher()->DispatchMouseExitAtPoint(
154        dispatcher()->GetLastMouseLocationInRoot());
155  }
156
157  OnCursorVisibilityChangedNative(show);
158}
159
160void WindowTreeHost::MoveCursorTo(const gfx::Point& location_in_dip) {
161  gfx::Point host_location(location_in_dip);
162  ConvertPointToHost(&host_location);
163  MoveCursorToInternal(location_in_dip, host_location);
164}
165
166void WindowTreeHost::MoveCursorToHostLocation(const gfx::Point& host_location) {
167  gfx::Point root_location(host_location);
168  ConvertPointFromHost(&root_location);
169  MoveCursorToInternal(root_location, host_location);
170}
171
172////////////////////////////////////////////////////////////////////////////////
173// WindowTreeHost, protected:
174
175WindowTreeHost::WindowTreeHost()
176    : window_(new Window(NULL)),
177      last_cursor_(ui::kCursorNull) {
178}
179
180void WindowTreeHost::DestroyCompositor() {
181  DCHECK(GetAcceleratedWidget());
182  compositor_.reset();
183}
184
185void WindowTreeHost::DestroyDispatcher() {
186  delete window_;
187  window_ = NULL;
188  dispatcher_.reset();
189
190  // TODO(beng): this comment is no longer quite valid since this function
191  // isn't called from WED, and WED isn't a subclass of Window. So it seems
192  // like we could just rely on ~Window now.
193  // Destroy child windows while we're still valid. This is also done by
194  // ~Window, but by that time any calls to virtual methods overriden here (such
195  // as GetRootWindow()) result in Window's implementation. By destroying here
196  // we ensure GetRootWindow() still returns this.
197  //window()->RemoveOrDestroyChildren();
198}
199
200void WindowTreeHost::CreateCompositor(
201    gfx::AcceleratedWidget accelerated_widget) {
202  compositor_.reset(new ui::Compositor(GetAcceleratedWidget()));
203  DCHECK(compositor_.get());
204  // TODO(beng): I think this setup should probably all move to a "accelerated
205  // widget available" function.
206  if (!dispatcher()) {
207    window()->Init(WINDOW_LAYER_NOT_DRAWN);
208    window()->set_host(this);
209    window()->SetName("RootWindow");
210    window()->SetEventTargeter(
211        scoped_ptr<ui::EventTargeter>(new WindowTargeter()));
212    prop_.reset(new ui::ViewProp(GetAcceleratedWidget(),
213                                 kWindowTreeHostForAcceleratedWidget,
214                                 this));
215    dispatcher_.reset(new WindowEventDispatcher(this));
216  }
217}
218
219void WindowTreeHost::OnHostMoved(const gfx::Point& new_location) {
220  TRACE_EVENT1("ui", "WindowTreeHost::OnHostMoved",
221               "origin", new_location.ToString());
222
223  FOR_EACH_OBSERVER(WindowTreeHostObserver, observers_,
224                    OnHostMoved(this, new_location));
225}
226
227void WindowTreeHost::OnHostResized(const gfx::Size& new_size) {
228  // The compositor should have the same size as the native root window host.
229  // Get the latest scale from display because it might have been changed.
230  compositor_->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(window()),
231                               new_size);
232
233  gfx::Size layer_size = GetBounds().size();
234  // The layer, and the observers should be notified of the
235  // transformed size of the root window.
236  UpdateRootWindowSize(layer_size);
237  FOR_EACH_OBSERVER(WindowTreeHostObserver, observers_, OnHostResized(this));
238}
239
240void WindowTreeHost::OnHostCloseRequested() {
241  FOR_EACH_OBSERVER(WindowTreeHostObserver, observers_,
242                    OnHostCloseRequested(this));
243}
244
245void WindowTreeHost::OnHostActivated() {
246  Env::GetInstance()->NotifyHostActivated(this);
247}
248
249void WindowTreeHost::OnHostLostWindowCapture() {
250  Window* capture_window = client::GetCaptureWindow(window());
251  if (capture_window && capture_window->GetRootWindow() == window())
252    capture_window->ReleaseCapture();
253}
254
255////////////////////////////////////////////////////////////////////////////////
256// WindowTreeHost, private:
257
258void WindowTreeHost::MoveCursorToInternal(const gfx::Point& root_location,
259                                          const gfx::Point& host_location) {
260  last_cursor_request_position_in_host_ = host_location;
261  MoveCursorToNative(host_location);
262  client::CursorClient* cursor_client = client::GetCursorClient(window());
263  if (cursor_client) {
264    const gfx::Display& display =
265        gfx::Screen::GetScreenFor(window())->GetDisplayNearestWindow(window());
266    cursor_client->SetDisplay(display);
267  }
268  dispatcher()->OnCursorMovedToRootLocation(root_location);
269}
270
271}  // namespace aura
272