Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / athena / wm / window_manager_impl.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 "athena/wm/window_manager_impl.h"
6
7 #include <algorithm>
8
9 #include "athena/screen/public/screen_manager.h"
10 #include "athena/util/container_priorities.h"
11 #include "athena/wm/bezel_controller.h"
12 #include "athena/wm/public/window_manager_observer.h"
13 #include "athena/wm/split_view_controller.h"
14 #include "athena/wm/title_drag_controller.h"
15 #include "athena/wm/window_list_provider_impl.h"
16 #include "athena/wm/window_overview_mode.h"
17 #include "base/bind.h"
18 #include "base/logging.h"
19 #include "ui/aura/layout_manager.h"
20 #include "ui/aura/window.h"
21 #include "ui/compositor/closure_animation_observer.h"
22 #include "ui/compositor/scoped_layer_animation_settings.h"
23 #include "ui/gfx/display.h"
24 #include "ui/gfx/screen.h"
25 #include "ui/wm/core/shadow_controller.h"
26 #include "ui/wm/core/window_util.h"
27 #include "ui/wm/core/wm_state.h"
28 #include "ui/wm/public/activation_client.h"
29 #include "ui/wm/public/window_types.h"
30
31 namespace athena {
32 namespace {
33 class WindowManagerImpl* instance = NULL;
34
35 void SetWindowState(aura::Window* window,
36                     const gfx::Rect& bounds,
37                     const gfx::Transform& transform) {
38   window->SetBounds(bounds);
39   window->SetTransform(transform);
40 }
41
42 }  // namespace
43
44 class AthenaContainerLayoutManager : public aura::LayoutManager {
45  public:
46   AthenaContainerLayoutManager();
47   virtual ~AthenaContainerLayoutManager();
48
49  private:
50   // aura::LayoutManager:
51   virtual void OnWindowResized() OVERRIDE;
52   virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE;
53   virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE;
54   virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE;
55   virtual void OnChildWindowVisibilityChanged(aura::Window* child,
56                                               bool visible) OVERRIDE;
57   virtual void SetChildBounds(aura::Window* child,
58                               const gfx::Rect& requested_bounds) OVERRIDE;
59
60   DISALLOW_COPY_AND_ASSIGN(AthenaContainerLayoutManager);
61 };
62
63 AthenaContainerLayoutManager::AthenaContainerLayoutManager() {
64 }
65
66 AthenaContainerLayoutManager::~AthenaContainerLayoutManager() {
67 }
68
69 void AthenaContainerLayoutManager::OnWindowResized() {
70   // Resize all the existing windows.
71   const aura::Window::Windows& list =
72       instance->window_list_provider_->GetWindowList();
73   const gfx::Size work_area =
74       gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().work_area().size();
75   bool is_splitview = instance->split_view_controller_->IsSplitViewModeActive();
76   gfx::Size split_size;
77   if (is_splitview) {
78     CHECK(instance->split_view_controller_->left_window());
79     split_size =
80         instance->split_view_controller_->left_window()->bounds().size();
81   }
82
83   for (aura::Window::Windows::const_iterator iter = list.begin();
84        iter != list.end();
85        ++iter) {
86     aura::Window* window = *iter;
87     if (is_splitview) {
88       if (window == instance->split_view_controller_->left_window())
89         window->SetBounds(gfx::Rect(split_size));
90       else if (window == instance->split_view_controller_->right_window())
91         window->SetBounds(
92             gfx::Rect(gfx::Point(split_size.width(), 0), split_size));
93       else
94         window->SetBounds(gfx::Rect(work_area));
95     } else {
96       window->SetBounds(gfx::Rect(work_area));
97     }
98   }
99 }
100
101 void AthenaContainerLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
102   if (!instance->window_list_provider_->IsWindowInList(child))
103     return;
104
105   if (instance->split_view_controller_->IsSplitViewModeActive() &&
106       !instance->IsOverviewModeActive()) {
107     instance->split_view_controller_->ReplaceWindow(
108         instance->split_view_controller_->left_window(), child);
109   } else {
110     gfx::Size size =
111         gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().work_area().size();
112     child->SetBounds(gfx::Rect(size));
113   }
114
115   if (instance->IsOverviewModeActive()) {
116     // TODO(pkotwicz|oshima). Creating a new window should only exit overview
117     // mode if the new window is activated. crbug.com/415266
118     instance->OnSelectWindow(child);
119   }
120 }
121
122 void AthenaContainerLayoutManager::OnWillRemoveWindowFromLayout(
123     aura::Window* child) {
124 }
125
126 void AthenaContainerLayoutManager::OnWindowRemovedFromLayout(
127     aura::Window* child) {
128 }
129
130 void AthenaContainerLayoutManager::OnChildWindowVisibilityChanged(
131     aura::Window* child,
132     bool visible) {
133 }
134
135 void AthenaContainerLayoutManager::SetChildBounds(
136     aura::Window* child,
137     const gfx::Rect& requested_bounds) {
138   if (!requested_bounds.IsEmpty())
139     SetChildBoundsDirect(child, requested_bounds);
140 }
141
142 WindowManagerImpl::WindowManagerImpl() {
143   ScreenManager::ContainerParams params("DefaultContainer", CP_DEFAULT);
144   params.can_activate_children = true;
145   container_.reset(ScreenManager::Get()->CreateDefaultContainer(params));
146   container_->SetLayoutManager(new AthenaContainerLayoutManager);
147   container_->AddObserver(this);
148   window_list_provider_.reset(new WindowListProviderImpl(container_.get()));
149   bezel_controller_.reset(new BezelController(container_.get()));
150   split_view_controller_.reset(
151       new SplitViewController(container_.get(), window_list_provider_.get()));
152   AddObserver(split_view_controller_.get());
153   bezel_controller_->set_left_right_delegate(split_view_controller_.get());
154   container_->AddPreTargetHandler(bezel_controller_.get());
155   title_drag_controller_.reset(new TitleDragController(container_.get(), this));
156   wm_state_.reset(new wm::WMState());
157   aura::client::ActivationClient* activation_client =
158       aura::client::GetActivationClient(container_->GetRootWindow());
159   shadow_controller_.reset(new wm::ShadowController(activation_client));
160   instance = this;
161   InstallAccelerators();
162 }
163
164 WindowManagerImpl::~WindowManagerImpl() {
165   overview_.reset();
166   RemoveObserver(split_view_controller_.get());
167   split_view_controller_.reset();
168   window_list_provider_.reset();
169   if (container_) {
170     container_->RemoveObserver(this);
171     container_->RemovePreTargetHandler(bezel_controller_.get());
172   }
173   // |title_drag_controller_| needs to be reset before |container_|.
174   title_drag_controller_.reset();
175   container_.reset();
176   instance = NULL;
177 }
178
179 void WindowManagerImpl::ToggleSplitView() {
180   if (IsOverviewModeActive())
181     return;
182
183   if (split_view_controller_->IsSplitViewModeActive()) {
184     split_view_controller_->DeactivateSplitMode();
185     FOR_EACH_OBSERVER(WindowManagerObserver, observers_, OnSplitViewModeExit());
186     // Relayout so that windows are maximzied.
187     container_->layout_manager()->OnWindowResized();
188   } else if (split_view_controller_->CanActivateSplitViewMode()) {
189     FOR_EACH_OBSERVER(WindowManagerObserver,
190                       observers_,
191                       OnSplitViewModeEnter());
192     split_view_controller_->ActivateSplitMode(NULL, NULL, NULL);
193   }
194 }
195
196 void WindowManagerImpl::ToggleOverview() {
197   if (IsOverviewModeActive()) {
198     SetInOverview(false);
199
200     // Activate the window which was active prior to entering overview.
201     const aura::Window::Windows windows =
202         window_list_provider_->GetWindowList();
203     if (!windows.empty()) {
204       aura::Window* window = windows.back();
205       // Show the window in case the exit overview animation has finished and
206       // |window| was hidden.
207       window->Show();
208
209       wm::ActivateWindow(window);
210     }
211   } else {
212     SetInOverview(true);
213   }
214 }
215
216 bool WindowManagerImpl::IsOverviewModeActive() {
217   return overview_;
218 }
219
220 void WindowManagerImpl::SetInOverview(bool active) {
221   bool in_overview = !!overview_;
222   if (active == in_overview)
223     return;
224
225   bezel_controller_->set_left_right_delegate(
226       active ? NULL : split_view_controller_.get());
227   if (active) {
228     FOR_EACH_OBSERVER(WindowManagerObserver, observers_, OnOverviewModeEnter());
229
230     // Note: The window_list_provider_ resembles the exact window list of the
231     // container, so no re-stacking is required before showing the OverviewMode.
232     overview_ = WindowOverviewMode::Create(
233         container_.get(), window_list_provider_.get(),
234         split_view_controller_.get(), this);
235   } else {
236     overview_.reset();
237     FOR_EACH_OBSERVER(WindowManagerObserver, observers_, OnOverviewModeExit());
238   }
239 }
240
241 void WindowManagerImpl::InstallAccelerators() {
242   const AcceleratorData accelerator_data[] = {
243       {TRIGGER_ON_PRESS, ui::VKEY_F6, ui::EF_NONE, CMD_TOGGLE_OVERVIEW,
244        AF_NONE},
245       {TRIGGER_ON_PRESS, ui::VKEY_F6, ui::EF_CONTROL_DOWN,
246        CMD_TOGGLE_SPLIT_VIEW, AF_NONE},
247   };
248   AcceleratorManager::Get()->RegisterAccelerators(
249       accelerator_data, arraysize(accelerator_data), this);
250 }
251
252 void WindowManagerImpl::AddObserver(WindowManagerObserver* observer) {
253   observers_.AddObserver(observer);
254 }
255
256 void WindowManagerImpl::RemoveObserver(WindowManagerObserver* observer) {
257   observers_.RemoveObserver(observer);
258 }
259
260 void WindowManagerImpl::ToggleSplitViewForTest() {
261   ToggleSplitView();
262 }
263
264 WindowListProvider* WindowManagerImpl::GetWindowListProvider() {
265   return window_list_provider_.get();
266 }
267
268 void WindowManagerImpl::OnSelectWindow(aura::Window* window) {
269   SetInOverview(false);
270
271   // Show the window in case the exit overview animation has finished and
272   // |window| was hidden.
273   window->Show();
274
275   wm::ActivateWindow(window);
276
277   if (split_view_controller_->IsSplitViewModeActive()) {
278     split_view_controller_->DeactivateSplitMode();
279     FOR_EACH_OBSERVER(WindowManagerObserver, observers_, OnSplitViewModeExit());
280   }
281   // If |window| does not have the size of the work-area, then make sure it is
282   // resized.
283   const gfx::Size work_area =
284       gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().work_area().size();
285   if (window->GetTargetBounds().size() != work_area) {
286     const gfx::Rect& window_bounds = window->bounds();
287     const gfx::Rect desired_bounds(work_area);
288     gfx::Transform transform;
289     transform.Translate(desired_bounds.x() - window_bounds.x(),
290                         desired_bounds.y() - window_bounds.y());
291     transform.Scale(desired_bounds.width() / window_bounds.width(),
292                     desired_bounds.height() / window_bounds.height());
293     ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
294     settings.SetPreemptionStrategy(
295         ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
296     settings.AddObserver(
297         new ui::ClosureAnimationObserver(base::Bind(&SetWindowState,
298                                                     base::Unretained(window),
299                                                     desired_bounds,
300                                                     gfx::Transform())));
301     window->SetTransform(transform);
302   }
303 }
304
305 void WindowManagerImpl::OnSelectSplitViewWindow(aura::Window* left,
306                                                 aura::Window* right,
307                                                 aura::Window* to_activate) {
308   SetInOverview(false);
309   FOR_EACH_OBSERVER(WindowManagerObserver, observers_, OnSplitViewModeEnter());
310   split_view_controller_->ActivateSplitMode(left, right, to_activate);
311 }
312
313 void WindowManagerImpl::OnWindowDestroying(aura::Window* window) {
314   if (window == container_)
315     container_.reset();
316 }
317
318 bool WindowManagerImpl::IsCommandEnabled(int command_id) const {
319   return true;
320 }
321
322 bool WindowManagerImpl::OnAcceleratorFired(int command_id,
323                                            const ui::Accelerator& accelerator) {
324   switch (command_id) {
325     case CMD_TOGGLE_OVERVIEW:
326       ToggleOverview();
327       break;
328     case CMD_TOGGLE_SPLIT_VIEW:
329       ToggleSplitView();
330       break;
331   }
332   return true;
333 }
334
335 aura::Window* WindowManagerImpl::GetWindowBehind(aura::Window* window) {
336   const aura::Window::Windows& windows = window_list_provider_->GetWindowList();
337   aura::Window::Windows::const_reverse_iterator iter =
338       std::find(windows.rbegin(), windows.rend(), window);
339   CHECK(iter != windows.rend());
340   ++iter;
341   aura::Window* behind = NULL;
342   if (iter != windows.rend())
343     behind = *iter++;
344
345   if (split_view_controller_->IsSplitViewModeActive()) {
346     aura::Window* left = split_view_controller_->left_window();
347     aura::Window* right = split_view_controller_->right_window();
348     CHECK(window == left || window == right);
349     if (behind == left || behind == right)
350       behind = (iter == windows.rend()) ? NULL : *iter;
351   }
352
353   return behind;
354 }
355
356 void WindowManagerImpl::OnTitleDragStarted(aura::Window* window) {
357   aura::Window* next_window = GetWindowBehind(window);
358   if (!next_window)
359     return;
360   // Make sure |window| is active.
361   wm::ActivateWindow(window);
362
363   // Make sure |next_window| is visibile.
364   next_window->Show();
365
366   // Position |next_window| correctly (left aligned if it's larger than
367   // |window|, and center aligned otherwise).
368   int dx = window->bounds().x() - next_window->bounds().x();
369   if (next_window->bounds().width() < window->bounds().width())
370     dx -= (next_window->bounds().width() - window->bounds().width()) / 2;
371
372   if (dx) {
373     gfx::Transform transform;
374     transform.Translate(dx, 0);
375     next_window->SetTransform(transform);
376   }
377 }
378
379 void WindowManagerImpl::OnTitleDragCompleted(aura::Window* window) {
380   aura::Window* next_window = GetWindowBehind(window);
381   if (!next_window)
382     return;
383   if (split_view_controller_->IsSplitViewModeActive()) {
384     split_view_controller_->ReplaceWindow(window, next_window);
385   } else {
386     ui::ScopedLayerAnimationSettings
387         settings(next_window->layer()->GetAnimator());
388     settings.AddObserver(new ui::ClosureAnimationObserver(
389         base::Bind(&SetWindowState,
390                    base::Unretained(next_window),
391                    window->bounds(),
392                    gfx::Transform())));
393
394     gfx::Transform transform;
395     transform.Scale(window->bounds().width() / next_window->bounds().width(),
396                     window->bounds().height() / next_window->bounds().height());
397     transform.Translate(window->bounds().x() - next_window->bounds().x(), 0);
398     next_window->SetTransform(transform);
399
400     wm::ActivateWindow(next_window);
401   }
402   window->Hide();
403 }
404
405 void WindowManagerImpl::OnTitleDragCanceled(aura::Window* window) {
406   aura::Window* next_window = GetWindowBehind(window);
407   if (!next_window)
408     return;
409   next_window->SetTransform(gfx::Transform());
410   next_window->Hide();
411 }
412
413 // static
414 WindowManager* WindowManager::Create() {
415   DCHECK(!instance);
416   new WindowManagerImpl;
417   DCHECK(instance);
418   return instance;
419 }
420
421 // static
422 void WindowManager::Shutdown() {
423   DCHECK(instance);
424   delete instance;
425   DCHECK(!instance);
426 }
427
428 // static
429 WindowManager* WindowManager::Get() {
430   DCHECK(instance);
431   return instance;
432 }
433
434 }  // namespace athena