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 26 namespace aura { 27 28 const char kWindowTreeHostForAcceleratedWidget[] = 29 "__AURA_WINDOW_TREE_HOST_ACCELERATED_WIDGET__"; 30 31 float 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 41 WindowTreeHost::~WindowTreeHost() { 42 DCHECK(!compositor_) << "compositor must be destroyed before root window"; 43 } 44 45 #if defined(OS_ANDROID) 46 // static 47 WindowTreeHost* 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 57 WindowTreeHost* WindowTreeHost::GetForAcceleratedWidget( 58 gfx::AcceleratedWidget widget) { 59 return reinterpret_cast<WindowTreeHost*>( 60 ui::ViewProp::GetValue(widget, kWindowTreeHostForAcceleratedWidget)); 61 } 62 63 void WindowTreeHost::InitHost() { 64 InitCompositor(); 65 UpdateRootWindowSize(GetBounds().size()); 66 Env::GetInstance()->NotifyHostInitialized(this); 67 window()->Show(); 68 } 69 70 void WindowTreeHost::InitCompositor() { 71 compositor_->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(window()), 72 GetBounds().size()); 73 compositor_->SetRootLayer(window()->layer()); 74 } 75 76 void WindowTreeHost::AddObserver(WindowTreeHostObserver* observer) { 77 observers_.AddObserver(observer); 78 } 79 80 void WindowTreeHost::RemoveObserver(WindowTreeHostObserver* observer) { 81 observers_.RemoveObserver(observer); 82 } 83 84 ui::EventProcessor* WindowTreeHost::event_processor() { 85 return dispatcher(); 86 } 87 88 gfx::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 96 void WindowTreeHost::SetRootTransform(const gfx::Transform& transform) { 97 window()->SetTransform(transform); 98 UpdateRootWindowSize(GetBounds().size()); 99 } 100 101 gfx::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 109 void 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 116 void WindowTreeHost::ConvertPointToNativeScreen(gfx::Point* point) const { 117 ConvertPointToHost(point); 118 gfx::Point location = GetLocationOnNativeScreen(); 119 point->Offset(location.x(), location.y()); 120 } 121 122 void WindowTreeHost::ConvertPointFromNativeScreen(gfx::Point* point) const { 123 gfx::Point location = GetLocationOnNativeScreen(); 124 point->Offset(-location.x(), -location.y()); 125 ConvertPointFromHost(point); 126 } 127 128 void 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 134 void 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 140 void 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 147 void 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 160 void 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 166 void 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 175 WindowTreeHost::WindowTreeHost() 176 : window_(new Window(NULL)), 177 last_cursor_(ui::kCursorNull) { 178 } 179 180 void WindowTreeHost::DestroyCompositor() { 181 compositor_.reset(); 182 } 183 184 void WindowTreeHost::DestroyDispatcher() { 185 delete window_; 186 window_ = NULL; 187 dispatcher_.reset(); 188 189 // TODO(beng): this comment is no longer quite valid since this function 190 // isn't called from WED, and WED isn't a subclass of Window. So it seems 191 // like we could just rely on ~Window now. 192 // Destroy child windows while we're still valid. This is also done by 193 // ~Window, but by that time any calls to virtual methods overriden here (such 194 // as GetRootWindow()) result in Window's implementation. By destroying here 195 // we ensure GetRootWindow() still returns this. 196 //window()->RemoveOrDestroyChildren(); 197 } 198 199 void WindowTreeHost::CreateCompositor( 200 gfx::AcceleratedWidget accelerated_widget) { 201 DCHECK(Env::GetInstance()); 202 ui::ContextFactory* context_factory = Env::GetInstance()->context_factory(); 203 DCHECK(context_factory); 204 compositor_.reset( 205 new ui::Compositor(GetAcceleratedWidget(), context_factory)); 206 // TODO(beng): I think this setup should probably all move to a "accelerated 207 // widget available" function. 208 if (!dispatcher()) { 209 window()->Init(WINDOW_LAYER_NOT_DRAWN); 210 window()->set_host(this); 211 window()->SetName("RootWindow"); 212 window()->SetEventTargeter( 213 scoped_ptr<ui::EventTargeter>(new WindowTargeter())); 214 prop_.reset(new ui::ViewProp(GetAcceleratedWidget(), 215 kWindowTreeHostForAcceleratedWidget, 216 this)); 217 dispatcher_.reset(new WindowEventDispatcher(this)); 218 } 219 } 220 221 void WindowTreeHost::OnHostMoved(const gfx::Point& new_location) { 222 TRACE_EVENT1("ui", "WindowTreeHost::OnHostMoved", 223 "origin", new_location.ToString()); 224 225 FOR_EACH_OBSERVER(WindowTreeHostObserver, observers_, 226 OnHostMoved(this, new_location)); 227 } 228 229 void WindowTreeHost::OnHostResized(const gfx::Size& new_size) { 230 // The compositor should have the same size as the native root window host. 231 // Get the latest scale from display because it might have been changed. 232 compositor_->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(window()), 233 new_size); 234 235 gfx::Size layer_size = GetBounds().size(); 236 // The layer, and the observers should be notified of the 237 // transformed size of the root window. 238 UpdateRootWindowSize(layer_size); 239 FOR_EACH_OBSERVER(WindowTreeHostObserver, observers_, OnHostResized(this)); 240 } 241 242 void WindowTreeHost::OnHostCloseRequested() { 243 FOR_EACH_OBSERVER(WindowTreeHostObserver, observers_, 244 OnHostCloseRequested(this)); 245 } 246 247 void WindowTreeHost::OnHostActivated() { 248 Env::GetInstance()->NotifyHostActivated(this); 249 } 250 251 void WindowTreeHost::OnHostLostWindowCapture() { 252 Window* capture_window = client::GetCaptureWindow(window()); 253 if (capture_window && capture_window->GetRootWindow() == window()) 254 capture_window->ReleaseCapture(); 255 } 256 257 //////////////////////////////////////////////////////////////////////////////// 258 // WindowTreeHost, private: 259 260 void WindowTreeHost::MoveCursorToInternal(const gfx::Point& root_location, 261 const gfx::Point& host_location) { 262 last_cursor_request_position_in_host_ = host_location; 263 MoveCursorToNative(host_location); 264 client::CursorClient* cursor_client = client::GetCursorClient(window()); 265 if (cursor_client) { 266 const gfx::Display& display = 267 gfx::Screen::GetScreenFor(window())->GetDisplayNearestWindow(window()); 268 cursor_client->SetDisplay(display); 269 } 270 dispatcher()->OnCursorMovedToRootLocation(root_location); 271 } 272 273 } // namespace aura 274