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

Side by Side Diff: views/focus/focus_manager.cc

Issue 141013: Relanding focus manager refactoring (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 6 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
« no previous file with comments | « views/focus/focus_manager.h ('k') | views/focus/focus_manager_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "views/focus/focus_manager.h" 5 #include "views/focus/focus_manager.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "build/build_config.h" 9 #include "build/build_config.h"
10 10
11 #if defined(OS_LINUX) 11 #if defined(OS_LINUX)
12 #include <gtk/gtk.h> 12 #include <gtk/gtk.h>
13 #endif 13 #endif
14 14
15 #include "base/histogram.h"
16 #include "base/logging.h" 15 #include "base/logging.h"
17 #include "views/accelerator.h" 16 #include "views/accelerator.h"
18 #include "views/focus/view_storage.h" 17 #include "views/focus/view_storage.h"
19 #include "views/view.h" 18 #include "views/view.h"
20 #include "views/widget/root_view.h" 19 #include "views/widget/root_view.h"
21 #include "views/widget/widget.h" 20 #include "views/widget/widget.h"
22 21
23 #if defined(OS_WIN) 22 #if defined(OS_WIN)
24 #include "base/win_util.h" 23 #include "base/win_util.h"
25 #endif 24 #endif
26 25
27 // The following keys are used in SetProp/GetProp to associate additional
28 // information needed for focus tracking with a window.
29
30 // Maps to the FocusManager instance for a top level window. See
31 // CreateFocusManager/DestoryFocusManager for usage.
32 static const wchar_t* const kFocusManagerKey = L"__VIEW_CONTAINER__";
33
34 // Maps to the View associated with a window.
35 // We register views with window so we can:
36 // - keep in sync the native focus with the view focus (when the native
37 // component gets the focus, we get the WM_SETFOCUS event and we can focus the
38 // associated view).
39 // - prevent tab key events from being sent to views.
40 static const wchar_t* const kViewKey = L"__CHROME_VIEW__";
41
42 // A property set to 1 to indicate whether the focus manager has subclassed that
43 // window. We are doing this to ensure we are not subclassing several times.
44 // Subclassing twice is not a problem if no one is subclassing the HWND between
45 // the 2 subclassings (the 2nd subclassing is ignored since the WinProc is the
46 // same as the current one). However if some other app goes and subclasses the
47 // HWND between the 2 subclassings, we will end up subclassing twice.
48 // This flag lets us test that whether we have or not subclassed yet.
49 static const wchar_t* const kFocusSubclassInstalled =
50 L"__FOCUS_SUBCLASS_INSTALLED__";
51
52 namespace views { 26 namespace views {
53 27
54 #if defined(OS_WIN)
55 // Callback installed via InstallFocusSubclass.
56 static LRESULT CALLBACK FocusWindowCallback(HWND window, UINT message,
57 WPARAM wParam, LPARAM lParam) {
58 if (!::IsWindow(window)) {
59 // QEMU has reported crashes when calling GetProp (this seems to happen for
60 // some weird messages, not sure what they are).
61 // Here we are just trying to avoid the crasher.
62 NOTREACHED();
63 return 0;
64 }
65
66 WNDPROC original_handler = win_util::GetSuperclassWNDPROC(window);
67 DCHECK(original_handler);
68 FocusManager* focus_manager = FocusManager::GetFocusManager(window);
69 // There are cases when we have no FocusManager for the window. This happens
70 // because we subclass certain windows (such as the TabContents window)
71 // but that window may not have an associated FocusManager.
72 if (focus_manager) {
73 switch (message) {
74 case WM_NCDESTROY:
75 if (!focus_manager->OnNCDestroy(window))
76 return 0;
77 break;
78 default:
79 break;
80 }
81 }
82 return CallWindowProc(original_handler, window, message, wParam, lParam);
83 }
84
85 #endif
86
87 // FocusManager ----------------------------------------------------- 28 // FocusManager -----------------------------------------------------
88 29
89 #if defined(OS_WIN) 30 FocusManager::FocusManager(Widget* widget)
90 // static 31 : widget_(widget),
91 FocusManager* FocusManager::CreateFocusManager(HWND window, 32 focused_view_(NULL) {
92 RootView* root_view) { 33 DCHECK(widget_);
93 DCHECK(window);
94 DCHECK(root_view);
95 InstallFocusSubclass(window, NULL);
96 FocusManager* focus_manager = new FocusManager(window, root_view);
97 SetProp(window, kFocusManagerKey, focus_manager);
98
99 return focus_manager;
100 }
101
102 // static
103 void FocusManager::InstallFocusSubclass(HWND window, View* view) {
104 DCHECK(window);
105
106 bool already_subclassed =
107 reinterpret_cast<bool>(GetProp(window,
108 kFocusSubclassInstalled));
109 if (already_subclassed &&
110 !win_util::IsSubclassed(window, &FocusWindowCallback)) {
111 NOTREACHED() << "window sub-classed by someone other than the FocusManager";
112 // Track in UMA so we know if this case happens.
113 UMA_HISTOGRAM_COUNTS("FocusManager.MultipleSubclass", 1);
114 } else {
115 win_util::Subclass(window, &FocusWindowCallback);
116 SetProp(window, kFocusSubclassInstalled, reinterpret_cast<HANDLE>(true));
117 }
118 if (view)
119 SetProp(window, kViewKey, view);
120 }
121
122 void FocusManager::UninstallFocusSubclass(HWND window) {
123 DCHECK(window);
124 if (win_util::Unsubclass(window, &FocusWindowCallback)) {
125 RemoveProp(window, kViewKey);
126 RemoveProp(window, kFocusSubclassInstalled);
127 }
128 }
129
130 #endif
131
132 // static
133 FocusManager* FocusManager::GetFocusManager(gfx::NativeView window) {
134 #if defined(OS_WIN)
135 DCHECK(window);
136
137 // In case parent windows belong to a different process, yet
138 // have the kFocusManagerKey property set, we have to be careful
139 // to also check the process id of the window we're checking.
140 DWORD window_pid = 0, current_pid = GetCurrentProcessId();
141 FocusManager* focus_manager;
142 for (focus_manager = NULL; focus_manager == NULL && IsWindow(window);
143 window = GetParent(window)) {
144 GetWindowThreadProcessId(window, &window_pid);
145 if (current_pid != window_pid)
146 break;
147 focus_manager = reinterpret_cast<FocusManager*>(
148 GetProp(window, kFocusManagerKey));
149 }
150 return focus_manager;
151 #else
152 NOTIMPLEMENTED();
153 return NULL;
154 #endif
155 }
156
157 #if defined(OS_WIN)
158 // static
159 View* FocusManager::GetViewForWindow(gfx::NativeView window, bool look_in_parent s) {
160 DCHECK(window);
161 do {
162 View* v = reinterpret_cast<View*>(GetProp(window, kViewKey));
163 if (v)
164 return v;
165 } while (look_in_parents && (window = ::GetParent(window)));
166 return NULL;
167 }
168
169 FocusManager::FocusManager(HWND root, RootView* root_view)
170 : root_(root),
171 top_root_view_(root_view),
172 focused_view_(NULL),
173 ignore_set_focus_msg_(false) {
174 stored_focused_view_storage_id_ = 34 stored_focused_view_storage_id_ =
175 ViewStorage::GetSharedInstance()->CreateStorageID(); 35 ViewStorage::GetSharedInstance()->CreateStorageID();
176 DCHECK(root_);
177 } 36 }
178 #endif
179 37
180 FocusManager::~FocusManager() { 38 FocusManager::~FocusManager() {
181 // If there are still registered FocusChange listeners, chances are they were 39 // If there are still registered FocusChange listeners, chances are they were
182 // leaked so warn about them. 40 // leaked so warn about them.
183 DCHECK(focus_change_listeners_.empty()); 41 DCHECK(focus_change_listeners_.empty());
184 } 42 }
185 43
186 #if defined(OS_WIN) 44 #if defined(OS_WIN)
187 // Message handlers. 45 // Message handlers.
188 bool FocusManager::OnNCDestroy(HWND window) {
189 // Window is being destroyed, undo the subclassing.
190 FocusManager::UninstallFocusSubclass(window);
191
192 if (window == root_) {
193 // We are the top window.
194
195 DCHECK(GetProp(window, kFocusManagerKey));
196
197 // Make sure this is called on the window that was set with the
198 // FocusManager.
199 RemoveProp(window, kFocusManagerKey);
200
201 delete this;
202 }
203 return true;
204 }
205
206 bool FocusManager::OnKeyDown(HWND window, UINT message, WPARAM wparam, 46 bool FocusManager::OnKeyDown(HWND window, UINT message, WPARAM wparam,
207 LPARAM lparam) { 47 LPARAM lparam) {
208 DCHECK((message == WM_KEYDOWN) || (message == WM_SYSKEYDOWN)); 48 DCHECK((message == WM_KEYDOWN) || (message == WM_SYSKEYDOWN));
49 HWND hwnd = widget_->GetNativeView();
209 50
210 if (!IsWindowVisible(root_)) { 51 if (!IsWindowVisible(hwnd)) {
211 // We got a message for a hidden window. Because WidgetWin::Close hides the 52 // We got a message for a hidden window. Because WidgetWin::Close hides the
212 // window, then destroys it, it it possible to get a message after we've 53 // window, then destroys it, it it possible to get a message after we've
213 // hidden the window. If we allow the message to be dispatched chances are 54 // hidden the window. If we allow the message to be dispatched chances are
214 // we'll crash in some weird place. By returning false we make sure the 55 // we'll crash in some weird place. By returning false we make sure the
215 // message isn't dispatched. 56 // message isn't dispatched.
216 return false; 57 return false;
217 } 58 }
218 59
219 // First give the registered keystroke handlers a chance a processing 60 // First give the registered keystroke handlers a chance a processing
220 // the message 61 // the message
(...skipping 17 matching lines...) Expand all
238 virtual_key_code, repeat_count, flags); 79 virtual_key_code, repeat_count, flags);
239 80
240 // If the focused view wants to process the key event as is, let it be. 81 // If the focused view wants to process the key event as is, let it be.
241 if (focused_view_ && focused_view_->SkipDefaultKeyEventProcessing(key_event)) 82 if (focused_view_ && focused_view_->SkipDefaultKeyEventProcessing(key_event))
242 return true; 83 return true;
243 84
244 // Intercept Tab related messages for focus traversal. 85 // Intercept Tab related messages for focus traversal.
245 // Note that we don't do focus traversal if the root window is not part of the 86 // Note that we don't do focus traversal if the root window is not part of the
246 // active window hierarchy as this would mean we have no focused view and 87 // active window hierarchy as this would mean we have no focused view and
247 // would focus the first focusable view. 88 // would focus the first focusable view.
89 HWND top_window = widget_->GetNativeView();
248 HWND active_window = ::GetActiveWindow(); 90 HWND active_window = ::GetActiveWindow();
249 if ((active_window == root_ || ::IsChild(active_window, root_)) && 91 if ((active_window == top_window || ::IsChild(active_window, top_window)) &&
250 IsTabTraversalKeyEvent(key_event)) { 92 IsTabTraversalKeyEvent(key_event)) {
251 AdvanceFocus(win_util::IsShiftPressed()); 93 AdvanceFocus(win_util::IsShiftPressed());
252 return false; 94 return false;
253 } 95 }
254 96
255 // Intercept arrow key messages to switch between grouped views. 97 // Intercept arrow key messages to switch between grouped views.
256 if (focused_view_ && focused_view_->GetGroup() != -1 && 98 if (focused_view_ && focused_view_->GetGroup() != -1 &&
257 (virtual_key_code == VK_UP || virtual_key_code == VK_DOWN || 99 (virtual_key_code == VK_UP || virtual_key_code == VK_DOWN ||
258 virtual_key_code == VK_LEFT || virtual_key_code == VK_RIGHT)) { 100 virtual_key_code == VK_LEFT || virtual_key_code == VK_RIGHT)) {
259 bool next = (virtual_key_code == VK_RIGHT || virtual_key_code == VK_DOWN); 101 bool next = (virtual_key_code == VK_RIGHT || virtual_key_code == VK_DOWN);
260 std::vector<View*> views; 102 std::vector<View*> views;
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
317 bool FocusManager::ContainsView(View* view) { 159 bool FocusManager::ContainsView(View* view) {
318 DCHECK(view); 160 DCHECK(view);
319 RootView* root_view = view->GetRootView(); 161 RootView* root_view = view->GetRootView();
320 if (!root_view) 162 if (!root_view)
321 return false; 163 return false;
322 164
323 Widget* widget = root_view->GetWidget(); 165 Widget* widget = root_view->GetWidget();
324 if (!widget) 166 if (!widget)
325 return false; 167 return false;
326 168
169 gfx::NativeView top_window = widget_->GetNativeView();
327 gfx::NativeView window = widget->GetNativeView(); 170 gfx::NativeView window = widget->GetNativeView();
328 while (window) { 171 while (window) {
329 if (window == root_) 172 if (window == top_window)
330 return true; 173 return true;
331 #if defined(OS_WIN) 174 #if defined(OS_WIN)
332 window = ::GetParent(window); 175 window = ::GetParent(window);
333 #else 176 #else
334 window = gtk_widget_get_parent(window); 177 window = gtk_widget_get_parent(window);
335 #endif 178 #endif
336 } 179 }
337 return false; 180 return false;
338 } 181 }
339 182
(...skipping 30 matching lines...) Expand all
370 focus_traversable = original_starting_view->GetRootView(); 213 focus_traversable = original_starting_view->GetRootView();
371 starting_view = original_starting_view; 214 starting_view = original_starting_view;
372 } 215 }
373 } else { 216 } else {
374 // When you are going back, starting view's FocusTraversable should not be 217 // When you are going back, starting view's FocusTraversable should not be
375 // used. 218 // used.
376 focus_traversable = original_starting_view->GetRootView(); 219 focus_traversable = original_starting_view->GetRootView();
377 starting_view = original_starting_view; 220 starting_view = original_starting_view;
378 } 221 }
379 } else { 222 } else {
380 focus_traversable = top_root_view_; 223 focus_traversable = widget_->GetRootView();
381 } 224 }
382 225
383 // Traverse the FocusTraversable tree down to find the focusable view. 226 // Traverse the FocusTraversable tree down to find the focusable view.
384 View* v = FindFocusableView(focus_traversable, starting_view, reverse); 227 View* v = FindFocusableView(focus_traversable, starting_view, reverse);
385 if (v) { 228 if (v) {
386 return v; 229 return v;
387 } else { 230 } else {
388 // Let's go up in the FocusTraversable tree. 231 // Let's go up in the FocusTraversable tree.
389 FocusTraversable* parent_focus_traversable = 232 FocusTraversable* parent_focus_traversable =
390 focus_traversable->GetFocusTraversableParent(); 233 focus_traversable->GetFocusTraversableParent();
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
450 if (view) { 293 if (view) {
451 view->SchedulePaint(); 294 view->SchedulePaint();
452 view->Focus(); 295 view->Focus();
453 view->DidGainFocus(); 296 view->DidGainFocus();
454 } 297 }
455 } 298 }
456 } 299 }
457 300
458 void FocusManager::ClearFocus() { 301 void FocusManager::ClearFocus() {
459 SetFocusedView(NULL); 302 SetFocusedView(NULL);
460 ClearHWNDFocus(); 303 ClearNativeFocus();
461 } 304 }
462 305
463 void FocusManager::ClearHWNDFocus() {
464 // Keep the top root window focused so we get keyboard events.
465 ignore_set_focus_msg_ = true;
466 #if defined(OS_WIN)
467 ::SetFocus(root_);
468 #else
469 NOTIMPLEMENTED();
470 #endif
471 ignore_set_focus_msg_ = false;
472 }
473
474 #if defined(OS_WIN)
475 void FocusManager::FocusHWND(HWND hwnd) {
476 ignore_set_focus_msg_ = true;
477 // Only reset focus if hwnd is not already focused.
478 if (hwnd && ::GetFocus() != hwnd)
479 ::SetFocus(hwnd);
480 ignore_set_focus_msg_ = false;
481 }
482 #endif
483
484 void FocusManager::StoreFocusedView() { 306 void FocusManager::StoreFocusedView() {
485 ViewStorage* view_storage = ViewStorage::GetSharedInstance(); 307 ViewStorage* view_storage = ViewStorage::GetSharedInstance();
486 if (!view_storage) { 308 if (!view_storage) {
487 // This should never happen but bug 981648 seems to indicate it could. 309 // This should never happen but bug 981648 seems to indicate it could.
488 NOTREACHED(); 310 NOTREACHED();
489 return; 311 return;
490 } 312 }
491 313
492 // TODO (jcampan): when a TabContents containing a popup is closed, the focus 314 // TODO (jcampan): when a TabContents containing a popup is closed, the focus
493 // is stored twice causing an assert. We should find a better alternative than 315 // is stored twice causing an assert. We should find a better alternative than
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
528 void FocusManager::ClearStoredFocusedView() { 350 void FocusManager::ClearStoredFocusedView() {
529 ViewStorage* view_storage = ViewStorage::GetSharedInstance(); 351 ViewStorage* view_storage = ViewStorage::GetSharedInstance();
530 if (!view_storage) { 352 if (!view_storage) {
531 // This should never happen but bug 981648 seems to indicate it could. 353 // This should never happen but bug 981648 seems to indicate it could.
532 NOTREACHED(); 354 NOTREACHED();
533 return; 355 return;
534 } 356 }
535 view_storage->RemoveView(stored_focused_view_storage_id_); 357 view_storage->RemoveView(stored_focused_view_storage_id_);
536 } 358 }
537 359
538 FocusManager* FocusManager::GetParentFocusManager() const {
539 #if defined(OS_WIN)
540 HWND parent = ::GetParent(root_);
541 #else
542 GtkWidget* parent = gtk_widget_get_parent(root_);
543 #endif
544 // If we are a top window, we don't have a parent FocusManager.
545 if (!parent)
546 return NULL;
547
548 return GetFocusManager(parent);
549 }
550
551 // Find the next (previous if reverse is true) focusable view for the specified 360 // Find the next (previous if reverse is true) focusable view for the specified
552 // FocusTraversable, starting at the specified view, traversing down the 361 // FocusTraversable, starting at the specified view, traversing down the
553 // FocusTraversable hierarchy. 362 // FocusTraversable hierarchy.
554 View* FocusManager::FindFocusableView(FocusTraversable* focus_traversable, 363 View* FocusManager::FindFocusableView(FocusTraversable* focus_traversable,
555 View* starting_view, 364 View* starting_view,
556 bool reverse) { 365 bool reverse) {
557 FocusTraversable* new_focus_traversable = NULL; 366 FocusTraversable* new_focus_traversable = NULL;
558 View* new_starting_view = NULL; 367 View* new_starting_view = NULL;
559 View* v = focus_traversable->FindNextFocusableView(starting_view, 368 View* v = focus_traversable->FindNextFocusableView(starting_view,
560 reverse, 369 reverse,
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
622 // We have to copy the target list here, because an AcceleratorPressed 431 // We have to copy the target list here, because an AcceleratorPressed
623 // event handler may modify the list. 432 // event handler may modify the list.
624 AcceleratorTargetList targets(map_iter->second); 433 AcceleratorTargetList targets(map_iter->second);
625 for (AcceleratorTargetList::iterator iter = targets.begin(); 434 for (AcceleratorTargetList::iterator iter = targets.begin();
626 iter != targets.end(); ++iter) { 435 iter != targets.end(); ++iter) {
627 if ((*iter)->AcceleratorPressed(accelerator)) 436 if ((*iter)->AcceleratorPressed(accelerator))
628 return true; 437 return true;
629 } 438 }
630 } 439 }
631 440
632 // When dealing with child windows that have their own FocusManager (such
633 // as ConstrainedWindow), we still want the parent FocusManager to process
634 // the accelerator if the child window did not process it.
635 FocusManager* parent_focus_manager = GetParentFocusManager();
636 if (parent_focus_manager)
637 return parent_focus_manager->ProcessAccelerator(accelerator);
638
639 return false; 441 return false;
640 } 442 }
641 443
642 AcceleratorTarget* FocusManager::GetCurrentTargetForAccelerator( 444 AcceleratorTarget* FocusManager::GetCurrentTargetForAccelerator(
643 const views::Accelerator& accelerator) const { 445 const views::Accelerator& accelerator) const {
644 AcceleratorMap::const_iterator map_iter = accelerators_.find(accelerator); 446 AcceleratorMap::const_iterator map_iter = accelerators_.find(accelerator);
645 if (map_iter == accelerators_.end() || map_iter->second.empty()) 447 if (map_iter == accelerators_.end() || map_iter->second.empty())
646 return NULL; 448 return NULL;
647 return map_iter->second.front(); 449 return map_iter->second.front();
648 } 450 }
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
692 std::find(focus_change_listeners_.begin(), focus_change_listeners_.end(), 494 std::find(focus_change_listeners_.begin(), focus_change_listeners_.end(),
693 listener); 495 listener);
694 if (place == focus_change_listeners_.end()) { 496 if (place == focus_change_listeners_.end()) {
695 NOTREACHED() << "Removing a listener that isn't registered."; 497 NOTREACHED() << "Removing a listener that isn't registered.";
696 return; 498 return;
697 } 499 }
698 focus_change_listeners_.erase(place); 500 focus_change_listeners_.erase(place);
699 } 501 }
700 502
701 } // namespace views 503 } // namespace views
OLDNEW
« no previous file with comments | « views/focus/focus_manager.h ('k') | views/focus/focus_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698