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

Side by Side Diff: mojo/services/window_manager/focus_controller.cc

Issue 765753003: Move window_manager service implementation to //services (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years 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
(Empty)
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 "mojo/services/window_manager/focus_controller.h"
6
7 #include "base/auto_reset.h"
8 #include "mojo/services/public/cpp/view_manager/view_property.h"
9 #include "mojo/services/public/cpp/view_manager/view_tracker.h"
10 #include "mojo/services/window_manager/focus_controller_observer.h"
11 #include "mojo/services/window_manager/focus_rules.h"
12 #include "mojo/services/window_manager/view_target.h"
13 #include "mojo/services/window_manager/window_manager_app.h"
14 #include "ui/events/event.h"
15
16 DECLARE_VIEW_PROPERTY_TYPE(mojo::FocusController*);
17
18 namespace mojo {
19
20 namespace {
21 DEFINE_VIEW_PROPERTY_KEY(FocusController*, kRootViewFocusController, nullptr);
22 } // namespace
23
24 FocusController::FocusController(scoped_ptr<FocusRules> rules)
25 : active_view_(nullptr),
26 focused_view_(nullptr),
27 updating_focus_(false),
28 updating_activation_(false),
29 rules_(rules.Pass()),
30 observer_manager_(this) {
31 DCHECK(rules_);
32 }
33
34 FocusController::~FocusController() {}
35
36 void FocusController::AddObserver(FocusControllerObserver* observer) {
37 focus_controller_observers_.AddObserver(observer);
38 }
39
40 void FocusController::RemoveObserver(FocusControllerObserver* observer) {
41 focus_controller_observers_.RemoveObserver(observer);
42 }
43
44 void FocusController::ActivateView(View* view) {
45 FocusView(view);
46 }
47
48 void FocusController::DeactivateView(View* view) {
49 if (view)
50 FocusView(rules_->GetNextActivatableView(view));
51 }
52
53 View* FocusController::GetActiveView() {
54 return active_view_;
55 }
56
57 View* FocusController::GetActivatableView(View* view) {
58 return rules_->GetActivatableView(view);
59 }
60
61 View* FocusController::GetToplevelView(View* view) {
62 return rules_->GetToplevelView(view);
63 }
64
65 bool FocusController::CanActivateView(View* view) const {
66 return rules_->CanActivateView(view);
67 }
68
69 void FocusController::FocusView(View* view) {
70 if (view &&
71 (view->Contains(focused_view_) || view->Contains(active_view_))) {
72 return;
73 }
74
75 // TODO(erg): We need to early abort in the of a view having
76 // capture. However, we currently don't have a capture client here.
77
78 // Focusing a window also activates its containing activatable window. Note
79 // that the rules could redirect activation activation and/or focus.
80 View* focusable = rules_->GetFocusableView(view);
81 View* activatable =
82 focusable ? rules_->GetActivatableView(focusable) : nullptr;
83
84 // We need valid focusable/activatable windows in the event we're not clearing
85 // focus. "Clearing focus" is inferred by whether or not |window| passed to
86 // this function is non-null.
87 if (view && (!focusable || !activatable))
88 return;
89 DCHECK((focusable && activatable) || !view);
90
91 // Activation change observers may change the focused window. If this happens
92 // we must not adjust the focus below since this will clobber that change.
93 View* last_focused_view = focused_view_;
94 if (!updating_activation_)
95 SetActiveView(view, activatable);
96
97 // If the window's ActivationChangeObserver shifted focus to a valid window,
98 // we don't want to focus the window we thought would be focused by default.
99 bool activation_changed_focus = last_focused_view != focused_view_;
100 if (!updating_focus_ && (!activation_changed_focus || !focused_view_)) {
101 if (active_view_ && focusable)
102 DCHECK(active_view_->Contains(focusable));
103 SetFocusedView(focusable);
104 }
105 }
106
107 void FocusController::ResetFocusWithinActiveView(View* view) {
108 DCHECK(view);
109 if (!active_view_)
110 return;
111 if (!active_view_->Contains(view))
112 return;
113 SetFocusedView(view);
114 }
115
116 View* FocusController::GetFocusedView() {
117 return focused_view_;
118 }
119
120 ////////////////////////////////////////////////////////////////////////////////
121 // FocusController, ui::EventHandler implementation:
122
123 void FocusController::OnKeyEvent(ui::KeyEvent* event) {
124 }
125
126 void FocusController::OnMouseEvent(ui::MouseEvent* event) {
127 if (event->type() == ui::ET_MOUSE_PRESSED && !event->handled()) {
128 View* view = static_cast<ViewTarget*>(event->target())->view();
129 ViewFocusedFromInputEvent(view);
130 }
131 }
132
133 void FocusController::OnScrollEvent(ui::ScrollEvent* event) {
134 }
135
136 void FocusController::OnTouchEvent(ui::TouchEvent* event) {
137 }
138
139 void FocusController::OnGestureEvent(ui::GestureEvent* event) {
140 if (event->type() == ui::ET_GESTURE_BEGIN &&
141 event->details().touch_points() == 1 &&
142 !event->handled()) {
143 View* view = static_cast<ViewTarget*>(event->target())->view();
144 ViewFocusedFromInputEvent(view);
145 }
146 }
147
148 ////////////////////////////////////////////////////////////////////////////////
149 // FocusController, aura::WindowObserver implementation:
150
151 void FocusController::OnViewVisibilityChanged(View* view) {
152 bool visible = view->visible();
153 if (!visible)
154 ViewLostFocusFromDispositionChange(view, view->parent());
155 }
156
157 void FocusController::OnViewDestroying(View* view) {
158 ViewLostFocusFromDispositionChange(view, view->parent());
159 }
160
161 void FocusController::OnTreeChanging(const TreeChangeParams& params) {
162 // TODO(erg): In the aura version, you could get into a situation where you
163 // have different focus clients, so you had to check for that. Does that
164 // happen here? Could we get away with not checking if it does?
165 if (params.receiver == active_view_ &&
166 params.target->Contains(params.receiver) &&
167 (!params.new_parent ||
168 /* different_focus_clients */ false)) {
169 ViewLostFocusFromDispositionChange(params.receiver, params.old_parent);
170 }
171 }
172
173 void FocusController::OnTreeChanged(const TreeChangeParams& params) {
174 // TODO(erg): Same as Changing version.
175 if (params.receiver == focused_view_ &&
176 params.target->Contains(params.receiver) &&
177 (!params.new_parent ||
178 /* different_focus_clients */ false)) {
179 ViewLostFocusFromDispositionChange(params.receiver, params.old_parent);
180 }
181 }
182
183 ////////////////////////////////////////////////////////////////////////////////
184 // FocusController, private:
185
186 void FocusController::SetFocusedView(View* view) {
187 if (updating_focus_ || view == focused_view_)
188 return;
189 DCHECK(rules_->CanFocusView(view));
190 if (view)
191 DCHECK_EQ(view, rules_->GetFocusableView(view));
192
193 base::AutoReset<bool> updating_focus(&updating_focus_, true);
194 View* lost_focus = focused_view_;
195
196 // TODO(erg): In the aura version, we reset the text input client here. Do
197 // that if we bring in something like the TextInputClient.
198
199 // Allow for the window losing focus to be deleted during dispatch. If it is
200 // deleted pass null to observers instead of a deleted window.
201 ViewTracker view_tracker;
202 if (lost_focus)
203 view_tracker.Add(lost_focus);
204 if (focused_view_ && observer_manager_.IsObserving(focused_view_) &&
205 focused_view_ != active_view_) {
206 observer_manager_.Remove(focused_view_);
207 }
208 focused_view_ = view;
209 if (focused_view_ && !observer_manager_.IsObserving(focused_view_))
210 observer_manager_.Add(focused_view_);
211
212 FOR_EACH_OBSERVER(FocusControllerObserver,
213 focus_controller_observers_,
214 OnViewFocused(focused_view_,
215 view_tracker.Contains(lost_focus) ?
216 lost_focus : nullptr));
217
218 // TODO(erg): In aura, there's a concept of a single FocusChangeObserver that
219 // is attached to an aura::Window. We don't currently have this in
220 // mojo::View, but if we add it later, we should make something analogous
221 // here.
222
223 // TODO(erg): In the aura version, we reset the TextInputClient here, too.
224 }
225
226 void FocusController::SetActiveView(View* requested_view, View* view) {
227 if (updating_activation_)
228 return;
229
230 if (view == active_view_) {
231 if (requested_view) {
232 FOR_EACH_OBSERVER(FocusControllerObserver,
233 focus_controller_observers_,
234 OnAttemptToReactivateView(requested_view,
235 active_view_));
236 }
237 return;
238 }
239
240 DCHECK(rules_->CanActivateView(view));
241 if (view)
242 DCHECK_EQ(view, rules_->GetActivatableView(view));
243
244 base::AutoReset<bool> updating_activation(&updating_activation_, true);
245 View* lost_activation = active_view_;
246 // Allow for the window losing activation to be deleted during dispatch. If
247 // it is deleted pass null to observers instead of a deleted window.
248 ViewTracker view_tracker;
249 if (lost_activation)
250 view_tracker.Add(lost_activation);
251 if (active_view_ && observer_manager_.IsObserving(active_view_) &&
252 focused_view_ != active_view_) {
253 observer_manager_.Remove(active_view_);
254 }
255 active_view_ = view;
256 if (active_view_ && !observer_manager_.IsObserving(active_view_))
257 observer_manager_.Add(active_view_);
258
259 if (active_view_) {
260 // TODO(erg): Reenable this when we have modal windows.
261 // StackTransientParentsBelowModalWindow(active_view_);
262
263 active_view_->MoveToFront();
264 }
265
266 // TODO(erg): Individual windows can have a single ActivationChangeObserver
267 // set on them. In the aura version of this code, it sends an
268 // OnWindowActivated message to both the window that lost activation, and the
269 // window that gained it.
270
271 FOR_EACH_OBSERVER(FocusControllerObserver,
272 focus_controller_observers_,
273 OnViewActivated(active_view_,
274 view_tracker.Contains(lost_activation) ?
275 lost_activation : nullptr));
276 }
277
278 void FocusController::ViewLostFocusFromDispositionChange(
279 View* view,
280 View* next) {
281 // TODO(erg): We clear the modality state here in the aura::Window version of
282 // this class, and should probably do the same once we have modal windows.
283
284 // TODO(beng): See if this function can be replaced by a call to
285 // FocusWindow().
286 // Activation adjustments are handled first in the event of a disposition
287 // changed. If an activation change is necessary, focus is reset as part of
288 // that process so there's no point in updating focus independently.
289 if (view == active_view_) {
290 View* next_activatable = rules_->GetNextActivatableView(view);
291 SetActiveView(nullptr, next_activatable);
292 if (!(active_view_ && active_view_->Contains(focused_view_)))
293 SetFocusedView(next_activatable);
294 } else if (view->Contains(focused_view_)) {
295 // Active window isn't changing, but focused window might be.
296 SetFocusedView(rules_->GetFocusableView(next));
297 }
298 }
299
300 void FocusController::ViewFocusedFromInputEvent(View* view) {
301 // Only focus |window| if it or any of its parents can be focused. Otherwise
302 // FocusWindow() will focus the topmost window, which may not be the
303 // currently focused one.
304 if (rules_->CanFocusView(GetToplevelView(view)))
305 FocusView(view);
306 }
307
308 void SetFocusController(View* root_view, FocusController* focus_controller) {
309 DCHECK_EQ(root_view->GetRoot(), root_view);
310 root_view->SetLocalProperty(kRootViewFocusController, focus_controller);
311 }
312
313 FocusController* GetFocusController(View* root_view) {
314 if (root_view)
315 DCHECK_EQ(root_view->GetRoot(), root_view);
316 return root_view ?
317 root_view->GetLocalProperty(kRootViewFocusController) : nullptr;
318 }
319
320 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/services/window_manager/focus_controller.h ('k') | mojo/services/window_manager/focus_controller_observer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698