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