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 "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