Home | History | Annotate | Download | only in aura
      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