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

Side by Side Diff: ash/wm/activation_controller.cc

Issue 23874013: Remove old activation code and disable-focus-controller flags (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 3 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 | Annotate | Revision Log
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 "ash/wm/activation_controller.h"
6
7 #include "ash/root_window_controller.h"
8 #include "ash/shell.h"
9 #include "ash/shell_window_ids.h"
10 #include "ash/wm/activation_controller_delegate.h"
11 #include "ash/wm/property_util.h"
12 #include "ash/wm/window_util.h"
13 #include "base/auto_reset.h"
14 #include "ui/aura/client/activation_change_observer.h"
15 #include "ui/aura/client/activation_delegate.h"
16 #include "ui/aura/client/aura_constants.h"
17 #include "ui/aura/client/focus_client.h"
18 #include "ui/aura/env.h"
19 #include "ui/aura/root_window.h"
20 #include "ui/aura/window.h"
21 #include "ui/aura/window_delegate.h"
22 #include "ui/base/ui_base_types.h"
23 #include "ui/compositor/layer.h"
24 #include "ui/views/corewm/window_modality_controller.h"
25
26 namespace ash {
27 namespace internal {
28 namespace {
29
30 // These are the list of container ids of containers which may contain windows
31 // that need to be activated in the order that they should be activated.
32 const int kWindowContainerIds[] = {
33 kShellWindowId_LockSystemModalContainer,
34 kShellWindowId_SettingBubbleContainer,
35 kShellWindowId_LockScreenContainer,
36 kShellWindowId_SystemModalContainer,
37 kShellWindowId_AlwaysOnTopContainer,
38 kShellWindowId_AppListContainer,
39 kShellWindowId_DefaultContainer,
40
41 // Docked, panel, launcher and status are intentionally checked after other
42 // containers even though these layers are higher. The user expects their
43 // windows to be focused before these elements.
44 kShellWindowId_DockedContainer,
45 kShellWindowId_PanelContainer,
46 kShellWindowId_ShelfContainer,
47 kShellWindowId_StatusContainer,
48 };
49
50 bool BelongsToContainerWithEqualOrGreaterId(const aura::Window* window,
51 int container_id) {
52 for (; window; window = window->parent()) {
53 if (window->id() >= container_id)
54 return true;
55 }
56 return false;
57 }
58
59 // Returns true if children of |window| can be activated.
60 // These are the only containers in which windows can receive focus.
61 bool SupportsChildActivation(aura::Window* window) {
62 for (size_t i = 0; i < arraysize(kWindowContainerIds); i++) {
63 if (window->id() == kWindowContainerIds[i])
64 return true;
65 }
66 return false;
67 }
68
69 bool HasModalTransientChild(aura::Window* window) {
70 aura::Window::Windows::const_iterator it;
71 for (it = window->transient_children().begin();
72 it != window->transient_children().end();
73 ++it) {
74 if ((*it)->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_WINDOW)
75 return true;
76 }
77 return false;
78 }
79
80 // See description in VisibilityMatches.
81 enum ActivateVisibilityType {
82 TARGET_VISIBILITY,
83 CURRENT_VISIBILITY,
84 };
85
86 // Used by CanActivateWindowWithEvent() to test the visibility of a window.
87 // This is used by two distinct code paths:
88 // . when activating from an event we only care about the actual visibility.
89 // . when activating because of a keyboard accelerator, in which case we
90 // care about the TargetVisibility.
91 bool VisibilityMatches(aura::Window* window, ActivateVisibilityType type) {
92 bool visible = (type == CURRENT_VISIBILITY) ? window->IsVisible() :
93 window->TargetVisibility();
94 return visible || wm::IsWindowMinimized(window) ||
95 (window->TargetVisibility() &&
96 (window->parent()->id() == kShellWindowId_DefaultContainer ||
97 window->parent()->id() == kShellWindowId_LockScreenContainer));
98 }
99
100 // Returns true if |window| can be activated or deactivated.
101 // A window manager typically defines some notion of "top level window" that
102 // supports activation/deactivation.
103 bool CanActivateWindowWithEvent(aura::Window* window,
104 const ui::Event* event,
105 ActivateVisibilityType visibility_type) {
106 return window &&
107 VisibilityMatches(window, visibility_type) &&
108 (!aura::client::GetActivationDelegate(window) ||
109 aura::client::GetActivationDelegate(window)->ShouldActivate()) &&
110 SupportsChildActivation(window->parent()) &&
111 (BelongsToContainerWithEqualOrGreaterId(
112 window, kShellWindowId_SystemModalContainer) ||
113 !Shell::GetInstance()->IsSystemModalWindowOpen());
114 }
115
116 // When a modal window is activated, we bring its entire transient parent chain
117 // to the front. This function must be called before the modal transient is
118 // stacked at the top to ensure correct stacking order.
119 void StackTransientParentsBelowModalWindow(aura::Window* window) {
120 if (window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_WINDOW)
121 return;
122
123 aura::Window* transient_parent = window->transient_parent();
124 while (transient_parent) {
125 transient_parent->parent()->StackChildAtTop(transient_parent);
126 transient_parent = transient_parent->transient_parent();
127 }
128 }
129
130 aura::Window* FindFocusableWindowFor(aura::Window* window) {
131 while (window && !window->CanFocus())
132 window = window->parent();
133 return window;
134 }
135
136 } // namespace
137
138 ////////////////////////////////////////////////////////////////////////////////
139 // ActivationController, public:
140
141 ActivationController::ActivationController(
142 aura::client::FocusClient* focus_client,
143 ActivationControllerDelegate* delegate)
144 : focus_client_(focus_client),
145 updating_activation_(false),
146 active_window_(NULL),
147 observer_manager_(this),
148 delegate_(delegate) {
149 aura::Env::GetInstance()->AddObserver(this);
150 focus_client_->AddObserver(this);
151 }
152
153 ActivationController::~ActivationController() {
154 aura::Env::GetInstance()->RemoveObserver(this);
155 focus_client_->RemoveObserver(this);
156 }
157
158 // static
159 aura::Window* ActivationController::GetActivatableWindow(
160 aura::Window* window,
161 const ui::Event* event) {
162 aura::Window* parent = window->parent();
163 aura::Window* child = window;
164 while (parent) {
165 if (CanActivateWindowWithEvent(child, event, CURRENT_VISIBILITY))
166 return child;
167 // If |child| isn't activatable, but has transient parent, trace
168 // that path instead.
169 if (child->transient_parent())
170 return GetActivatableWindow(child->transient_parent(), event);
171 parent = parent->parent();
172 child = child->parent();
173 }
174 return NULL;
175 }
176
177 bool ActivationController::CanActivateWindow(aura::Window* window) const {
178 return CanActivateWindowWithEvent(window, NULL, TARGET_VISIBILITY) &&
179 !HasModalTransientChild(window);
180 }
181
182 ////////////////////////////////////////////////////////////////////////////////
183 // ActivationController, aura::client::ActivationClient implementation:
184
185 void ActivationController::AddObserver(
186 aura::client::ActivationChangeObserver* observer) {
187 observers_.AddObserver(observer);
188 }
189
190 void ActivationController::RemoveObserver(
191 aura::client::ActivationChangeObserver* observer) {
192 observers_.RemoveObserver(observer);
193 }
194
195 void ActivationController::ActivateWindow(aura::Window* window) {
196 ActivateWindowWithEvent(window, NULL);
197 }
198
199 void ActivationController::DeactivateWindow(aura::Window* window) {
200 if (window)
201 ActivateNextWindow(window);
202 }
203
204 aura::Window* ActivationController::GetActiveWindow() {
205 return active_window_;
206 }
207
208 aura::Window* ActivationController::GetActivatableWindow(aura::Window* window) {
209 return GetActivatableWindow(window, NULL);
210 }
211
212 aura::Window* ActivationController::GetToplevelWindow(aura::Window* window) {
213 return GetActivatableWindow(window, NULL);
214 }
215
216 bool ActivationController::OnWillFocusWindow(aura::Window* window,
217 const ui::Event* event) {
218 return CanActivateWindowWithEvent(
219 GetActivatableWindow(window, event), event, CURRENT_VISIBILITY);
220 }
221
222 ////////////////////////////////////////////////////////////////////////////////
223 // ActivationController, aura::WindowObserver implementation:
224
225 void ActivationController::OnWindowVisibilityChanged(aura::Window* window,
226 bool visible) {
227 if (!visible) {
228 aura::Window* next_window = ActivateNextWindow(window);
229 if (next_window && next_window->parent() == window->parent()) {
230 // Despite the activation change, we need to keep the window being hidden
231 // stacked above the new window so it stays on top as it animates away.
232 window->layer()->parent()->StackAbove(window->layer(),
233 next_window->layer());
234 }
235 }
236 }
237
238 void ActivationController::OnWindowDestroying(aura::Window* window) {
239 // Don't use wm::IsActiveWidnow in case the |window| has already been
240 // removed from the root tree.
241 if (active_window_ == window) {
242 active_window_ = NULL;
243 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
244 observers_,
245 OnWindowActivated(NULL, window));
246 ActivateWindow(GetTopmostWindowToActivate(window));
247 }
248 observer_manager_.Remove(window);
249 }
250
251 ////////////////////////////////////////////////////////////////////////////////
252 // ActivationController, aura::EnvObserver implementation:
253
254 void ActivationController::OnWindowInitialized(aura::Window* window) {
255 observer_manager_.Add(window);
256 }
257
258 ////////////////////////////////////////////////////////////////////////////////
259 // ActivationController, aura::RootWindowObserver implementation:
260
261 void ActivationController::OnWindowFocused(aura::Window* gained_focus,
262 aura::Window* lost_focus) {
263 if (gained_focus)
264 ActivateWindow(GetActivatableWindow(gained_focus, NULL));
265 }
266
267 ////////////////////////////////////////////////////////////////////////////////
268 // ActivationController, ui::EventHandler implementation:
269
270 void ActivationController::OnKeyEvent(ui::KeyEvent* event) {
271 }
272
273 void ActivationController::OnMouseEvent(ui::MouseEvent* event) {
274 if (event->type() == ui::ET_MOUSE_PRESSED)
275 FocusWindowWithEvent(event);
276 }
277
278 void ActivationController::OnScrollEvent(ui::ScrollEvent* event) {
279 }
280
281 void ActivationController::OnTouchEvent(ui::TouchEvent* event) {
282 if (event->type() == ui::ET_TOUCH_PRESSED)
283 FocusWindowWithEvent(event);
284 }
285
286 void ActivationController::OnGestureEvent(ui::GestureEvent* event) {
287 if (event->type() == ui::ET_GESTURE_BEGIN &&
288 event->details().touch_points() == 1) {
289 FocusWindowWithEvent(event);
290 }
291 }
292
293 ////////////////////////////////////////////////////////////////////////////////
294 // ActivationController, private:
295
296 void ActivationController::ActivateWindowWithEvent(aura::Window* window,
297 const ui::Event* event) {
298 // Prevent recursion when called from focus.
299 if (updating_activation_)
300 return;
301 base::AutoReset<bool> in_activate_window(&updating_activation_, true);
302
303 // We allow the delegate to change which window gets activated, or to prevent
304 // activation changes.
305 aura::Window* original_active_window = window;
306 window = delegate_->WillActivateWindow(window);
307 // TODO(beng): note that this breaks the previous behavior where an activation
308 // attempt by a window behind the lock screen would at least
309 // restack that window frontmost within its container. fix this.
310 if (!window && original_active_window != window)
311 return;
312
313 // TODO(beng): This encapsulates additional Ash-specific restrictions on
314 // whether activation can change. Should move to the delegate.
315 if (window && !CanActivateWindowWithEvent(window, event, CURRENT_VISIBILITY))
316 return;
317
318 if (active_window_ == window)
319 return;
320
321 aura::Window* old_active = active_window_;
322 active_window_ = window;
323
324 if (window &&
325 !window->Contains(aura::client::GetFocusClient(window)->
326 GetFocusedWindow())) {
327 aura::client::GetFocusClient(window)->FocusWindow(window);
328 }
329
330 if (window) {
331 StackTransientParentsBelowModalWindow(window);
332 window->parent()->StackChildAtTop(window);
333 }
334
335 FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
336 observers_,
337 OnWindowActivated(window, old_active));
338 if (aura::client::GetActivationChangeObserver(old_active)) {
339 aura::client::GetActivationChangeObserver(old_active)->OnWindowActivated(
340 window, old_active);
341 }
342 if (aura::client::GetActivationChangeObserver(window)) {
343 aura::client::GetActivationChangeObserver(window)->OnWindowActivated(
344 window, old_active);
345 }
346 }
347
348 aura::Window* ActivationController::ActivateNextWindow(aura::Window* window) {
349 aura::Window* next_window = NULL;
350 if (wm::IsActiveWindow(window)) {
351 next_window = GetTopmostWindowToActivate(window);
352 ActivateWindow(next_window);
353 }
354 return next_window;
355 }
356
357 aura::Window* ActivationController::GetTopmostWindowToActivate(
358 aura::Window* ignore) const {
359 size_t current_container_index = 0;
360 // If the container of the window losing focus is in the list, start from that
361 // container.
362 aura::RootWindow* root = ignore->GetRootWindow();
363 if (!root)
364 root = Shell::GetActiveRootWindow();
365 for (size_t i = 0; ignore && i < arraysize(kWindowContainerIds); i++) {
366 aura::Window* container = Shell::GetContainer(root, kWindowContainerIds[i]);
367 if (container && container->Contains(ignore)) {
368 current_container_index = i;
369 break;
370 }
371 }
372
373 // Look for windows to focus in that container and below.
374 aura::Window* window = NULL;
375 for (; !window && current_container_index < arraysize(kWindowContainerIds);
376 current_container_index++) {
377 aura::Window::Windows containers = Shell::GetContainersFromAllRootWindows(
378 kWindowContainerIds[current_container_index],
379 root);
380 for (aura::Window::Windows::const_iterator iter = containers.begin();
381 iter != containers.end() && !window; ++iter) {
382 window = GetTopmostWindowToActivateInContainer((*iter), ignore);
383 }
384 }
385 return window;
386 }
387
388 aura::Window* ActivationController::GetTopmostWindowToActivateInContainer(
389 aura::Window* container,
390 aura::Window* ignore) const {
391 for (aura::Window::Windows::const_reverse_iterator i =
392 container->children().rbegin();
393 i != container->children().rend();
394 ++i) {
395 if (*i != ignore &&
396 CanActivateWindowWithEvent(*i, NULL, CURRENT_VISIBILITY) &&
397 !wm::IsWindowMinimized(*i))
398 return *i;
399 }
400 return NULL;
401 }
402
403 void ActivationController::FocusWindowWithEvent(const ui::Event* event) {
404 aura::Window* window = static_cast<aura::Window*>(event->target());
405 window = delegate_->WillFocusWindow(window);
406 if (GetActiveWindow() != window) {
407 aura::client::GetFocusClient(window)->FocusWindow(
408 FindFocusableWindowFor(window));
409 }
410 }
411
412 } // namespace internal
413 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698