OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 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 "chromecast/graphics/cast_focus_client_aura.h" | |
6 | |
7 #include "ui/aura/window.h" | |
8 | |
9 #define LOG_WINDOW_INFO(top_level, window) \ | |
10 "top-level: " << (top_level)->id() << ": '" << (top_level)->GetName() \ | |
11 << "', window: " << (window)->id() << ": '" \ | |
12 << (window)->GetName() << "'" | |
13 | |
14 namespace chromecast { | |
15 | |
16 CastFocusClientAura::CastFocusClientAura() : focused_window_(nullptr) {} | |
17 | |
18 CastFocusClientAura::~CastFocusClientAura() { | |
19 focused_window_ = nullptr; | |
20 for (aura::Window* window : focusable_windows_) { | |
21 window->RemoveObserver(this); | |
22 } | |
23 focusable_windows_.clear(); | |
24 } | |
25 | |
26 aura::Window* CastFocusClientAura::GetFocusedWindow() { | |
27 return focused_window_; | |
28 } | |
29 | |
30 void CastFocusClientAura::AddObserver( | |
31 aura::client::FocusChangeObserver* observer) { | |
32 focus_observers_.AddObserver(observer); | |
33 } | |
34 | |
35 void CastFocusClientAura::RemoveObserver( | |
36 aura::client::FocusChangeObserver* observer) { | |
37 focus_observers_.RemoveObserver(observer); | |
38 } | |
39 | |
40 void CastFocusClientAura::OnWindowVisibilityChanged(aura::Window* window, | |
41 bool visible) { | |
42 if (!visible && (window == focused_window_)) { | |
43 // The focused window just lost visibility, so de-focus it. | |
44 UpdateWindowFocus(); | |
45 } else if (visible) { | |
46 // The window that just became visible might be the most appropriate window | |
47 // to have focus. | |
48 UpdateWindowFocus(); | |
49 } | |
50 } | |
51 | |
52 // One of our observed windows is being destroyed. | |
53 // We observe each window that has the potential for being focused, | |
54 // so this window needs to be removed from the list of focusable windows. | |
55 void CastFocusClientAura::OnWindowDestroying(aura::Window* window) { | |
56 aura::Window* top_level = GetTopLevelWindow(window); | |
57 DCHECK(top_level); | |
58 LOG(INFO) << "Removing window, " << LOG_WINDOW_INFO(top_level, window); | |
sadrul
2017/01/26 01:50:10
Should these be DLOG?
Joshua LeVasseur
2017/01/26 02:51:00
Done.
| |
59 | |
60 auto iter = | |
61 std::find(focusable_windows_.begin(), focusable_windows_.end(), window); | |
62 if (iter != focusable_windows_.end()) { | |
63 focusable_windows_.erase(iter); | |
64 window->RemoveObserver(this); | |
65 } | |
66 if (window == focused_window_) { | |
67 // De-focus the window that is being destroyed. | |
68 UpdateWindowFocus(); | |
69 } | |
70 } | |
71 | |
72 // Update focus if a window is entering or leaving our hierarchy. | |
73 void CastFocusClientAura::OnWindowHierarchyChanging( | |
74 const HierarchyChangeParams& params) { | |
75 if (params.new_parent && | |
76 (aura::client::GetFocusClient(params.new_parent) == this)) { | |
77 if (params.old_parent == params.new_parent) { | |
78 // A window is moving within our hierarchy. | |
79 return; | |
80 } else { | |
81 // A window is entering our hierarchy, so we need to consider | |
82 // focusing it. | |
83 FocusWindow(params.target); | |
84 return; | |
85 } | |
86 } | |
87 | |
88 // The window is leaving our hierarchy, so stop tracking it. | |
89 // It could contain multiple windows that were focused, so lets stop tracking | |
90 // them all. | |
91 auto iter = focusable_windows_.begin(); | |
92 bool was_focused = false; | |
93 while (iter != focusable_windows_.end()) { | |
94 aura::Window* window = *iter; | |
95 if (params.target == window || params.target->Contains(window)) { | |
96 window->RemoveObserver(this); | |
97 was_focused |= window == focused_window_; | |
98 iter = focusable_windows_.erase(iter); | |
99 | |
100 aura::Window* top_level = GetTopLevelWindow(window); | |
101 DCHECK(top_level); | |
102 LOG(INFO) << "Dropping window, " << LOG_WINDOW_INFO(top_level, window); | |
103 } else { | |
104 ++iter; | |
105 } | |
106 } | |
107 | |
108 if (was_focused) { | |
109 // The window that was removed from our hierarchy was the focused window, so | |
110 // de-focus it. | |
111 UpdateWindowFocus(); | |
112 } | |
113 } | |
114 | |
115 // An explicit request to focus a window. | |
116 // We lock focus to the top-most high-level window, and so will ignore this | |
117 // focus request if it isn't for the topmost window. If it is for a lower | |
118 // window, then we'll track it to focus it later when it rises to the top. | |
119 void CastFocusClientAura::FocusWindow(aura::Window* window) { | |
120 if (window) { | |
121 if (!window->CanFocus()) { | |
122 return; | |
123 } | |
124 aura::Window* top_level = GetTopLevelWindow(window); | |
125 DCHECK(top_level); | |
126 LOG(INFO) << "Requesting focus for " << LOG_WINDOW_INFO(top_level, window); | |
127 auto iter = | |
128 std::find(focusable_windows_.begin(), focusable_windows_.end(), window); | |
129 if (iter == focusable_windows_.end()) { | |
130 // We're not yet tracking this focusable window, so start tracking it as a | |
131 // potential focus target. | |
132 window->AddObserver(this); | |
133 focusable_windows_.push_back(window); | |
134 } | |
135 } | |
136 | |
137 // Check whether this new window is the most appropriate to focus. | |
138 UpdateWindowFocus(); | |
139 } | |
140 | |
141 // Finds the top-most window, and if it doesn't have focus, then gives it focus. | |
142 void CastFocusClientAura::UpdateWindowFocus() { | |
143 aura::Window* window = GetWindowToFocus(); | |
144 if (window == focused_window_) { | |
145 return; | |
146 } | |
147 | |
148 if (window) { | |
149 aura::Window* top_level = GetTopLevelWindow(window); | |
150 DCHECK(top_level); | |
151 LOG(INFO) << "Switching focus to " << LOG_WINDOW_INFO(top_level, window); | |
152 } | |
153 | |
154 aura::Window* unfocus_window = focused_window_; | |
155 focused_window_ = window; | |
156 | |
157 for (aura::client::FocusChangeObserver& observer : focus_observers_) { | |
158 observer.OnWindowFocused(focused_window_, unfocus_window); | |
159 if (focused_window_ != window) { | |
160 // The observer changed focused_window_. | |
161 return; | |
162 } | |
163 } | |
164 | |
165 if (unfocus_window) { | |
166 aura::client::FocusChangeObserver* focus_observer = | |
167 aura::client::GetFocusChangeObserver(unfocus_window); | |
168 if (focus_observer) { | |
169 focus_observer->OnWindowFocused(focused_window_, unfocus_window); | |
170 if (focused_window_ != window) { | |
171 // The observer changed focused_window_. | |
172 return; | |
173 } | |
174 } | |
175 } | |
176 if (focused_window_) { | |
177 aura::client::FocusChangeObserver* focus_observer = | |
178 aura::client::GetFocusChangeObserver(focused_window_); | |
179 if (focus_observer) { | |
180 focus_observer->OnWindowFocused(focused_window_, unfocus_window); | |
181 if (focused_window_ != window) { | |
182 // The observer changed focused_window_. | |
183 return; | |
184 } | |
185 } | |
186 } | |
187 } | |
188 | |
189 // Returns the most appropriate window to have focus. | |
190 // A focusable window could be anywhere within its window hierarchy, and we | |
191 // choose based on the z-order of the top-level window in its hierarchy. | |
192 aura::Window* CastFocusClientAura::GetWindowToFocus() { | |
193 aura::Window* next = nullptr; | |
194 aura::Window* next_top_level = nullptr; | |
195 for (aura::Window* window : focusable_windows_) { | |
196 if (!window->CanFocus() || !window->IsVisible()) { | |
197 continue; | |
198 } | |
199 | |
200 // Compare z-order of top-level windows using the window IDs. | |
201 aura::Window* top_level = GetTopLevelWindow(window); | |
202 DCHECK(top_level); | |
203 if (!next || top_level->id() >= next_top_level->id()) { | |
204 next = window; | |
205 next_top_level = top_level; | |
206 } | |
207 } | |
208 return next; | |
209 } | |
210 | |
211 aura::Window* CastFocusClientAura::GetTopLevelWindow(aura::Window* window) { | |
212 while (window->parent() && !window->parent()->GetHost()) { | |
213 window = window->parent(); | |
214 } | |
215 return window; | |
sadrul
2017/01/26 01:50:10
Can you just use window->GetRootWindow(), instead
Joshua LeVasseur
2017/01/26 02:51:00
I want to get a child window of the root window (w
sadrul
2017/01/27 00:30:56
OK. Note that there is also Window::GetToplevelWin
Joshua LeVasseur
2017/01/27 04:53:44
To avoid conflict with existing names, I've rename
| |
216 } | |
217 | |
218 void CastFocusClientAura::ResetFocusWithinActiveWindow(aura::Window* window) { | |
219 // Sets focus to |window| if it's within the active window (a child of the | |
220 // focused window). | |
221 if (focused_window_ && focused_window_->Contains(window)) { | |
222 FocusWindow(window); | |
223 } | |
224 } | |
225 | |
226 } // namespace chromecast | |
OLD | NEW |