OLD | NEW |
| (Empty) |
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/common/wm/mru_window_tracker.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "ash/common/wm/focus_rules.h" | |
10 #include "ash/common/wm/switchable_windows.h" | |
11 #include "ash/common/wm/window_state.h" | |
12 #include "ash/common/wm_shell.h" | |
13 #include "ash/common/wm_window.h" | |
14 #include "ash/public/cpp/shell_window_ids.h" | |
15 #include "base/bind.h" | |
16 #include "ui/aura/window.h" | |
17 | |
18 namespace ash { | |
19 | |
20 namespace { | |
21 | |
22 using CanActivateWindowPredicate = base::Callback<bool(WmWindow*)>; | |
23 | |
24 bool CallCanActivate(WmWindow* window) { | |
25 return window->CanActivate(); | |
26 } | |
27 | |
28 // Adds the windows that can be cycled through for the specified window id to | |
29 // |windows|. | |
30 void AddTrackedWindows(WmWindow* root, | |
31 int container_id, | |
32 MruWindowTracker::WindowList* windows) { | |
33 WmWindow* container = root->GetChildByShellWindowId(container_id); | |
34 const MruWindowTracker::WindowList children(container->GetChildren()); | |
35 windows->insert(windows->end(), children.begin(), children.end()); | |
36 } | |
37 | |
38 // Returns a list of windows ordered by their stacking order. | |
39 // If |mru_windows| is passed, these windows are moved to the front of the list. | |
40 // It uses the given |should_include_window_predicate| to determine whether to | |
41 // include a window in the returned list or not. | |
42 MruWindowTracker::WindowList BuildWindowListInternal( | |
43 const std::list<WmWindow*>* mru_windows, | |
44 const CanActivateWindowPredicate& should_include_window_predicate) { | |
45 MruWindowTracker::WindowList windows; | |
46 WmWindow* active_root = WmShell::Get()->GetRootWindowForNewWindows(); | |
47 for (WmWindow* window : WmShell::Get()->GetAllRootWindows()) { | |
48 if (window == active_root) | |
49 continue; | |
50 for (size_t i = 0; i < wm::kSwitchableWindowContainerIdsLength; ++i) | |
51 AddTrackedWindows(window, wm::kSwitchableWindowContainerIds[i], &windows); | |
52 } | |
53 | |
54 // Add windows in the active root windows last so that the topmost window | |
55 // in the active root window becomes the front of the list. | |
56 for (size_t i = 0; i < wm::kSwitchableWindowContainerIdsLength; ++i) | |
57 AddTrackedWindows(active_root, wm::kSwitchableWindowContainerIds[i], | |
58 &windows); | |
59 | |
60 // Removes unfocusable windows. | |
61 std::vector<WmWindow*>::iterator itr = windows.begin(); | |
62 while (itr != windows.end()) { | |
63 if (!should_include_window_predicate.Run(*itr)) | |
64 itr = windows.erase(itr); | |
65 else | |
66 ++itr; | |
67 } | |
68 | |
69 // Put the windows in the mru_windows list at the head, if it's available. | |
70 if (mru_windows) { | |
71 // Iterate through the list backwards, so that we can move each window to | |
72 // the front of the windows list as we find them. | |
73 for (auto ix = mru_windows->rbegin(); ix != mru_windows->rend(); ++ix) { | |
74 // Exclude windows in non-switchable containers and those which cannot | |
75 // be activated. | |
76 if (!wm::IsSwitchableContainer((*ix)->GetParent()) || | |
77 !should_include_window_predicate.Run(*ix)) { | |
78 continue; | |
79 } | |
80 | |
81 MruWindowTracker::WindowList::iterator window = | |
82 std::find(windows.begin(), windows.end(), *ix); | |
83 if (window != windows.end()) { | |
84 windows.erase(window); | |
85 windows.push_back(*ix); | |
86 } | |
87 } | |
88 } | |
89 | |
90 // Window cycling expects the topmost window at the front of the list. | |
91 std::reverse(windows.begin(), windows.end()); | |
92 | |
93 return windows; | |
94 } | |
95 | |
96 } // namespace | |
97 | |
98 ////////////////////////////////////////////////////////////////////////////// | |
99 // MruWindowTracker, public: | |
100 | |
101 MruWindowTracker::MruWindowTracker() : ignore_window_activations_(false) { | |
102 WmShell::Get()->AddActivationObserver(this); | |
103 } | |
104 | |
105 MruWindowTracker::~MruWindowTracker() { | |
106 WmShell::Get()->RemoveActivationObserver(this); | |
107 for (WmWindow* window : mru_windows_) | |
108 window->aura_window()->RemoveObserver(this); | |
109 } | |
110 | |
111 MruWindowTracker::WindowList MruWindowTracker::BuildMruWindowList() const { | |
112 return BuildWindowListInternal(&mru_windows_, base::Bind(&CallCanActivate)); | |
113 } | |
114 | |
115 MruWindowTracker::WindowList MruWindowTracker::BuildWindowListIgnoreModal() | |
116 const { | |
117 return BuildWindowListInternal(nullptr, | |
118 base::Bind(&IsWindowConsideredActivatable)); | |
119 } | |
120 | |
121 void MruWindowTracker::SetIgnoreActivations(bool ignore) { | |
122 ignore_window_activations_ = ignore; | |
123 | |
124 // If no longer ignoring window activations, move currently active window | |
125 // to front. | |
126 if (!ignore) | |
127 SetActiveWindow(WmShell::Get()->GetActiveWindow()); | |
128 } | |
129 | |
130 ////////////////////////////////////////////////////////////////////////////// | |
131 // MruWindowTracker, private: | |
132 | |
133 void MruWindowTracker::SetActiveWindow(WmWindow* active_window) { | |
134 if (!active_window) | |
135 return; | |
136 | |
137 std::list<WmWindow*>::iterator iter = | |
138 std::find(mru_windows_.begin(), mru_windows_.end(), active_window); | |
139 // Observe all newly tracked windows. | |
140 if (iter == mru_windows_.end()) | |
141 active_window->aura_window()->AddObserver(this); | |
142 else | |
143 mru_windows_.erase(iter); | |
144 mru_windows_.push_front(active_window); | |
145 } | |
146 | |
147 void MruWindowTracker::OnWindowActivated(WmWindow* gained_active, | |
148 WmWindow* lost_active) { | |
149 if (!ignore_window_activations_) | |
150 SetActiveWindow(gained_active); | |
151 } | |
152 | |
153 void MruWindowTracker::OnWindowDestroyed(aura::Window* window) { | |
154 // It's possible for OnWindowActivated() to be called after | |
155 // OnWindowDestroying(). This means we need to override OnWindowDestroyed() | |
156 // else we may end up with a deleted window in |mru_windows_|. | |
157 mru_windows_.remove(WmWindow::Get(window)); | |
158 window->RemoveObserver(this); | |
159 } | |
160 | |
161 } // namespace ash | |
OLD | NEW |