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