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