Home | History | Annotate | Download | only in screen
      1 // Copyright 2014 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 "athena/screen/public/screen_manager.h"
      6 
      7 #include "athena/input/public/accelerator_manager.h"
      8 #include "athena/screen/screen_accelerator_handler.h"
      9 #include "athena/util/container_priorities.h"
     10 #include "athena/util/fill_layout_manager.h"
     11 #include "base/logging.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "ui/aura/client/screen_position_client.h"
     14 #include "ui/aura/client/window_tree_client.h"
     15 #include "ui/aura/layout_manager.h"
     16 #include "ui/aura/test/test_screen.h"
     17 #include "ui/aura/window.h"
     18 #include "ui/aura/window_property.h"
     19 #include "ui/aura/window_targeter.h"
     20 #include "ui/aura/window_tree_host.h"
     21 #include "ui/compositor/layer.h"
     22 #include "ui/gfx/display.h"
     23 #include "ui/gfx/screen.h"
     24 #include "ui/wm/core/base_focus_rules.h"
     25 #include "ui/wm/core/capture_controller.h"
     26 #include "ui/wm/core/focus_controller.h"
     27 #include "ui/wm/core/window_util.h"
     28 
     29 namespace athena {
     30 namespace {
     31 
     32 DEFINE_OWNED_WINDOW_PROPERTY_KEY(ScreenManager::ContainerParams,
     33                                  kContainerParamsKey,
     34                                  NULL);
     35 
     36 ScreenManager* instance = NULL;
     37 
     38 bool GrabsInput(aura::Window* container) {
     39   ScreenManager::ContainerParams* params =
     40       container->GetProperty(kContainerParamsKey);
     41   return params && params->grab_inputs;
     42 }
     43 
     44 // Returns the container which contains |window|.
     45 aura::Window* GetContainer(aura::Window* window) {
     46   aura::Window* container = window;
     47   while (container && !container->GetProperty(kContainerParamsKey))
     48     container = container->parent();
     49   return container;
     50 }
     51 
     52 class AthenaFocusRules : public wm::BaseFocusRules {
     53  public:
     54   AthenaFocusRules() {}
     55   virtual ~AthenaFocusRules() {}
     56 
     57   // wm::BaseFocusRules:
     58   virtual bool SupportsChildActivation(aura::Window* window) const OVERRIDE {
     59     ScreenManager::ContainerParams* params =
     60         window->GetProperty(kContainerParamsKey);
     61     return params && params->can_activate_children;
     62   }
     63   virtual bool CanActivateWindow(aura::Window* window) const OVERRIDE {
     64     // Check if containers of higher z-order than |window| have 'grab_inputs'
     65     // fields.
     66     if (window) {
     67       const aura::Window::Windows& containers =
     68           window->GetRootWindow()->children();
     69       aura::Window::Windows::const_iterator iter =
     70           std::find(containers.begin(), containers.end(), GetContainer(window));
     71       DCHECK(iter != containers.end());
     72       for (++iter; iter != containers.end(); ++iter) {
     73         if (GrabsInput(*iter))
     74           return false;
     75       }
     76     }
     77     return BaseFocusRules::CanActivateWindow(window);
     78   }
     79 
     80  private:
     81   DISALLOW_COPY_AND_ASSIGN(AthenaFocusRules);
     82 };
     83 
     84 class AthenaWindowTreeClient : public aura::client::WindowTreeClient {
     85  public:
     86   explicit AthenaWindowTreeClient(aura::Window* container)
     87       : container_(container) {}
     88 
     89  private:
     90   virtual ~AthenaWindowTreeClient() {}
     91 
     92   // aura::client::WindowTreeClient:
     93   virtual aura::Window* GetDefaultParent(aura::Window* context,
     94                                          aura::Window* window,
     95                                          const gfx::Rect& bounds) OVERRIDE {
     96     aura::Window* transient_parent = wm::GetTransientParent(window);
     97     if (transient_parent)
     98       return GetContainer(transient_parent);
     99     return container_;
    100   }
    101 
    102   aura::Window* container_;
    103 
    104   DISALLOW_COPY_AND_ASSIGN(AthenaWindowTreeClient);
    105 };
    106 
    107 class AthenaScreenPositionClient : public aura::client::ScreenPositionClient {
    108  public:
    109   AthenaScreenPositionClient() {
    110   }
    111   virtual ~AthenaScreenPositionClient() {
    112   }
    113 
    114  private:
    115   // aura::client::ScreenPositionClient:
    116   virtual void ConvertPointToScreen(const aura::Window* window,
    117                                     gfx::Point* point) OVERRIDE {
    118     const aura::Window* root = window->GetRootWindow();
    119     aura::Window::ConvertPointToTarget(window, root, point);
    120   }
    121 
    122   virtual void ConvertPointFromScreen(const aura::Window* window,
    123                                       gfx::Point* point) OVERRIDE {
    124     const aura::Window* root = window->GetRootWindow();
    125     aura::Window::ConvertPointToTarget(root, window, point);
    126   }
    127 
    128   virtual void ConvertHostPointToScreen(aura::Window* window,
    129                                         gfx::Point* point) OVERRIDE {
    130     // TODO(oshima): Implement this when adding multiple display support.
    131     NOTREACHED();
    132   }
    133 
    134   virtual void SetBounds(aura::Window* window,
    135                          const gfx::Rect& bounds,
    136                          const gfx::Display& display) OVERRIDE {
    137     window->SetBounds(bounds);
    138   }
    139 
    140   DISALLOW_COPY_AND_ASSIGN(AthenaScreenPositionClient);
    141 };
    142 
    143 class AthenaEventTargeter : public aura::WindowTargeter,
    144                             public aura::WindowObserver {
    145  public:
    146   explicit AthenaEventTargeter(aura::Window* container)
    147       : container_(container) {
    148     container_->AddObserver(this);
    149   }
    150 
    151   virtual ~AthenaEventTargeter() {
    152     // Removed before the container is removed.
    153     if (container_)
    154       container_->RemoveObserver(this);
    155   }
    156 
    157  private:
    158   // aura::WindowTargeter:
    159   virtual bool SubtreeCanAcceptEvent(
    160       ui::EventTarget* target,
    161       const ui::LocatedEvent& event) const OVERRIDE {
    162     aura::Window* window = static_cast<aura::Window*>(target);
    163     const aura::Window::Windows& containers =
    164         container_->GetRootWindow()->children();
    165     aura::Window::Windows::const_iterator iter =
    166         std::find(containers.begin(), containers.end(), container_);
    167     DCHECK(iter != containers.end());
    168     for (; iter != containers.end(); ++iter) {
    169       if ((*iter)->Contains(window))
    170         return true;
    171     }
    172     return false;
    173   }
    174 
    175   // aura::WindowObserver:
    176   virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
    177     aura::Window* root_window = container_->GetRootWindow();
    178     DCHECK_EQ(window, container_);
    179     DCHECK_EQ(
    180         this, static_cast<ui::EventTarget*>(root_window)->GetEventTargeter());
    181 
    182     container_->RemoveObserver(this);
    183     container_ = NULL;
    184 
    185     // This will remove myself.
    186     root_window->SetEventTargeter(scoped_ptr<ui::EventTargeter>());
    187   }
    188 
    189   aura::Window* container_;
    190 
    191   DISALLOW_COPY_AND_ASSIGN(AthenaEventTargeter);
    192 };
    193 
    194 class ScreenManagerImpl : public ScreenManager {
    195  public:
    196   explicit ScreenManagerImpl(aura::Window* root_window);
    197   virtual ~ScreenManagerImpl();
    198 
    199   void Init();
    200 
    201  private:
    202   // ScreenManager:
    203   virtual aura::Window* CreateDefaultContainer(
    204       const ContainerParams& params) OVERRIDE;
    205   virtual aura::Window* CreateContainer(const ContainerParams& params) OVERRIDE;
    206   virtual aura::Window* GetContext() OVERRIDE { return root_window_; }
    207   virtual void SetRotation(gfx::Display::Rotation rotation) OVERRIDE;
    208   virtual void SetRotationLocked(bool rotation_locked) OVERRIDE;
    209 
    210   // Not owned.
    211   aura::Window* root_window_;
    212 
    213   scoped_ptr<aura::client::FocusClient> focus_client_;
    214   scoped_ptr<aura::client::WindowTreeClient> window_tree_client_;
    215   scoped_ptr<AcceleratorHandler> accelerator_handler_;
    216   scoped_ptr< ::wm::ScopedCaptureClient> capture_client_;
    217   scoped_ptr<aura::client::ScreenPositionClient> screen_position_client_;
    218 
    219   gfx::Display::Rotation last_requested_rotation_;
    220   bool rotation_locked_;
    221 
    222   DISALLOW_COPY_AND_ASSIGN(ScreenManagerImpl);
    223 };
    224 
    225 ScreenManagerImpl::ScreenManagerImpl(aura::Window* root_window)
    226     : root_window_(root_window),
    227       last_requested_rotation_(gfx::Display::ROTATE_0),
    228       rotation_locked_(false) {
    229   DCHECK(root_window_);
    230   DCHECK(!instance);
    231   instance = this;
    232 }
    233 
    234 ScreenManagerImpl::~ScreenManagerImpl() {
    235   aura::client::SetScreenPositionClient(root_window_, NULL);
    236   aura::client::SetWindowTreeClient(root_window_, NULL);
    237   wm::FocusController* focus_controller =
    238       static_cast<wm::FocusController*>(focus_client_.get());
    239   root_window_->RemovePreTargetHandler(focus_controller);
    240   aura::client::SetActivationClient(root_window_, NULL);
    241   aura::client::SetFocusClient(root_window_, NULL);
    242   aura::Window::Windows children = root_window_->children();
    243   // Close All children:
    244   for (aura::Window::Windows::iterator iter = children.begin();
    245        iter != children.end();
    246        ++iter) {
    247     delete *iter;
    248   }
    249   instance = NULL;
    250 }
    251 
    252 void ScreenManagerImpl::Init() {
    253   wm::FocusController* focus_controller =
    254       new wm::FocusController(new AthenaFocusRules());
    255 
    256   aura::client::SetFocusClient(root_window_, focus_controller);
    257   root_window_->AddPreTargetHandler(focus_controller);
    258   aura::client::SetActivationClient(root_window_, focus_controller);
    259   focus_client_.reset(focus_controller);
    260 
    261   root_window_->SetLayoutManager(new FillLayoutManager(root_window_));
    262   capture_client_.reset(new ::wm::ScopedCaptureClient(root_window_));
    263   accelerator_handler_.reset(new ScreenAcceleratorHandler(root_window_));
    264 }
    265 
    266 aura::Window* ScreenManagerImpl::CreateDefaultContainer(
    267     const ContainerParams& params) {
    268   aura::Window* container = CreateContainer(params);
    269   window_tree_client_.reset(new AthenaWindowTreeClient(container));
    270   aura::client::SetWindowTreeClient(root_window_, window_tree_client_.get());
    271 
    272   screen_position_client_.reset(new AthenaScreenPositionClient());
    273   aura::client::SetScreenPositionClient(root_window_,
    274                                         screen_position_client_.get());
    275 
    276   return container;
    277 }
    278 
    279 // A functor to find a container that has the higher priority.
    280 struct HigherPriorityFinder {
    281   HigherPriorityFinder(int p) : priority(p) {}
    282   bool operator()(aura::Window* window) {
    283     return window->GetProperty(kContainerParamsKey)->z_order_priority >
    284            priority;
    285   }
    286   int priority;
    287 };
    288 
    289 #if !defined(NDEBUG)
    290 struct PriorityMatcher {
    291   PriorityMatcher(int p) : priority(p) {}
    292   bool operator()(aura::Window* window) {
    293     return window->GetProperty(kContainerParamsKey)->z_order_priority ==
    294            priority;
    295   }
    296   int priority;
    297 };
    298 #endif
    299 
    300 aura::Window* ScreenManagerImpl::CreateContainer(
    301     const ContainerParams& params) {
    302   aura::Window* container = new aura::Window(NULL);
    303   CHECK_GE(params.z_order_priority, 0);
    304   container->Init(aura::WINDOW_LAYER_NOT_DRAWN);
    305   container->SetName(params.name);
    306 
    307   const aura::Window::Windows& children = root_window_->children();
    308 
    309 #if !defined(NDEBUG)
    310   DCHECK(std::find_if(children.begin(),
    311                       children.end(),
    312                       PriorityMatcher(params.z_order_priority))
    313          == children.end())
    314       << "The container with the priority "
    315       << params.z_order_priority << " already exists.";
    316 #endif
    317 
    318   container->SetProperty(kContainerParamsKey, new ContainerParams(params));
    319 
    320   // If another container is already grabbing the input, SetEventTargeter
    321   // implicitly release the grabbing and remove the EventTargeter instance.
    322   // TODO(mukai|oshima): think about the ideal behavior of multiple grabbing
    323   // and implement it.
    324   if (params.grab_inputs) {
    325     DCHECK(std::find_if(children.begin(), children.end(), &GrabsInput)
    326            == children.end())
    327         << "input has already been grabbed by another container";
    328     root_window_->SetEventTargeter(
    329         scoped_ptr<ui::EventTargeter>(new AthenaEventTargeter(container)));
    330   }
    331 
    332   root_window_->AddChild(container);
    333 
    334   aura::Window::Windows::const_iterator iter =
    335       std::find_if(children.begin(),
    336                    children.end(),
    337                    HigherPriorityFinder(params.z_order_priority));
    338   if (iter != children.end())
    339     root_window_->StackChildBelow(container, *iter);
    340 
    341   container->Show();
    342   return container;
    343 }
    344 
    345 void ScreenManagerImpl::SetRotation(gfx::Display::Rotation rotation) {
    346   last_requested_rotation_ = rotation;
    347   if (rotation_locked_ || rotation ==
    348       gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().rotation()) {
    349     return;
    350   }
    351 
    352   // TODO(flackr): Use display manager to update display rotation:
    353   // http://crbug.com/401044.
    354   static_cast<aura::TestScreen*>(gfx::Screen::GetNativeScreen())->
    355       SetDisplayRotation(rotation);
    356 }
    357 
    358 void ScreenManagerImpl::SetRotationLocked(bool rotation_locked) {
    359   rotation_locked_ = rotation_locked;
    360   if (!rotation_locked_)
    361     SetRotation(last_requested_rotation_);
    362 }
    363 
    364 }  // namespace
    365 
    366 ScreenManager::ContainerParams::ContainerParams(const std::string& n,
    367                                                 int priority)
    368     : name(n),
    369       can_activate_children(false),
    370       grab_inputs(false),
    371       z_order_priority(priority) {
    372 }
    373 
    374 // static
    375 ScreenManager* ScreenManager::Create(aura::Window* root_window) {
    376   (new ScreenManagerImpl(root_window))->Init();
    377   DCHECK(instance);
    378   return instance;
    379 }
    380 
    381 // static
    382 ScreenManager* ScreenManager::Get() {
    383   DCHECK(instance);
    384   return instance;
    385 }
    386 
    387 // static
    388 void ScreenManager::Shutdown() {
    389   DCHECK(instance);
    390   delete instance;
    391   DCHECK(!instance);
    392 }
    393 
    394 }  // namespace athena
    395