OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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/aura_shell/activation_controller.h" | |
6 | |
7 #include "base/auto_reset.h" | |
8 #include "ui/aura/client/activation_delegate.h" | |
9 #include "ui/aura/root_window.h" | |
10 #include "ui/aura/window.h" | |
11 #include "ui/aura/window_delegate.h" | |
12 #include "ui/aura_shell/shell.h" | |
13 #include "ui/aura_shell/shell_window_ids.h" | |
14 #include "ui/aura_shell/window_util.h" | |
15 | |
16 namespace aura_shell { | |
17 namespace internal { | |
18 namespace { | |
19 | |
20 aura::Window* GetContainer(int id) { | |
21 return Shell::GetInstance()->GetContainer(id); | |
22 } | |
23 | |
24 // Returns true if children of |window| can be activated. | |
25 // These are the only containers in which windows can receive focus. | |
26 bool SupportsChildActivation(aura::Window* window) { | |
27 return window->id() == kShellWindowId_DefaultContainer || | |
28 window->id() == kShellWindowId_AlwaysOnTopContainer || | |
29 window->id() == kShellWindowId_ModalContainer || | |
30 window->id() == kShellWindowId_LockScreenContainer || | |
31 window->id() == kShellWindowId_LockModalContainer; | |
32 } | |
33 | |
34 // Returns true if |window| can be activated or deactivated. | |
35 // A window manager typically defines some notion of "top level window" that | |
36 // supports activation/deactivation. | |
37 bool CanActivateWindow(aura::Window* window) { | |
38 return window && | |
39 window->IsVisible() && | |
40 (!aura::client::GetActivationDelegate(window) || | |
41 aura::client::GetActivationDelegate(window)->ShouldActivate(NULL)) && | |
42 SupportsChildActivation(window->parent()); | |
43 } | |
44 | |
45 } // namespace | |
46 | |
47 //////////////////////////////////////////////////////////////////////////////// | |
48 // ActivationController, public: | |
49 | |
50 ActivationController::ActivationController() | |
51 : updating_activation_(false), | |
52 default_container_for_test_(NULL) { | |
53 aura::client::SetActivationClient(this); | |
54 aura::RootWindow::GetInstance()->AddRootWindowObserver(this); | |
55 } | |
56 | |
57 ActivationController::~ActivationController() { | |
58 aura::RootWindow::GetInstance()->RemoveRootWindowObserver(this); | |
59 } | |
60 | |
61 // static | |
62 aura::Window* ActivationController::GetActivatableWindow(aura::Window* window) { | |
63 aura::Window* parent = window->parent(); | |
64 aura::Window* child = window; | |
65 while (parent) { | |
66 if (SupportsChildActivation(parent)) | |
67 return child; | |
68 // If |child| isn't activatable, but has transient parent, trace | |
69 // that path instead. | |
70 if (child->transient_parent()) | |
71 return GetActivatableWindow(child->transient_parent()); | |
72 parent = parent->parent(); | |
73 child = child->parent(); | |
74 } | |
75 return NULL; | |
76 } | |
77 | |
78 //////////////////////////////////////////////////////////////////////////////// | |
79 // ActivationController, aura::client::ActivationClient implementation: | |
80 | |
81 void ActivationController::ActivateWindow(aura::Window* window) { | |
82 // Prevent recursion when called from focus. | |
83 if (updating_activation_) | |
84 return; | |
85 | |
86 AutoReset<bool> in_activate_window(&updating_activation_, true); | |
87 if (!window) | |
88 return; | |
89 // Nothing may actually have changed. | |
90 aura::Window* old_active = GetActiveWindow(); | |
91 if (old_active == window) | |
92 return; | |
93 // The stacking client may impose rules on what window configurations can be | |
94 // activated or deactivated. | |
95 if (!CanActivateWindow(window)) | |
96 return; | |
97 | |
98 if (!window->Contains(window->GetFocusManager()->GetFocusedWindow())) | |
99 window->GetFocusManager()->SetFocusedWindow(window); | |
100 aura::RootWindow::GetInstance()->SetProperty( | |
101 aura::client::kRootWindowActiveWindow, | |
102 window); | |
103 // Invoke OnLostActive after we've changed the active window. That way if the | |
104 // delegate queries for active state it doesn't think the window is still | |
105 // active. | |
106 if (old_active && aura::client::GetActivationDelegate(old_active)) | |
107 aura::client::GetActivationDelegate(old_active)->OnLostActive(); | |
108 if (window) { | |
109 window->parent()->StackChildAtTop(window); | |
110 if (aura::client::GetActivationDelegate(window)) | |
111 aura::client::GetActivationDelegate(window)->OnActivated(); | |
112 } | |
113 } | |
114 | |
115 void ActivationController::DeactivateWindow(aura::Window* window) { | |
116 if (window) | |
117 ActivateNextWindow(window); | |
118 } | |
119 | |
120 aura::Window* ActivationController::GetActiveWindow() { | |
121 return reinterpret_cast<aura::Window*>( | |
122 aura::RootWindow::GetInstance()->GetProperty( | |
123 aura::client::kRootWindowActiveWindow)); | |
124 } | |
125 | |
126 bool ActivationController::CanFocusWindow(aura::Window* window) const { | |
127 return CanActivateWindow(GetActivatableWindow(window)); | |
128 } | |
129 | |
130 //////////////////////////////////////////////////////////////////////////////// | |
131 // ActivationController, aura::WindowObserver implementation: | |
132 | |
133 void ActivationController::OnWindowVisibilityChanged(aura::Window* window, | |
134 bool visible) { | |
135 if (!visible) | |
136 ActivateNextWindow(window); | |
137 } | |
138 | |
139 void ActivationController::OnWindowDestroyed(aura::Window* window) { | |
140 if (IsActiveWindow(window)) { | |
141 // Clear the property before activating something else, since | |
142 // ActivateWindow() will attempt to notify the window stored in this value | |
143 // otherwise. | |
144 aura::RootWindow::GetInstance()->SetProperty( | |
145 aura::client::kRootWindowActiveWindow, | |
146 NULL); | |
147 ActivateWindow(GetTopmostWindowToActivate(window)); | |
148 } | |
149 window->RemoveObserver(this); | |
150 } | |
151 | |
152 //////////////////////////////////////////////////////////////////////////////// | |
153 // ActivationController, aura::RootWindowObserver implementation: | |
154 | |
155 void ActivationController::OnWindowInitialized(aura::Window* window) { | |
156 window->AddObserver(this); | |
157 } | |
158 | |
159 void ActivationController::OnWindowFocused(aura::Window* window) { | |
160 ActivateWindow(GetActivatableWindow(window)); | |
161 } | |
162 | |
163 //////////////////////////////////////////////////////////////////////////////// | |
164 // ActivationController, private: | |
165 | |
166 void ActivationController::ActivateNextWindow(aura::Window* window) { | |
167 if (IsActiveWindow(window)) | |
168 ActivateWindow(GetTopmostWindowToActivate(window)); | |
169 } | |
170 | |
171 aura::Window* ActivationController::GetTopmostWindowToActivate( | |
172 aura::Window* ignore) const { | |
173 const aura::Window* container = | |
174 default_container_for_test_ ? default_container_for_test_ : | |
175 GetContainer(kShellWindowId_DefaultContainer); | |
176 for (aura::Window::Windows::const_reverse_iterator i = | |
177 container->children().rbegin(); | |
178 i != container->children().rend(); | |
179 ++i) { | |
180 if (*i != ignore && CanActivateWindow(*i)) | |
181 return *i; | |
182 } | |
183 return NULL; | |
184 } | |
185 | |
186 } // namespace internal | |
187 } // namespace aura_shell | |
OLD | NEW |