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

Side by Side Diff: ui/wm/core/focus_controller.cc

Issue 851853002: It is time. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Trying to reup because the last upload failed. Created 5 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
« no previous file with comments | « ui/wm/core/focus_controller.h ('k') | ui/wm/core/focus_controller_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/focus_controller.h"
6
7 #include "base/auto_reset.h"
8 #include "ui/aura/client/aura_constants.h"
9 #include "ui/aura/client/capture_client.h"
10 #include "ui/aura/client/focus_change_observer.h"
11 #include "ui/aura/env.h"
12 #include "ui/aura/window_tracker.h"
13 #include "ui/base/ime/text_input_focus_manager.h"
14 #include "ui/events/event.h"
15 #include "ui/wm/core/focus_rules.h"
16 #include "ui/wm/core/window_util.h"
17 #include "ui/wm/public/activation_change_observer.h"
18
19 namespace wm {
20 namespace {
21
22 // When a modal window is activated, we bring its entire transient parent chain
23 // to the front. This function must be called before the modal transient is
24 // stacked at the top to ensure correct stacking order.
25 void StackTransientParentsBelowModalWindow(aura::Window* window) {
26 if (window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_WINDOW)
27 return;
28
29 aura::Window* transient_parent = wm::GetTransientParent(window);
30 while (transient_parent) {
31 transient_parent->parent()->StackChildAtTop(transient_parent);
32 transient_parent = wm::GetTransientParent(transient_parent);
33 }
34 }
35
36 } // namespace
37
38 ////////////////////////////////////////////////////////////////////////////////
39 // FocusController, public:
40
41 FocusController::FocusController(FocusRules* rules)
42 : active_window_(NULL),
43 focused_window_(NULL),
44 updating_focus_(false),
45 updating_activation_(false),
46 rules_(rules),
47 observer_manager_(this) {
48 DCHECK(rules);
49 }
50
51 FocusController::~FocusController() {
52 }
53
54 ////////////////////////////////////////////////////////////////////////////////
55 // FocusController, aura::client::ActivationClient implementation:
56
57 void FocusController::AddObserver(
58 aura::client::ActivationChangeObserver* observer) {
59 activation_observers_.AddObserver(observer);
60 }
61
62 void FocusController::RemoveObserver(
63 aura::client::ActivationChangeObserver* observer) {
64 activation_observers_.RemoveObserver(observer);
65 }
66
67 void FocusController::ActivateWindow(aura::Window* window) {
68 FocusWindow(window);
69 }
70
71 void FocusController::DeactivateWindow(aura::Window* window) {
72 if (window)
73 FocusWindow(rules_->GetNextActivatableWindow(window));
74 }
75
76 aura::Window* FocusController::GetActiveWindow() {
77 return active_window_;
78 }
79
80 aura::Window* FocusController::GetActivatableWindow(aura::Window* window) {
81 return rules_->GetActivatableWindow(window);
82 }
83
84 aura::Window* FocusController::GetToplevelWindow(aura::Window* window) {
85 return rules_->GetToplevelWindow(window);
86 }
87
88 bool FocusController::CanActivateWindow(aura::Window* window) const {
89 return rules_->CanActivateWindow(window);
90 }
91
92 ////////////////////////////////////////////////////////////////////////////////
93 // FocusController, aura::client::FocusClient implementation:
94
95 void FocusController::AddObserver(
96 aura::client::FocusChangeObserver* observer) {
97 focus_observers_.AddObserver(observer);
98 }
99
100 void FocusController::RemoveObserver(
101 aura::client::FocusChangeObserver* observer) {
102 focus_observers_.RemoveObserver(observer);
103 }
104
105 void FocusController::FocusWindow(aura::Window* window) {
106 if (window &&
107 (window->Contains(focused_window_) || window->Contains(active_window_))) {
108 return;
109 }
110
111 // We should not be messing with the focus if the window has capture, unless
112 // no has focus.
113 if (window && (aura::client::GetCaptureWindow(window) == window) &&
114 focused_window_) {
115 return;
116 }
117
118 // Focusing a window also activates its containing activatable window. Note
119 // that the rules could redirect activation activation and/or focus.
120 aura::Window* focusable = rules_->GetFocusableWindow(window);
121 aura::Window* activatable =
122 focusable ? rules_->GetActivatableWindow(focusable) : NULL;
123
124 // We need valid focusable/activatable windows in the event we're not clearing
125 // focus. "Clearing focus" is inferred by whether or not |window| passed to
126 // this function is non-NULL.
127 if (window && (!focusable || !activatable))
128 return;
129 DCHECK((focusable && activatable) || !window);
130
131 // Activation change observers may change the focused window. If this happens
132 // we must not adjust the focus below since this will clobber that change.
133 aura::Window* last_focused_window = focused_window_;
134 if (!updating_activation_)
135 SetActiveWindow(window, activatable);
136
137 // If the window's ActivationChangeObserver shifted focus to a valid window,
138 // we don't want to focus the window we thought would be focused by default.
139 bool activation_changed_focus = last_focused_window != focused_window_;
140 if (!updating_focus_ && (!activation_changed_focus || !focused_window_)) {
141 if (active_window_ && focusable)
142 DCHECK(active_window_->Contains(focusable));
143 SetFocusedWindow(focusable);
144 }
145 }
146
147 void FocusController::ResetFocusWithinActiveWindow(aura::Window* window) {
148 DCHECK(window);
149 if (!active_window_)
150 return;
151 if (!active_window_->Contains(window))
152 return;
153 SetFocusedWindow(window);
154 }
155
156 aura::Window* FocusController::GetFocusedWindow() {
157 return focused_window_;
158 }
159
160 ////////////////////////////////////////////////////////////////////////////////
161 // FocusController, ui::EventHandler implementation:
162 void FocusController::OnKeyEvent(ui::KeyEvent* event) {
163 }
164
165 void FocusController::OnMouseEvent(ui::MouseEvent* event) {
166 if (event->type() == ui::ET_MOUSE_PRESSED && !event->handled())
167 WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target()));
168 }
169
170 void FocusController::OnScrollEvent(ui::ScrollEvent* event) {
171 }
172
173 void FocusController::OnTouchEvent(ui::TouchEvent* event) {
174 }
175
176 void FocusController::OnGestureEvent(ui::GestureEvent* event) {
177 if (event->type() == ui::ET_GESTURE_BEGIN &&
178 event->details().touch_points() == 1 &&
179 !event->handled()) {
180 WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target()));
181 }
182 }
183
184 ////////////////////////////////////////////////////////////////////////////////
185 // FocusController, aura::WindowObserver implementation:
186
187 void FocusController::OnWindowVisibilityChanged(aura::Window* window,
188 bool visible) {
189 if (!visible)
190 WindowLostFocusFromDispositionChange(window, window->parent());
191 }
192
193 void FocusController::OnWindowDestroying(aura::Window* window) {
194 WindowLostFocusFromDispositionChange(window, window->parent());
195 }
196
197 void FocusController::OnWindowHierarchyChanging(
198 const HierarchyChangeParams& params) {
199 if (params.receiver == active_window_ &&
200 params.target->Contains(params.receiver) && (!params.new_parent ||
201 aura::client::GetFocusClient(params.new_parent) !=
202 aura::client::GetFocusClient(params.receiver))) {
203 WindowLostFocusFromDispositionChange(params.receiver, params.old_parent);
204 }
205 }
206
207 void FocusController::OnWindowHierarchyChanged(
208 const HierarchyChangeParams& params) {
209 if (params.receiver == focused_window_ &&
210 params.target->Contains(params.receiver) && (!params.new_parent ||
211 aura::client::GetFocusClient(params.new_parent) !=
212 aura::client::GetFocusClient(params.receiver))) {
213 WindowLostFocusFromDispositionChange(params.receiver, params.old_parent);
214 }
215 }
216
217 ////////////////////////////////////////////////////////////////////////////////
218 // FocusController, private:
219
220 void FocusController::SetFocusedWindow(aura::Window* window) {
221 if (updating_focus_ || window == focused_window_)
222 return;
223 DCHECK(rules_->CanFocusWindow(window));
224 if (window)
225 DCHECK_EQ(window, rules_->GetFocusableWindow(window));
226
227 base::AutoReset<bool> updating_focus(&updating_focus_, true);
228 aura::Window* lost_focus = focused_window_;
229
230 // |window| is going to get the focus, so reset the text input client.
231 // OnWindowFocused() may set a proper text input client if the implementation
232 // supports text input.
233 ui::TextInputFocusManager* text_input_focus_manager =
234 ui::TextInputFocusManager::GetInstance();
235 if (window)
236 text_input_focus_manager->FocusTextInputClient(NULL);
237
238 // Allow for the window losing focus to be deleted during dispatch. If it is
239 // deleted pass NULL to observers instead of a deleted window.
240 aura::WindowTracker window_tracker;
241 if (lost_focus)
242 window_tracker.Add(lost_focus);
243 if (focused_window_ && observer_manager_.IsObserving(focused_window_) &&
244 focused_window_ != active_window_) {
245 observer_manager_.Remove(focused_window_);
246 }
247 focused_window_ = window;
248 if (focused_window_ && !observer_manager_.IsObserving(focused_window_))
249 observer_manager_.Add(focused_window_);
250
251 FOR_EACH_OBSERVER(aura::client::FocusChangeObserver,
252 focus_observers_,
253 OnWindowFocused(focused_window_,
254 window_tracker.Contains(lost_focus) ?
255 lost_focus : NULL));
256 if (window_tracker.Contains(lost_focus)) {
257 aura::client::FocusChangeObserver* observer =
258 aura::client::GetFocusChangeObserver(lost_focus);
259 if (observer)
260 observer->OnWindowFocused(focused_window_, lost_focus);
261 }
262 aura::client::FocusChangeObserver* observer =
263 aura::client::GetFocusChangeObserver(focused_window_);
264 if (observer) {
265 observer->OnWindowFocused(
266 focused_window_,
267 window_tracker.Contains(lost_focus) ? lost_focus : NULL);
268 }
269
270 // Ensure that the text input client is reset when the window loses the focus.
271 if (!window)
272 text_input_focus_manager->FocusTextInputClient(NULL);
273 }
274
275 void FocusController::SetActiveWindow(aura::Window* requested_window,
276 aura::Window* window) {
277 if (updating_activation_)
278 return;
279
280 if (window == active_window_) {
281 if (requested_window) {
282 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
283 activation_observers_,
284 OnAttemptToReactivateWindow(requested_window,
285 active_window_));
286 }
287 return;
288 }
289
290 DCHECK(rules_->CanActivateWindow(window));
291 if (window)
292 DCHECK_EQ(window, rules_->GetActivatableWindow(window));
293
294 base::AutoReset<bool> updating_activation(&updating_activation_, true);
295 aura::Window* lost_activation = active_window_;
296 // Allow for the window losing activation to be deleted during dispatch. If
297 // it is deleted pass NULL to observers instead of a deleted window.
298 aura::WindowTracker window_tracker;
299 if (lost_activation)
300 window_tracker.Add(lost_activation);
301 if (active_window_ && observer_manager_.IsObserving(active_window_) &&
302 focused_window_ != active_window_) {
303 observer_manager_.Remove(active_window_);
304 }
305 active_window_ = window;
306 if (active_window_ && !observer_manager_.IsObserving(active_window_))
307 observer_manager_.Add(active_window_);
308 if (active_window_) {
309 StackTransientParentsBelowModalWindow(active_window_);
310 active_window_->parent()->StackChildAtTop(active_window_);
311 }
312
313 aura::client::ActivationChangeObserver* observer = NULL;
314 if (window_tracker.Contains(lost_activation)) {
315 observer = aura::client::GetActivationChangeObserver(lost_activation);
316 if (observer)
317 observer->OnWindowActivated(active_window_, lost_activation);
318 }
319 observer = aura::client::GetActivationChangeObserver(active_window_);
320 if (observer) {
321 observer->OnWindowActivated(
322 active_window_,
323 window_tracker.Contains(lost_activation) ? lost_activation : NULL);
324 }
325 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
326 activation_observers_,
327 OnWindowActivated(active_window_,
328 window_tracker.Contains(lost_activation) ?
329 lost_activation : NULL));
330 }
331
332 void FocusController::WindowLostFocusFromDispositionChange(
333 aura::Window* window,
334 aura::Window* next) {
335 // A window's modality state will interfere with focus restoration during its
336 // destruction.
337 window->ClearProperty(aura::client::kModalKey);
338 // TODO(beng): See if this function can be replaced by a call to
339 // FocusWindow().
340 // Activation adjustments are handled first in the event of a disposition
341 // changed. If an activation change is necessary, focus is reset as part of
342 // that process so there's no point in updating focus independently.
343 if (window == active_window_) {
344 aura::Window* next_activatable = rules_->GetNextActivatableWindow(window);
345 SetActiveWindow(NULL, next_activatable);
346 if (!(active_window_ && active_window_->Contains(focused_window_)))
347 SetFocusedWindow(next_activatable);
348 } else if (window->Contains(focused_window_)) {
349 // Active window isn't changing, but focused window might be.
350 SetFocusedWindow(rules_->GetFocusableWindow(next));
351 }
352 }
353
354 void FocusController::WindowFocusedFromInputEvent(aura::Window* window) {
355 // Only focus |window| if it or any of its parents can be focused. Otherwise
356 // FocusWindow() will focus the topmost window, which may not be the
357 // currently focused one.
358 if (rules_->CanFocusWindow(GetToplevelWindow(window)))
359 FocusWindow(window);
360 }
361
362 } // namespace wm
OLDNEW
« no previous file with comments | « ui/wm/core/focus_controller.h ('k') | ui/wm/core/focus_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698