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