• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
GetViewsWithAssociatedWindow(const aura::Window & parent_window,std::map<views::View *,aura::Window * > * hosted_windows)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|.
GetOrderOfViewsWithLayers(views::View * view,ui::Layer * parent_layer,const std::map<views::View *,aura::Window * > & hosts,std::vector<views::View * > * order)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 
AssociationObserver(WindowReorderer * reorderer)85 WindowReorderer::AssociationObserver::AssociationObserver(
86     WindowReorderer* reorderer)
87     : reorderer_(reorderer) {
88 }
89 
~AssociationObserver()90 WindowReorderer::AssociationObserver::~AssociationObserver() {
91   while (!windows_.empty())
92     StopObserving(*windows_.begin());
93 }
94 
StartObserving(aura::Window * window)95 void WindowReorderer::AssociationObserver::StartObserving(
96     aura::Window* window) {
97   windows_.insert(window);
98   window->AddObserver(this);
99 }
100 
StopObserving(aura::Window * window)101 void WindowReorderer::AssociationObserver::StopObserving(
102     aura::Window* window) {
103   windows_.erase(window);
104   window->RemoveObserver(this);
105 }
106 
OnWindowPropertyChanged(aura::Window * window,const void * key,intptr_t old)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 
OnWindowDestroying(aura::Window * window)115 void WindowReorderer::AssociationObserver::OnWindowDestroying(
116     aura::Window* window) {
117   windows_.erase(window);
118   window->RemoveObserver(this);
119 }
120 
WindowReorderer(aura::Window * parent_window,View * root_view)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 
~WindowReorderer()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 
ReorderChildWindows()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 
OnWindowAdded(aura::Window * new_window)186 void WindowReorderer::OnWindowAdded(aura::Window* new_window) {
187   association_observer_->StartObserving(new_window);
188   ReorderChildWindows();
189 }
190 
OnWillRemoveWindow(aura::Window * window)191 void WindowReorderer::OnWillRemoveWindow(aura::Window* window) {
192   association_observer_->StopObserving(window);
193 }
194 
OnWindowDestroying(aura::Window * window)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