Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ui / wm / core / shadow_controller.cc
1 // Copyright (c) 2012 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/shadow_controller.h"
6
7 #include <utility>
8
9 #include "base/command_line.h"
10 #include "base/logging.h"
11 #include "base/memory/linked_ptr.h"
12 #include "base/scoped_observer.h"
13 #include "ui/aura/env.h"
14 #include "ui/aura/env_observer.h"
15 #include "ui/aura/window.h"
16 #include "ui/aura/window_observer.h"
17 #include "ui/compositor/layer.h"
18 #include "ui/wm/core/shadow.h"
19 #include "ui/wm/core/shadow_types.h"
20 #include "ui/wm/core/window_util.h"
21 #include "ui/wm/public/activation_client.h"
22
23 using std::make_pair;
24
25 namespace wm {
26
27 namespace {
28
29 ShadowType GetShadowTypeFromWindow(aura::Window* window) {
30   switch (window->type()) {
31     case ui::wm::WINDOW_TYPE_NORMAL:
32     case ui::wm::WINDOW_TYPE_PANEL:
33     case ui::wm::WINDOW_TYPE_MENU:
34     case ui::wm::WINDOW_TYPE_TOOLTIP:
35       return SHADOW_TYPE_RECTANGULAR;
36     default:
37       break;
38   }
39   return SHADOW_TYPE_NONE;
40 }
41
42 bool ShouldUseSmallShadowForWindow(aura::Window* window) {
43   switch (window->type()) {
44     case ui::wm::WINDOW_TYPE_MENU:
45     case ui::wm::WINDOW_TYPE_TOOLTIP:
46       return true;
47     default:
48       break;
49   }
50   return false;
51 }
52
53 bool IsShadowAlwaysActive(aura::Window* window) {
54   return GetShadowType(window) == SHADOW_TYPE_RECTANGULAR_ALWAYS_ACTIVE;
55 }
56
57 Shadow::Style GetShadowStyleForWindow(aura::Window* window) {
58   return ShouldUseSmallShadowForWindow(window) ? Shadow::STYLE_SMALL :
59       ((IsActiveWindow(window) || IsShadowAlwaysActive(window)) ?
60        Shadow::STYLE_ACTIVE : Shadow::STYLE_INACTIVE);
61 }
62
63 // Returns the shadow style to be applied to |losing_active| when it is losing
64 // active to |gaining_active|. |gaining_active| may be of a type that hides when
65 // inactive, and as such we do not want to render |losing_active| as inactive.
66 Shadow::Style GetShadowStyleForWindowLosingActive(
67     aura::Window* losing_active,
68     aura::Window* gaining_active) {
69   if (IsShadowAlwaysActive(losing_active))
70     return Shadow::STYLE_ACTIVE;
71
72   if (gaining_active && aura::client::GetHideOnDeactivate(gaining_active)) {
73     aura::Window::Windows::const_iterator it =
74         std::find(GetTransientChildren(losing_active).begin(),
75                   GetTransientChildren(losing_active).end(),
76                   gaining_active);
77     if (it != GetTransientChildren(losing_active).end())
78       return Shadow::STYLE_ACTIVE;
79   }
80   return Shadow::STYLE_INACTIVE;
81 }
82
83 }  // namespace
84
85 // ShadowController::Impl ------------------------------------------------------
86
87 // Real implementation of the ShadowController. ShadowController observes
88 // ActivationChangeObserver, which are per ActivationClient, where as there is
89 // only a single Impl (as it observes all window creation by way of an
90 // EnvObserver).
91 class ShadowController::Impl :
92       public aura::EnvObserver,
93       public aura::WindowObserver,
94       public base::RefCounted<Impl> {
95  public:
96   // Returns the singleton instance, destroyed when there are no more refs.
97   static Impl* GetInstance();
98
99   // aura::EnvObserver override:
100   virtual void OnWindowInitialized(aura::Window* window) OVERRIDE;
101
102   // aura::WindowObserver overrides:
103   virtual void OnWindowPropertyChanged(
104       aura::Window* window, const void* key, intptr_t old) OVERRIDE;
105   virtual void OnWindowBoundsChanged(
106       aura::Window* window,
107       const gfx::Rect& old_bounds,
108       const gfx::Rect& new_bounds) OVERRIDE;
109   virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
110
111  private:
112   friend class base::RefCounted<Impl>;
113   friend class ShadowController;
114   friend class ShadowController::TestApi;
115
116   typedef std::map<aura::Window*, linked_ptr<Shadow> > WindowShadowMap;
117
118   Impl();
119   virtual ~Impl();
120
121   // Forwarded from ShadowController.
122   void OnWindowActivated(aura::Window* gained_active,
123                          aura::Window* lost_active);
124
125   // Checks if |window| is visible and contains a property requesting a shadow.
126   bool ShouldShowShadowForWindow(aura::Window* window) const;
127
128   // Returns |window|'s shadow from |window_shadows_|, or NULL if no shadow
129   // exists.
130   Shadow* GetShadowForWindow(aura::Window* window);
131
132   // Updates the shadow styles for windows when activation changes.
133   void HandleWindowActivationChange(aura::Window* gaining_active,
134                                     aura::Window* losing_active);
135
136   // Shows or hides |window|'s shadow as needed (creating the shadow if
137   // necessary).
138   void HandlePossibleShadowVisibilityChange(aura::Window* window);
139
140   // Creates a new shadow for |window| and stores it in |window_shadows_|.  The
141   // shadow's bounds are initialized and it is added to the window's layer.
142   void CreateShadowForWindow(aura::Window* window);
143
144   WindowShadowMap window_shadows_;
145
146   ScopedObserver<aura::Window, aura::WindowObserver> observer_manager_;
147
148   static Impl* instance_;
149
150   DISALLOW_COPY_AND_ASSIGN(Impl);
151 };
152
153 // static
154 ShadowController::Impl* ShadowController::Impl::instance_ = NULL;
155
156 // static
157 ShadowController::Impl* ShadowController::Impl::GetInstance() {
158   if (!instance_)
159     instance_ = new Impl();
160   return instance_;
161 }
162
163 void ShadowController::Impl::OnWindowInitialized(aura::Window* window) {
164   observer_manager_.Add(window);
165   SetShadowType(window, GetShadowTypeFromWindow(window));
166   HandlePossibleShadowVisibilityChange(window);
167 }
168
169 void ShadowController::Impl::OnWindowPropertyChanged(aura::Window* window,
170                                                      const void* key,
171                                                      intptr_t old) {
172   if (key == kShadowTypeKey) {
173     HandlePossibleShadowVisibilityChange(window);
174     return;
175   }
176 }
177
178 void ShadowController::Impl::OnWindowBoundsChanged(
179     aura::Window* window,
180     const gfx::Rect& old_bounds,
181     const gfx::Rect& new_bounds) {
182   Shadow* shadow = GetShadowForWindow(window);
183   if (shadow)
184     shadow->SetContentBounds(gfx::Rect(new_bounds.size()));
185 }
186
187 void ShadowController::Impl::OnWindowDestroyed(aura::Window* window) {
188   window_shadows_.erase(window);
189   observer_manager_.Remove(window);
190 }
191
192 void ShadowController::Impl::OnWindowActivated(aura::Window* gained_active,
193                                                aura::Window* lost_active) {
194   if (gained_active) {
195     Shadow* shadow = GetShadowForWindow(gained_active);
196     if (shadow && !ShouldUseSmallShadowForWindow(gained_active))
197       shadow->SetStyle(Shadow::STYLE_ACTIVE);
198   }
199   if (lost_active) {
200     Shadow* shadow = GetShadowForWindow(lost_active);
201     if (shadow && !ShouldUseSmallShadowForWindow(lost_active)) {
202       shadow->SetStyle(GetShadowStyleForWindowLosingActive(lost_active,
203                                                            gained_active));
204     }
205   }
206 }
207
208 bool ShadowController::Impl::ShouldShowShadowForWindow(
209     aura::Window* window) const {
210   const ShadowType type = GetShadowType(window);
211   switch (type) {
212     case SHADOW_TYPE_NONE:
213       return false;
214     case SHADOW_TYPE_RECTANGULAR:
215     case SHADOW_TYPE_RECTANGULAR_ALWAYS_ACTIVE:
216       return true;
217     default:
218       NOTREACHED() << "Unknown shadow type " << type;
219       return false;
220   }
221 }
222
223 Shadow* ShadowController::Impl::GetShadowForWindow(aura::Window* window) {
224   WindowShadowMap::const_iterator it = window_shadows_.find(window);
225   return it != window_shadows_.end() ? it->second.get() : NULL;
226 }
227
228 void ShadowController::Impl::HandlePossibleShadowVisibilityChange(
229     aura::Window* window) {
230   const bool should_show = ShouldShowShadowForWindow(window);
231   Shadow* shadow = GetShadowForWindow(window);
232   if (shadow) {
233     shadow->SetStyle(GetShadowStyleForWindow(window));
234     shadow->layer()->SetVisible(should_show);
235   } else if (should_show && !shadow) {
236     CreateShadowForWindow(window);
237   }
238 }
239
240 void ShadowController::Impl::CreateShadowForWindow(aura::Window* window) {
241   linked_ptr<Shadow> shadow(new Shadow());
242   window_shadows_.insert(make_pair(window, shadow));
243   shadow->Init(GetShadowStyleForWindow(window));
244   shadow->SetContentBounds(gfx::Rect(window->bounds().size()));
245   shadow->layer()->SetVisible(ShouldShowShadowForWindow(window));
246   window->layer()->Add(shadow->layer());
247 }
248
249 ShadowController::Impl::Impl()
250     : observer_manager_(this) {
251   aura::Env::GetInstance()->AddObserver(this);
252 }
253
254 ShadowController::Impl::~Impl() {
255   DCHECK_EQ(instance_, this);
256   aura::Env::GetInstance()->RemoveObserver(this);
257   instance_ = NULL;
258 }
259
260 // ShadowController ------------------------------------------------------------
261
262 ShadowController::ShadowController(
263     aura::client::ActivationClient* activation_client)
264     : activation_client_(activation_client),
265       impl_(Impl::GetInstance()) {
266   // Watch for window activation changes.
267   activation_client_->AddObserver(this);
268 }
269
270 ShadowController::~ShadowController() {
271   activation_client_->RemoveObserver(this);
272 }
273
274 void ShadowController::OnWindowActivated(aura::Window* gained_active,
275                                          aura::Window* lost_active) {
276   impl_->OnWindowActivated(gained_active, lost_active);
277 }
278
279 // ShadowController::TestApi ---------------------------------------------------
280
281 Shadow* ShadowController::TestApi::GetShadowForWindow(aura::Window* window) {
282   return controller_->impl_->GetShadowForWindow(window);
283 }
284
285 }  // namespace wm