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

Side by Side Diff: chromecast/graphics/cast_focus_client_aura.cc

Issue 2636303002: [Chromecast] Add support for z-order and window focus. (Closed)
Patch Set: more tests, and bug fix found by test Created 3 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
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698