Home | History | Annotate | Download | only in widget
      1 // Copyright 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/views/widget/window_reorderer.h"
      6 
      7 #include <map>
      8 #include <vector>
      9 
     10 #include "ui/aura/window.h"
     11 #include "ui/views/view.h"
     12 #include "ui/views/view_constants_aura.h"
     13 
     14 namespace views {
     15 
     16 namespace {
     17 
     18 // Sets |hosted_windows| to a mapping of the views with an associated window to
     19 // the window that they are associated to. Only views associated to a child of
     20 // |parent_window| are returned.
     21 void GetViewsWithAssociatedWindow(
     22     const aura::Window& parent_window,
     23     std::map<views::View*, aura::Window*>* hosted_windows) {
     24   const std::vector<aura::Window*>& child_windows = parent_window.children();
     25   for (size_t i = 0; i < child_windows.size(); ++i) {
     26     aura::Window* child = child_windows[i];
     27     View* host_view = child->GetProperty(kHostViewKey);
     28     if (host_view)
     29       (*hosted_windows)[host_view] = child;
     30   }
     31 }
     32 
     33 // Sets |order| to the list of views whose layer / associated window's layer
     34 // is a child of |parent_layer|. |order| is sorted in ascending z-order of
     35 // the views.
     36 // |hosts| are the views with an associated window whose layer is a child of
     37 // |parent_layer|.
     38 void GetOrderOfViewsWithLayers(
     39     views::View* view,
     40     ui::Layer* parent_layer,
     41     const std::map<views::View*, aura::Window*>& hosts,
     42     std::vector<views::View*>* order) {
     43   DCHECK(view);
     44   DCHECK(parent_layer);
     45   DCHECK(order);
     46   if (view->layer() && view->layer()->parent() == parent_layer) {
     47     order->push_back(view);
     48     // |hosts| may contain a child of |view|.
     49   } else if (hosts.find(view) != hosts.end()) {
     50     order->push_back(view);
     51   }
     52 
     53   for (int i = 0; i < view->child_count(); ++i)
     54     GetOrderOfViewsWithLayers(view->child_at(i), parent_layer, hosts, order);
     55 }
     56 
     57 }  // namespace
     58 
     59 // Class which reorders windows as a result of the kHostViewKey property being
     60 // set on the window.
     61 class WindowReorderer::AssociationObserver : public aura::WindowObserver {
     62  public:
     63   explicit AssociationObserver(WindowReorderer* reorderer);
     64   virtual ~AssociationObserver();
     65 
     66   // Start/stop observing changes in the kHostViewKey property on |window|.
     67   void StartObserving(aura::Window* window);
     68   void StopObserving(aura::Window* window);
     69 
     70  private:
     71   // aura::WindowObserver overrides:
     72   virtual void OnWindowPropertyChanged(aura::Window* window,
     73                                       const void* key,
     74                                       intptr_t old) OVERRIDE;
     75   virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
     76 
     77   // Not owned.
     78   WindowReorderer* reorderer_;
     79 
     80   std::set<aura::Window*> windows_;
     81 
     82   DISALLOW_COPY_AND_ASSIGN(AssociationObserver);
     83 };
     84 
     85 WindowReorderer::AssociationObserver::AssociationObserver(
     86     WindowReorderer* reorderer)
     87     : reorderer_(reorderer) {
     88 }
     89 
     90 WindowReorderer::AssociationObserver::~AssociationObserver() {
     91   while (!windows_.empty())
     92     StopObserving(*windows_.begin());
     93 }
     94 
     95 void WindowReorderer::AssociationObserver::StartObserving(
     96     aura::Window* window) {
     97   windows_.insert(window);
     98   window->AddObserver(this);
     99 }
    100 
    101 void WindowReorderer::AssociationObserver::StopObserving(
    102     aura::Window* window) {
    103   windows_.erase(window);
    104   window->RemoveObserver(this);
    105 }
    106 
    107 void WindowReorderer::AssociationObserver::OnWindowPropertyChanged(
    108     aura::Window* window,
    109     const void* key,
    110     intptr_t old) {
    111   if (key == kHostViewKey)
    112     reorderer_->ReorderChildWindows();
    113 }
    114 
    115 void WindowReorderer::AssociationObserver::OnWindowDestroying(
    116     aura::Window* window) {
    117   windows_.erase(window);
    118   window->RemoveObserver(this);
    119 }
    120 
    121 WindowReorderer::WindowReorderer(aura::Window* parent_window,
    122                                  View* root_view)
    123     : parent_window_(parent_window),
    124       root_view_(root_view),
    125       association_observer_(new AssociationObserver(this)) {
    126   parent_window_->AddObserver(this);
    127   const std::vector<aura::Window*>& windows = parent_window_->children();
    128   for (size_t i = 0; i < windows.size(); ++i)
    129     association_observer_->StartObserving(windows[i]);
    130   ReorderChildWindows();
    131 }
    132 
    133 WindowReorderer::~WindowReorderer() {
    134   if (parent_window_) {
    135     parent_window_->RemoveObserver(this);
    136     // |association_observer_| stops observing any windows it is observing upon
    137     // destruction.
    138   }
    139 }
    140 
    141 void WindowReorderer::ReorderChildWindows() {
    142   if (!parent_window_)
    143     return;
    144 
    145   std::map<View*, aura::Window*> hosted_windows;
    146   GetViewsWithAssociatedWindow(*parent_window_, &hosted_windows);
    147 
    148   if (hosted_windows.empty()) {
    149     // Exit early if there are no views with associated windows.
    150     // View::ReorderLayers() should have already reordered the layers owned by
    151     // views.
    152     return;
    153   }
    154 
    155   // Compute the desired z-order of the layers based on the order of the views
    156   // with layers and views with associated windows in the view tree.
    157   std::vector<View*> view_with_layer_order;
    158   GetOrderOfViewsWithLayers(root_view_, parent_window_->layer(), hosted_windows,
    159       &view_with_layer_order);
    160 
    161   // For the sake of simplicity, reorder both the layers owned by views and the
    162   // layers of windows associated with a view. Iterate through
    163   // |view_with_layer_order| backwards and stack windows at the bottom so that
    164   // windows not associated to a view are stacked above windows with an
    165   // associated view.
    166   for (std::vector<View*>::reverse_iterator it = view_with_layer_order.rbegin();
    167        it != view_with_layer_order.rend(); ++it) {
    168     View* view = *it;
    169     ui::Layer* layer = view->layer();
    170     aura::Window* window = NULL;
    171 
    172     std::map<View*, aura::Window*>::iterator hosted_window_it =
    173         hosted_windows.find(view);
    174     if (hosted_window_it != hosted_windows.end()) {
    175       window = hosted_window_it->second;
    176       layer = window->layer();
    177     }
    178 
    179     DCHECK(layer);
    180     if (window)
    181       parent_window_->StackChildAtBottom(window);
    182     parent_window_->layer()->StackAtBottom(layer);
    183   }
    184 }
    185 
    186 void WindowReorderer::OnWindowAdded(aura::Window* new_window) {
    187   association_observer_->StartObserving(new_window);
    188   ReorderChildWindows();
    189 }
    190 
    191 void WindowReorderer::OnWillRemoveWindow(aura::Window* window) {
    192   association_observer_->StopObserving(window);
    193 }
    194 
    195 void WindowReorderer::OnWindowDestroying(aura::Window* window) {
    196   parent_window_->RemoveObserver(this);
    197   parent_window_ = NULL;
    198   association_observer_.reset();
    199 }
    200 
    201 }  // namespace views
    202