- add sources.
[platform/framework/web/crosswalk.git] / src / ash / wm / overview / window_selector.cc
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 "ash/wm/overview/window_selector.h"
6
7 #include <algorithm>
8
9 #include "ash/ash_switches.h"
10 #include "ash/root_window_controller.h"
11 #include "ash/shell.h"
12 #include "ash/wm/mru_window_tracker.h"
13 #include "ash/wm/overview/window_overview.h"
14 #include "ash/wm/overview/window_selector_delegate.h"
15 #include "ash/wm/overview/window_selector_panels.h"
16 #include "ash/wm/overview/window_selector_window.h"
17 #include "ash/wm/window_state.h"
18 #include "base/auto_reset.h"
19 #include "base/command_line.h"
20 #include "base/metrics/histogram.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/timer/timer.h"
23 #include "ui/aura/client/activation_client.h"
24 #include "ui/aura/client/focus_client.h"
25 #include "ui/aura/root_window.h"
26 #include "ui/aura/window.h"
27 #include "ui/aura/window_observer.h"
28 #include "ui/events/event.h"
29 #include "ui/events/event_handler.h"
30
31 namespace ash {
32
33 namespace {
34
35 // The time from when the user pressed alt+tab while still holding alt before
36 // overview is engaged.
37 const int kOverviewDelayOnCycleMilliseconds = 100;
38
39 // If the delay before overview is less than or equal to this threshold the
40 // initial monitor is used for multi-display overview, otherwise the monitor
41 // of the currently selected window is used.
42 const int kOverviewDelayInitialMonitorThreshold = 100;
43
44 // The maximum amount of time allowed for the delay before overview on cycling.
45 // If the specified time exceeds this the timer will not be started.
46 const int kMaxOverviewDelayOnCycleMilliseconds = 10000;
47
48 int GetOverviewDelayOnCycleMilliseconds() {
49   static int value = -1;
50   if (value == -1) {
51     value = kOverviewDelayOnCycleMilliseconds;
52     if (CommandLine::ForCurrentProcess()->HasSwitch(
53           switches::kAshOverviewDelayOnAltTab)) {
54       if (!base::StringToInt(CommandLine::ForCurrentProcess()->
55             GetSwitchValueASCII(switches::kAshOverviewDelayOnAltTab), &value)) {
56         LOG(ERROR) << "Expected int value for "
57                    << switches::kAshOverviewDelayOnAltTab;
58       }
59     }
60   }
61   return value;
62 }
63
64 // A comparator for locating a given target window.
65 struct WindowSelectorItemComparator
66     : public std::unary_function<WindowSelectorItem*, bool> {
67   explicit WindowSelectorItemComparator(const aura::Window* target_window)
68       : target(target_window) {
69   }
70
71   bool operator()(WindowSelectorItem* window) const {
72     return window->TargetedWindow(target) != NULL;
73   }
74
75   const aura::Window* target;
76 };
77
78 // A comparator for locating a selector item for a given root.
79 struct WindowSelectorItemForRoot
80     : public std::unary_function<WindowSelectorItem*, bool> {
81   explicit WindowSelectorItemForRoot(const aura::Window* root)
82       : root_window(root) {
83   }
84
85   bool operator()(WindowSelectorItem* item) const {
86     return item->GetRootWindow() == root_window;
87   }
88
89   const aura::Window* root_window;
90 };
91
92 // Filter to watch for the termination of a keyboard gesture to cycle through
93 // multiple windows.
94 class WindowSelectorEventFilter : public ui::EventHandler {
95  public:
96   WindowSelectorEventFilter(WindowSelector* selector);
97   virtual ~WindowSelectorEventFilter();
98
99   // Overridden from ui::EventHandler:
100   virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
101
102  private:
103   // A weak pointer to the WindowSelector which owns this instance.
104   WindowSelector* selector_;
105
106   DISALLOW_COPY_AND_ASSIGN(WindowSelectorEventFilter);
107 };
108
109 // Watch for all keyboard events by filtering the root window.
110 WindowSelectorEventFilter::WindowSelectorEventFilter(WindowSelector* selector)
111     : selector_(selector) {
112   Shell::GetInstance()->AddPreTargetHandler(this);
113 }
114
115 WindowSelectorEventFilter::~WindowSelectorEventFilter() {
116   Shell::GetInstance()->RemovePreTargetHandler(this);
117 }
118
119 void WindowSelectorEventFilter::OnKeyEvent(ui::KeyEvent* event) {
120   // Views uses VKEY_MENU for both left and right Alt keys.
121   if (event->key_code() == ui::VKEY_MENU &&
122       event->type() == ui::ET_KEY_RELEASED) {
123     selector_->SelectWindow();
124     // Warning: |this| will be deleted from here on.
125   }
126 }
127
128 // Triggers a shelf visibility update on all root window controllers.
129 void UpdateShelfVisibility() {
130   Shell::RootWindowControllerList root_window_controllers =
131       Shell::GetInstance()->GetAllRootWindowControllers();
132   for (Shell::RootWindowControllerList::iterator iter =
133           root_window_controllers.begin();
134        iter != root_window_controllers.end(); ++iter) {
135     (*iter)->UpdateShelfVisibility();
136   }
137 }
138
139 // Returns the window immediately below |window| in the current container.
140 aura::Window* GetWindowBelow(aura::Window* window) {
141   aura::Window* parent = window->parent();
142   if (!parent)
143     return NULL;
144   aura::Window* below = NULL;
145   for (aura::Window::Windows::const_iterator iter = parent->children().begin();
146        iter != parent->children().end(); ++iter) {
147     if (*iter == window)
148       return below;
149     below = *iter;
150   }
151   NOTREACHED();
152   return NULL;
153 }
154
155 }  // namespace
156
157 // This class restores and moves a window to the front of the stacking order for
158 // the duration of the class's scope.
159 class ScopedShowWindow : public aura::WindowObserver {
160  public:
161   ScopedShowWindow();
162   virtual ~ScopedShowWindow();
163
164   // Show |window| at the top of the stacking order.
165   void Show(aura::Window* window);
166
167   // Cancel restoring the window on going out of scope.
168   void CancelRestore();
169
170   aura::Window* window() { return window_; }
171
172   // aura::WindowObserver:
173   virtual void OnWillRemoveWindow(aura::Window* window) OVERRIDE;
174
175  private:
176   // The window being shown.
177   aura::Window* window_;
178
179   // The window immediately below where window_ belongs.
180   aura::Window* stack_window_above_;
181
182   // If true, minimize window_ on going out of scope.
183   bool minimized_;
184
185   DISALLOW_COPY_AND_ASSIGN(ScopedShowWindow);
186 };
187
188 ScopedShowWindow::ScopedShowWindow()
189     : window_(NULL),
190       stack_window_above_(NULL),
191       minimized_(false) {
192 }
193
194 void ScopedShowWindow::Show(aura::Window* window) {
195   DCHECK(!window_);
196   window_ = window;
197   stack_window_above_ = GetWindowBelow(window);
198   minimized_ = wm::GetWindowState(window)->IsMinimized();
199   window_->Show();
200   window_->SetTransform(gfx::Transform());
201   window_->parent()->AddObserver(this);
202   window_->parent()->StackChildAtTop(window_);
203 }
204
205 ScopedShowWindow::~ScopedShowWindow() {
206   if (window_) {
207     window_->parent()->RemoveObserver(this);
208
209     // Restore window's stacking position.
210     if (stack_window_above_)
211       window_->parent()->StackChildAbove(window_, stack_window_above_);
212     else
213       window_->parent()->StackChildAtBottom(window_);
214
215     // Restore minimized state.
216     if (minimized_)
217       wm::GetWindowState(window_)->Minimize();
218   }
219 }
220
221 void ScopedShowWindow::CancelRestore() {
222   if (!window_)
223     return;
224   window_->parent()->RemoveObserver(this);
225   window_ = stack_window_above_ = NULL;
226 }
227
228 void ScopedShowWindow::OnWillRemoveWindow(aura::Window* window) {
229   if (window == window_) {
230     CancelRestore();
231   } else if (window == stack_window_above_) {
232     // If the window this window was above is removed, use the next window down
233     // as the restore marker.
234     stack_window_above_ = GetWindowBelow(stack_window_above_);
235   }
236 }
237
238 WindowSelector::WindowSelector(const WindowList& windows,
239                                WindowSelector::Mode mode,
240                                WindowSelectorDelegate* delegate)
241     : mode_(mode),
242       timer_enabled_(GetOverviewDelayOnCycleMilliseconds() <
243                          kMaxOverviewDelayOnCycleMilliseconds),
244       start_overview_timer_(FROM_HERE,
245           base::TimeDelta::FromMilliseconds(
246               GetOverviewDelayOnCycleMilliseconds()),
247           this, &WindowSelector::StartOverview),
248       delegate_(delegate),
249       selected_window_(0),
250       restore_focus_window_(NULL),
251       restoring_focus_(false) {
252   DCHECK(delegate_);
253   std::vector<WindowSelectorPanels*> panels_items;
254   for (size_t i = 0; i < windows.size(); ++i) {
255     windows[i]->AddObserver(this);
256     observed_windows_.insert(windows[i]);
257
258     if (windows[i]->type() == aura::client::WINDOW_TYPE_PANEL &&
259         wm::GetWindowState(windows[i])->panel_attached()) {
260       // Attached panel windows are grouped into a single overview item per
261       // root window (display).
262       std::vector<WindowSelectorPanels*>::iterator iter =
263           std::find_if(panels_items.begin(), panels_items.end(),
264                        WindowSelectorItemForRoot(windows[i]->GetRootWindow()));
265       WindowSelectorPanels* panels_item = NULL;
266       if (iter == panels_items.end()) {
267         panels_item = new WindowSelectorPanels();
268         panels_items.push_back(panels_item);
269         windows_.push_back(panels_item);
270       } else {
271         panels_item = *iter;
272       }
273       panels_item->AddWindow(windows[i]);
274     } else {
275       windows_.push_back(new WindowSelectorWindow(windows[i]));
276     }
277   }
278   RemoveFocusAndSetRestoreWindow();
279   UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.Items", windows_.size());
280
281   // Observe window activations and switchable containers on all root windows
282   // for newly created windows during overview.
283   Shell::GetInstance()->activation_client()->AddObserver(this);
284   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
285   for (Shell::RootWindowList::const_iterator iter = root_windows.begin();
286        iter != root_windows.end(); ++iter) {
287     for (size_t i = 0; i < kSwitchableWindowContainerIdsLength; ++i) {
288       Shell::GetContainer(*iter,
289                           kSwitchableWindowContainerIds[i])->AddObserver(this);
290     }
291   }
292
293   if (mode == WindowSelector::CYCLE) {
294     event_handler_.reset(new WindowSelectorEventFilter(this));
295     if (timer_enabled_)
296       start_overview_timer_.Reset();
297   } else {
298     StartOverview();
299   }
300 }
301
302 WindowSelector::~WindowSelector() {
303   ResetFocusRestoreWindow(true);
304   for (std::set<aura::Window*>::iterator iter = observed_windows_.begin();
305        iter != observed_windows_.end(); ++iter) {
306     (*iter)->RemoveObserver(this);
307   }
308   Shell::GetInstance()->activation_client()->RemoveObserver(this);
309   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
310   for (Shell::RootWindowList::const_iterator iter = root_windows.begin();
311        iter != root_windows.end(); ++iter) {
312     for (size_t i = 0; i < kSwitchableWindowContainerIdsLength; ++i) {
313       Shell::GetContainer(*iter,
314           kSwitchableWindowContainerIds[i])->RemoveObserver(this);
315     }
316   }
317   window_overview_.reset();
318   // Clearing the window list resets the ignored_by_shelf flag on the windows.
319   windows_.clear();
320   UpdateShelfVisibility();
321 }
322
323 void WindowSelector::Step(WindowSelector::Direction direction) {
324   DCHECK(!windows_.empty());
325   // Upgrade to CYCLE mode if currently in OVERVIEW mode.
326   if (mode_ != CYCLE) {
327     event_handler_.reset(new WindowSelectorEventFilter(this));
328     DCHECK(window_overview_);
329     // Set the initial selection window to animate to the new selection.
330     window_overview_->SetSelection(selected_window_);
331     window_overview_->MoveToSingleRootWindow(
332         windows_[selected_window_]->GetRootWindow());
333     mode_ = CYCLE;
334   }
335
336   selected_window_ = (selected_window_ + windows_.size() +
337       (direction == WindowSelector::FORWARD ? 1 : -1)) % windows_.size();
338   if (window_overview_) {
339     window_overview_->SetSelection(selected_window_);
340   } else {
341     showing_window_.reset(new ScopedShowWindow);
342     showing_window_->Show(windows_[selected_window_]->SelectionWindow());
343     start_overview_timer_.Reset();
344     if (timer_enabled_)
345       start_overview_timer_.Reset();
346   }
347 }
348
349 void WindowSelector::SelectWindow() {
350   ResetFocusRestoreWindow(false);
351   SelectWindow(windows_[selected_window_]->SelectionWindow());
352 }
353
354 void WindowSelector::SelectWindow(aura::Window* window) {
355   if (showing_window_ && showing_window_->window() == window)
356     showing_window_->CancelRestore();
357   ScopedVector<WindowSelectorItem>::iterator iter =
358       std::find_if(windows_.begin(), windows_.end(),
359                    WindowSelectorItemComparator(window));
360   DCHECK(iter != windows_.end());
361   // The selected window should not be minimized when window selection is
362   // ended.
363   (*iter)->RestoreWindowOnExit(window);
364   delegate_->OnWindowSelected(window);
365 }
366
367 void WindowSelector::CancelSelection() {
368   delegate_->OnSelectionCanceled();
369 }
370
371 void WindowSelector::OnWindowAdded(aura::Window* new_window) {
372   if (new_window->type() != aura::client::WINDOW_TYPE_NORMAL &&
373       new_window->type() != aura::client::WINDOW_TYPE_PANEL) {
374     return;
375   }
376
377   for (size_t i = 0; i < kSwitchableWindowContainerIdsLength; ++i) {
378     if (new_window->parent()->id() == kSwitchableWindowContainerIds[i] &&
379         !new_window->transient_parent()) {
380       // The new window is in one of the switchable containers, abort overview.
381       CancelSelection();
382       return;
383     }
384   }
385 }
386
387 void WindowSelector::OnWindowDestroying(aura::Window* window) {
388   ScopedVector<WindowSelectorItem>::iterator iter =
389       std::find_if(windows_.begin(), windows_.end(),
390                    WindowSelectorItemComparator(window));
391   DCHECK(window == restore_focus_window_ || iter != windows_.end());
392   window->RemoveObserver(this);
393   if (window == restore_focus_window_)
394     restore_focus_window_ = NULL;
395   if (iter == windows_.end())
396     return;
397
398   observed_windows_.erase(window);
399   (*iter)->RemoveWindow(window);
400   // If there are still windows in this selector entry then the overview is
401   // still active and the active selection remains the same.
402   if (!(*iter)->empty())
403     return;
404
405   size_t deleted_index = iter - windows_.begin();
406   windows_.erase(iter);
407   if (windows_.empty()) {
408     CancelSelection();
409     return;
410   }
411   if (window_overview_)
412     window_overview_->OnWindowsChanged();
413   if (mode_ == CYCLE && selected_window_ >= deleted_index) {
414     if (selected_window_ > deleted_index)
415       selected_window_--;
416     selected_window_ = selected_window_ % windows_.size();
417     if (window_overview_)
418       window_overview_->SetSelection(selected_window_);
419   }
420 }
421
422 void WindowSelector::OnWindowBoundsChanged(aura::Window* window,
423                                            const gfx::Rect& old_bounds,
424                                            const gfx::Rect& new_bounds) {
425   if (!window_overview_)
426     return;
427
428   ScopedVector<WindowSelectorItem>::iterator iter =
429       std::find_if(windows_.begin(), windows_.end(),
430                    WindowSelectorItemComparator(window));
431   DCHECK(window == restore_focus_window_ || iter != windows_.end());
432   if (iter == windows_.end())
433     return;
434
435   // Immediately finish any active bounds animation.
436   window->layer()->GetAnimator()->StopAnimatingProperty(
437       ui::LayerAnimationElement::BOUNDS);
438
439   // Recompute the transform for the window.
440   (*iter)->RecomputeWindowTransforms();
441 }
442
443 void WindowSelector::OnWindowActivated(aura::Window* gained_active,
444                                        aura::Window* lost_active) {
445   if (restoring_focus_ || !gained_active)
446     return;
447   // Don't restore focus on exit if a window was just activated.
448   ResetFocusRestoreWindow(false);
449   CancelSelection();
450 }
451
452 void WindowSelector::OnAttemptToReactivateWindow(aura::Window* request_active,
453                                                  aura::Window* actual_active) {
454   if (restoring_focus_)
455     return;
456   // Don't restore focus on exit if a window was just activated.
457   ResetFocusRestoreWindow(false);
458   CancelSelection();
459 }
460
461 void WindowSelector::StartOverview() {
462   DCHECK(!window_overview_);
463   aura::Window* overview_root = NULL;
464   if (mode_ == CYCLE) {
465     overview_root = GetOverviewDelayOnCycleMilliseconds() <=
466                         kOverviewDelayInitialMonitorThreshold ?
467                     Shell::GetTargetRootWindow() :
468                     windows_[selected_window_]->GetRootWindow();
469   }
470   window_overview_.reset(new WindowOverview(this, &windows_, overview_root));
471   if (mode_ == CYCLE)
472     window_overview_->SetSelection(selected_window_);
473   UpdateShelfVisibility();
474 }
475
476 void WindowSelector::RemoveFocusAndSetRestoreWindow() {
477   aura::client::FocusClient* focus_client = aura::client::GetFocusClient(
478       Shell::GetPrimaryRootWindow());
479   DCHECK(!restore_focus_window_);
480   restore_focus_window_ = focus_client->GetFocusedWindow();
481   if (restore_focus_window_) {
482     // Removing focus from the window could cause the window to be destroyed so
483     // it must be observed before removing focus.
484     if (observed_windows_.find(restore_focus_window_) ==
485             observed_windows_.end()) {
486       restore_focus_window_->AddObserver(this);
487     }
488     focus_client->FocusWindow(NULL);
489   }
490 }
491
492 void WindowSelector::ResetFocusRestoreWindow(bool focus) {
493   if (!restore_focus_window_)
494     return;
495   if (focus) {
496     base::AutoReset<bool> restoring_focus(&restoring_focus_, true);
497     restore_focus_window_->Focus();
498   }
499   // If the window is in the observed_windows_ list it needs to continue to be
500   // observed.
501   if (observed_windows_.find(restore_focus_window_) ==
502           observed_windows_.end()) {
503     restore_focus_window_->RemoveObserver(this);
504   }
505   restore_focus_window_ = NULL;
506 }
507
508 }  // namespace ash