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