Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(368)

Side by Side Diff: components/mus/ws/focus_controller.cc

Issue 1560063003: mus: Fix activation cycle direction. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/mus/ws/focus_controller.h" 5 #include "components/mus/ws/focus_controller.h"
6 6
7 #include "base/macros.h" 7 #include "base/macros.h"
8 #include "components/mus/public/interfaces/window_manager.mojom.h" 8 #include "components/mus/public/interfaces/window_manager.mojom.h"
9 #include "components/mus/ws/focus_controller_delegate.h" 9 #include "components/mus/ws/focus_controller_delegate.h"
10 #include "components/mus/ws/focus_controller_observer.h" 10 #include "components/mus/ws/focus_controller_observer.h"
11 #include "components/mus/ws/server_window.h" 11 #include "components/mus/ws/server_window.h"
12 #include "components/mus/ws/server_window_drawn_tracker.h" 12 #include "components/mus/ws/server_window_drawn_tracker.h"
13 13
14 namespace mus { 14 namespace mus {
15 namespace ws { 15 namespace ws {
16 16
17 namespace { 17 namespace {
18 18
19 ServerWindow* GetDeepestFirstDescendant(ServerWindow* window) { 19 ServerWindow* GetDeepestLastDescendant(ServerWindow* window) {
20 while (!window->children().empty()) 20 while (!window->children().empty())
21 window = window->children()[0]; 21 window = window->children().back();
22 return window; 22 return window;
23 } 23 }
24 24
25 // This can be used to iterate over each node in a rooted tree for the purpose 25 // This can be used to iterate over each node in a rooted tree for the purpose
26 // of shifting focus/activation. 26 // of shifting focus/activation.
27 class WindowTreeIterator { 27 class WindowTreeIterator {
28 public: 28 public:
29 explicit WindowTreeIterator(ServerWindow* root) : root_(root) {} 29 explicit WindowTreeIterator(ServerWindow* root) : root_(root) {}
30 ~WindowTreeIterator() {} 30 ~WindowTreeIterator() {}
31 31
32 ServerWindow* GetNext(ServerWindow* window) const { 32 ServerWindow* GetNext(ServerWindow* window) const {
33 if (window == root_ || window == nullptr) 33 if (window == root_ || window == nullptr)
34 return GetDeepestFirstDescendant(root_); 34 return GetDeepestLastDescendant(root_);
35 35
36 // Return the next sibling. 36 // Return the next sibling.
37 ServerWindow* parent = window->parent(); 37 ServerWindow* parent = window->parent();
38 if (parent) { 38 if (parent) {
39 const ServerWindow::Windows& siblings = parent->children(); 39 const ServerWindow::Windows& siblings = parent->children();
40 ServerWindow::Windows::const_iterator iter = 40 ServerWindow::Windows::const_reverse_iterator iter =
41 std::find(siblings.begin(), siblings.end(), window); 41 std::find(siblings.rbegin(), siblings.rend(), window);
42 DCHECK(iter != siblings.end()); 42 DCHECK(iter != siblings.rend());
43 ++iter; 43 ++iter;
44 if (iter != siblings.end()) 44 if (iter != siblings.rend())
45 return GetDeepestFirstDescendant(*iter); 45 return GetDeepestLastDescendant(*iter);
46 } 46 }
47 47
48 // All children and siblings have been explored. Next is the parent. 48 // All children and siblings have been explored. Next is the parent.
49 return parent; 49 return parent;
50 } 50 }
51 51
52 private: 52 private:
53 ServerWindow* root_; 53 ServerWindow* root_;
54 54
55 DISALLOW_COPY_AND_ASSIGN(WindowTreeIterator); 55 DISALLOW_COPY_AND_ASSIGN(WindowTreeIterator);
56 }; 56 };
57 57
58 } // namespace 58 } // namespace
59 59
60 FocusController::FocusController(FocusControllerDelegate* delegate, 60 FocusController::FocusController(FocusControllerDelegate* delegate,
61 ServerWindow* root) 61 ServerWindow* root)
62 : delegate_(delegate), 62 : delegate_(delegate),
63 root_(root), 63 root_(root),
64 focused_window_(nullptr), 64 focused_window_(nullptr),
65 active_window_(nullptr) { 65 active_window_(nullptr),
66 activation_reason_(ActivationChangeReason::UNKNONW) {
66 DCHECK(delegate_); 67 DCHECK(delegate_);
67 DCHECK(root_); 68 DCHECK(root_);
68 } 69 }
69 70
70 FocusController::~FocusController() {} 71 FocusController::~FocusController() {
72 ClearCycleWindows();
73 }
71 74
72 void FocusController::SetFocusedWindow(ServerWindow* window) { 75 void FocusController::SetFocusedWindow(ServerWindow* window) {
73 if (GetFocusedWindow() == window) 76 if (GetFocusedWindow() == window)
74 return; 77 return;
75 78
76 SetFocusedWindowImpl(FocusControllerChangeSource::EXPLICIT, window); 79 SetFocusedWindowImpl(FocusControllerChangeSource::EXPLICIT, window);
77 } 80 }
78 81
79 ServerWindow* FocusController::GetFocusedWindow() { 82 ServerWindow* FocusController::GetFocusedWindow() {
80 return focused_window_; 83 return focused_window_;
81 } 84 }
82 85
83 void FocusController::ActivateNextWindow() { 86 void FocusController::ActivateNextWindow() {
84 WindowTreeIterator iter(root_); 87 WindowTreeIterator iter(root_);
85 ServerWindow* activate = active_window_; 88 ServerWindow* activate = active_window_;
86 do { 89 while (true) {
87 activate = iter.GetNext(activate); 90 activate = iter.GetNext(activate);
88 } while (activate != active_window_ && !CanBeActivated(activate)); 91 if (activation_reason_ == ActivationChangeReason::CYCLE) {
89 SetActiveWindow(activate); 92 if (activate == active_window_) {
93 // We have cycled over all the activatable windows. Remove the oldest
94 // window that was cycled.
95 if (!cycle_windows_.empty()) {
96 cycle_windows_.front()->RemoveObserver(this);
97 cycle_windows_.erase(cycle_windows_.begin());
98 continue;
99 }
100 } else if (std::find(cycle_windows_.begin(), cycle_windows_.end(),
sky 2016/01/06 21:02:39 FYI: you can use ContainsValue(cycle_windows_, act
101 activate) != cycle_windows_.end()) {
102 // We are cycling between activated windows, and this window has already
103 // been through the cycle. So skip over it.
104 continue;
105 }
106 }
107 if (activate == active_window_ || CanBeActivated(activate))
108 break;
109 }
110 SetActiveWindow(activate, ActivationChangeReason::CYCLE);
90 111
91 if (active_window_) { 112 if (active_window_) {
92 // Do not shift focus if the focused window already lives in the active 113 // Do not shift focus if the focused window already lives in the active
93 // window. 114 // window.
94 if (focused_window_ && active_window_->Contains(focused_window_)) 115 if (focused_window_ && active_window_->Contains(focused_window_))
95 return; 116 return;
96 // Focus the first focusable window in the tree. 117 // Focus the first focusable window in the tree.
97 WindowTreeIterator iter(active_window_); 118 WindowTreeIterator iter(active_window_);
98 ServerWindow* focus = nullptr; 119 ServerWindow* focus = nullptr;
99 do { 120 do {
100 focus = iter.GetNext(focus); 121 focus = iter.GetNext(focus);
101 } while (focus != active_window_ && !CanBeFocused(focus)); 122 } while (focus != active_window_ && !CanBeFocused(focus));
102 SetFocusedWindow(focus); 123 SetFocusedWindow(focus);
103 } else { 124 } else {
104 SetFocusedWindow(nullptr); 125 SetFocusedWindow(nullptr);
105 } 126 }
106 } 127 }
107 128
108 void FocusController::AddObserver(FocusControllerObserver* observer) { 129 void FocusController::AddObserver(FocusControllerObserver* observer) {
109 observers_.AddObserver(observer); 130 observers_.AddObserver(observer);
110 } 131 }
111 132
112 void FocusController::RemoveObserver(FocusControllerObserver* observer) { 133 void FocusController::RemoveObserver(FocusControllerObserver* observer) {
113 observers_.RemoveObserver(observer); 134 observers_.RemoveObserver(observer);
114 } 135 }
115 136
116 void FocusController::SetActiveWindow(ServerWindow* window) { 137 void FocusController::SetActiveWindow(ServerWindow* window,
138 ActivationChangeReason reason) {
117 DCHECK(!window || CanBeActivated(window)); 139 DCHECK(!window || CanBeActivated(window));
118 if (active_window_ == window) 140 if (active_window_ == window)
119 return; 141 return;
142 if (reason != ActivationChangeReason::CYCLE) {
143 ClearCycleWindows();
144 } else if (activation_reason_ != ActivationChangeReason::CYCLE) {
145 DCHECK(cycle_windows_.empty());
146 if (active_window_) {
147 active_window_->AddObserver(this);
148 cycle_windows_.push_back(active_window_);
149 }
150 }
151
120 ServerWindow* old_active = active_window_; 152 ServerWindow* old_active = active_window_;
121 active_window_ = window; 153 active_window_ = window;
122 if (old_active != active_window_) { 154 activation_reason_ = reason;
123 FOR_EACH_OBSERVER(FocusControllerObserver, observers_, 155 FOR_EACH_OBSERVER(FocusControllerObserver, observers_,
124 OnActivationChanged(old_active, active_window_)); 156 OnActivationChanged(old_active, active_window_));
157 if (active_window_ && activation_reason_ == ActivationChangeReason::CYCLE) {
158 active_window_->AddObserver(this);
sky 2016/01/06 21:02:39 nit: add an AddWindowToCycleWindows (or something
159 cycle_windows_.push_back(active_window_);
125 } 160 }
126 } 161 }
127 162
128 bool FocusController::CanBeFocused(ServerWindow* window) const { 163 bool FocusController::CanBeFocused(ServerWindow* window) const {
129 // All ancestors of |window| must be drawn, and be focusable. 164 // All ancestors of |window| must be drawn, and be focusable.
130 for (ServerWindow* w = window; w; w = w->parent()) { 165 for (ServerWindow* w = window; w; w = w->parent()) {
131 if (!w->IsDrawn()) 166 if (!w->IsDrawn())
132 return false; 167 return false;
133 if (!w->can_focus()) 168 if (!w->can_focus())
134 return false; 169 return false;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 ServerWindow* window) { 215 ServerWindow* window) {
181 if (window && !CanBeFocused(window)) 216 if (window && !CanBeFocused(window))
182 return; 217 return;
183 ServerWindow* old_focused = GetFocusedWindow(); 218 ServerWindow* old_focused = GetFocusedWindow();
184 219
185 DCHECK(!window || window->IsDrawn()); 220 DCHECK(!window || window->IsDrawn());
186 221
187 // Activate the closest activatable ancestor window. 222 // Activate the closest activatable ancestor window.
188 // TODO(sad): The window to activate doesn't necessarily have to be a direct 223 // TODO(sad): The window to activate doesn't necessarily have to be a direct
189 // ancestor (e.g. could be a transient parent). 224 // ancestor (e.g. could be a transient parent).
190 SetActiveWindow(GetActivatableAncestorOf(window)); 225 SetActiveWindow(GetActivatableAncestorOf(window),
226 ActivationChangeReason::FOCUS);
191 227
192 FOR_EACH_OBSERVER(FocusControllerObserver, observers_, 228 FOR_EACH_OBSERVER(FocusControllerObserver, observers_,
193 OnFocusChanged(change_source, old_focused, window)); 229 OnFocusChanged(change_source, old_focused, window));
194 230
195 focused_window_ = window; 231 focused_window_ = window;
196 // We can currently use only a single ServerWindowDrawnTracker since focused 232 // We can currently use only a single ServerWindowDrawnTracker since focused
197 // window is expected to be a direct descendant of the active window. 233 // window is expected to be a direct descendant of the active window.
198 if (focused_window_ && active_window_) { 234 if (focused_window_ && active_window_) {
199 DCHECK(active_window_->Contains(focused_window_)); 235 DCHECK(active_window_->Contains(focused_window_));
200 } 236 }
201 ServerWindow* track_window = focused_window_; 237 ServerWindow* track_window = focused_window_;
202 if (!track_window) 238 if (!track_window)
203 track_window = active_window_; 239 track_window = active_window_;
204 if (track_window) 240 if (track_window)
205 drawn_tracker_.reset(new ServerWindowDrawnTracker(track_window, this)); 241 drawn_tracker_.reset(new ServerWindowDrawnTracker(track_window, this));
206 else 242 else
207 drawn_tracker_.reset(); 243 drawn_tracker_.reset();
208 } 244 }
209 245
246 void FocusController::ClearCycleWindows() {
247 while (!cycle_windows_.empty()) {
248 cycle_windows_.front()->RemoveObserver(this);
249 cycle_windows_.erase(cycle_windows_.begin());
250 }
251 }
252
210 void FocusController::OnDrawnStateWillChange(ServerWindow* ancestor, 253 void FocusController::OnDrawnStateWillChange(ServerWindow* ancestor,
211 ServerWindow* window, 254 ServerWindow* window,
212 bool is_drawn) { 255 bool is_drawn) {
213 DCHECK(!is_drawn); 256 DCHECK(!is_drawn);
214 DCHECK(root_->Contains(window)); 257 DCHECK(root_->Contains(window));
215 drawn_tracker_.reset(); 258 drawn_tracker_.reset();
216 259
217 auto will_be_hidden = [ancestor, window](ServerWindow* w) { 260 auto will_be_hidden = [ancestor, window](ServerWindow* w) {
218 return w != ancestor && ancestor->Contains(w) && w->Contains(window); 261 return w != ancestor && ancestor->Contains(w) && w->Contains(window);
219 }; 262 };
220 263
221 // If |window| is |active_window_|, then activate the next activatable window 264 // If |window| is |active_window_|, then activate the next activatable window
222 // that does not belong to the subtree which is getting hidden. 265 // that does not belong to the subtree which is getting hidden.
223 if (window == active_window_) { 266 if (window == active_window_) {
224 WindowTreeIterator iter(root_); 267 WindowTreeIterator iter(root_);
225 ServerWindow* activate = active_window_; 268 ServerWindow* activate = active_window_;
226 do { 269 do {
227 activate = iter.GetNext(activate); 270 activate = iter.GetNext(activate);
228 } while (activate != active_window_ && 271 } while (activate != active_window_ &&
229 (will_be_hidden(activate) || !CanBeActivated(activate))); 272 (will_be_hidden(activate) || !CanBeActivated(activate)));
230 if (activate == window) 273 if (activate == window)
231 activate = nullptr; 274 activate = nullptr;
232 SetActiveWindow(activate); 275 SetActiveWindow(activate, ActivationChangeReason::DRAWN_STATE_CHANGED);
233 276
234 // Now make sure focus is in the active window. 277 // Now make sure focus is in the active window.
235 ServerWindow* focus = nullptr; 278 ServerWindow* focus = nullptr;
236 if (active_window_) { 279 if (active_window_) {
237 WindowTreeIterator iter(active_window_); 280 WindowTreeIterator iter(active_window_);
238 focus = nullptr; 281 focus = nullptr;
239 do { 282 do {
240 focus = iter.GetNext(focus); 283 focus = iter.GetNext(focus);
241 } while (focus != active_window_ && 284 } while (focus != active_window_ &&
242 (will_be_hidden(focus) || !CanBeFocused(focus))); 285 (will_be_hidden(focus) || !CanBeFocused(focus)));
(...skipping 16 matching lines...) Expand all
259 focus = nullptr; 302 focus = nullptr;
260 SetFocusedWindowImpl(FocusControllerChangeSource::DRAWN_STATE_CHANGED, focus); 303 SetFocusedWindowImpl(FocusControllerChangeSource::DRAWN_STATE_CHANGED, focus);
261 } 304 }
262 305
263 void FocusController::OnDrawnStateChanged(ServerWindow* ancestor, 306 void FocusController::OnDrawnStateChanged(ServerWindow* ancestor,
264 ServerWindow* window, 307 ServerWindow* window,
265 bool is_drawn) { 308 bool is_drawn) {
266 DCHECK(false); 309 DCHECK(false);
267 } 310 }
268 311
312 void FocusController::OnWillDestroyWindow(ServerWindow* window) {
313 cycle_windows_.erase(
314 std::find(cycle_windows_.begin(), cycle_windows_.end(), window));
sky 2016/01/06 21:02:39 also remove the observer here too.
315 }
316
269 } // namespace ws 317 } // namespace ws
270 } // namespace mus 318 } // namespace mus
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698