Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ui / wm / core / transient_window_manager.cc
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 "ui/wm/core/transient_window_manager.h"
6
7 #include <algorithm>
8 #include <functional>
9
10 #include "base/auto_reset.h"
11 #include "base/stl_util.h"
12 #include "ui/aura/window.h"
13 #include "ui/aura/window_property.h"
14 #include "ui/wm/core/transient_window_observer.h"
15 #include "ui/wm/core/transient_window_stacking_client.h"
16 #include "ui/wm/core/window_util.h"
17
18 using aura::Window;
19
20 namespace wm {
21
22 DEFINE_OWNED_WINDOW_PROPERTY_KEY(TransientWindowManager, kPropertyKey, NULL);
23
24 TransientWindowManager::~TransientWindowManager() {
25 }
26
27 // static
28 TransientWindowManager* TransientWindowManager::Get(Window* window) {
29   TransientWindowManager* manager = window->GetProperty(kPropertyKey);
30   if (!manager) {
31     manager = new TransientWindowManager(window);
32     window->SetProperty(kPropertyKey, manager);
33   }
34   return manager;
35 }
36
37 // static
38 const TransientWindowManager* TransientWindowManager::Get(
39     const Window* window) {
40   return window->GetProperty(kPropertyKey);
41 }
42
43 void TransientWindowManager::AddObserver(TransientWindowObserver* observer) {
44   observers_.AddObserver(observer);
45 }
46
47 void TransientWindowManager::RemoveObserver(TransientWindowObserver* observer) {
48   observers_.RemoveObserver(observer);
49 }
50
51 void TransientWindowManager::AddTransientChild(Window* child) {
52   // TransientWindowStackingClient does the stacking of transient windows. If it
53   // isn't installed stacking is going to be wrong.
54   DCHECK(TransientWindowStackingClient::instance_);
55
56   TransientWindowManager* child_manager = Get(child);
57   if (child_manager->transient_parent_)
58     Get(child_manager->transient_parent_)->RemoveTransientChild(child);
59   DCHECK(std::find(transient_children_.begin(), transient_children_.end(),
60                    child) == transient_children_.end());
61   transient_children_.push_back(child);
62   child_manager->transient_parent_ = window_;
63
64   // Restack |child| properly above its transient parent, if they share the same
65   // parent.
66   if (child->parent() == window_->parent())
67     RestackTransientDescendants();
68
69   FOR_EACH_OBSERVER(TransientWindowObserver, observers_,
70                     OnTransientChildAdded(window_, child));
71 }
72
73 void TransientWindowManager::RemoveTransientChild(Window* child) {
74   Windows::iterator i =
75       std::find(transient_children_.begin(), transient_children_.end(), child);
76   DCHECK(i != transient_children_.end());
77   transient_children_.erase(i);
78   TransientWindowManager* child_manager = Get(child);
79   DCHECK_EQ(window_, child_manager->transient_parent_);
80   child_manager->transient_parent_ = NULL;
81
82   // If |child| and its former transient parent share the same parent, |child|
83   // should be restacked properly so it is not among transient children of its
84   // former parent, anymore.
85   if (window_->parent() == child->parent())
86     RestackTransientDescendants();
87
88   FOR_EACH_OBSERVER(TransientWindowObserver, observers_,
89                     OnTransientChildRemoved(window_, child));
90 }
91
92 bool TransientWindowManager::IsStackingTransient(
93     const aura::Window* target) const {
94   return stacking_target_ == target;
95 }
96
97 TransientWindowManager::TransientWindowManager(Window* window)
98     : window_(window),
99       transient_parent_(NULL),
100       stacking_target_(NULL) {
101   window_->AddObserver(this);
102 }
103
104 void TransientWindowManager::RestackTransientDescendants() {
105   Window* parent = window_->parent();
106   if (!parent)
107     return;
108
109   // Stack any transient children that share the same parent to be in front of
110   // |window_|. The existing stacking order is preserved by iterating backwards
111   // and always stacking on top.
112   Window::Windows children(parent->children());
113   for (Window::Windows::reverse_iterator it = children.rbegin();
114        it != children.rend(); ++it) {
115     if ((*it) != window_ && HasTransientAncestor(*it, window_)) {
116       TransientWindowManager* descendant_manager = Get(*it);
117       base::AutoReset<Window*> resetter(
118           &descendant_manager->stacking_target_,
119           window_);
120       parent->StackChildAbove((*it), window_);
121     }
122   }
123 }
124
125 void TransientWindowManager::OnWindowParentChanged(aura::Window* window,
126                                                    aura::Window* parent) {
127   DCHECK_EQ(window_, window);
128   // Stack |window| properly if it is transient child of a sibling.
129   Window* transient_parent = wm::GetTransientParent(window);
130   if (transient_parent && transient_parent->parent() == parent) {
131     TransientWindowManager* transient_parent_manager =
132         Get(transient_parent);
133     transient_parent_manager->RestackTransientDescendants();
134   }
135 }
136
137 void TransientWindowManager::OnWindowVisibilityChanging(Window* window,
138                                                         bool visible) {
139   // TODO(sky): move handling of becoming visible here.
140   if (!visible) {
141     std::for_each(transient_children_.begin(), transient_children_.end(),
142                   std::mem_fun(&Window::Hide));
143   }
144 }
145
146 void TransientWindowManager::OnWindowStackingChanged(Window* window) {
147   DCHECK_EQ(window_, window);
148
149   // Do nothing if we initiated the stacking change.
150   const TransientWindowManager* transient_manager =
151       Get(static_cast<const Window*>(window));
152   if (transient_manager && transient_manager->stacking_target_) {
153     Windows::const_iterator window_i = std::find(
154         window->parent()->children().begin(),
155         window->parent()->children().end(),
156         window);
157     DCHECK(window_i != window->parent()->children().end());
158     if (window_i != window->parent()->children().begin() &&
159         (*(window_i - 1) == transient_manager->stacking_target_))
160       return;
161   }
162
163   RestackTransientDescendants();
164 }
165
166 void TransientWindowManager::OnWindowDestroying(Window* window) {
167   // Removes ourselves from our transient parent (if it hasn't been done by the
168   // RootWindow).
169   if (transient_parent_) {
170     TransientWindowManager::Get(transient_parent_)->RemoveTransientChild(
171         window_);
172   }
173
174   // Destroy transient children, only after we've removed ourselves from our
175   // parent, as destroying an active transient child may otherwise attempt to
176   // refocus us.
177   Windows transient_children(transient_children_);
178   STLDeleteElements(&transient_children);
179   DCHECK(transient_children_.empty());
180 }
181
182 }  // namespace wm