diff options
author | jcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-20 04:22:44 +0000 |
---|---|---|
committer | jcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-20 04:22:44 +0000 |
commit | 3c3ba740c63a178807cc0c1a563080e0adbfe143 (patch) | |
tree | 78bcd84e7870d8009165df0e7a9fca87f4e91903 /views/focus | |
parent | 76724d00d3498f952d945d775a3f33f751624121 (diff) | |
download | chromium_src-3c3ba740c63a178807cc0c1a563080e0adbfe143.zip chromium_src-3c3ba740c63a178807cc0c1a563080e0adbfe143.tar.gz chromium_src-3c3ba740c63a178807cc0c1a563080e0adbfe143.tar.bz2 |
Relanding focus manager refactoring with build fix, see:http://codereview.chromium.org/125148BUG=NoneTEST=NoneTBR=ben
Review URL: http://codereview.chromium.org/141013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18889 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views/focus')
-rw-r--r-- | views/focus/external_focus_tracker.cc | 3 | ||||
-rw-r--r-- | views/focus/focus_manager.cc | 224 | ||||
-rw-r--r-- | views/focus/focus_manager.h | 85 | ||||
-rw-r--r-- | views/focus/focus_manager_gtk.cc | 25 | ||||
-rw-r--r-- | views/focus/focus_manager_unittest.cc | 5 | ||||
-rw-r--r-- | views/focus/focus_manager_win.cc | 33 |
6 files changed, 95 insertions, 280 deletions
diff --git a/views/focus/external_focus_tracker.cc b/views/focus/external_focus_tracker.cc index 8f8bfdf..b08d287 100644 --- a/views/focus/external_focus_tracker.cc +++ b/views/focus/external_focus_tracker.cc @@ -4,6 +4,7 @@ #include "views/focus/external_focus_tracker.h" +#include "base/logging.h" #include "views/view.h" #include "views/focus/view_storage.h" @@ -13,6 +14,8 @@ ExternalFocusTracker::ExternalFocusTracker(View* parent_view, FocusManager* focus_manager) : focus_manager_(focus_manager), parent_view_(parent_view) { + DCHECK(focus_manager); + DCHECK(parent_view); view_storage_ = ViewStorage::GetSharedInstance(); last_focused_view_storage_id_ = view_storage_->CreateStorageID(); // Store the view which is focused when we're created. diff --git a/views/focus/focus_manager.cc b/views/focus/focus_manager.cc index f4b67ff..dc26649 100644 --- a/views/focus/focus_manager.cc +++ b/views/focus/focus_manager.cc @@ -12,7 +12,6 @@ #include <gtk/gtk.h> #endif -#include "base/histogram.h" #include "base/logging.h" #include "views/accelerator.h" #include "views/focus/view_storage.h" @@ -24,158 +23,17 @@ #include "base/win_util.h" #endif -// The following keys are used in SetProp/GetProp to associate additional -// information needed for focus tracking with a window. - -// Maps to the FocusManager instance for a top level window. See -// CreateFocusManager/DestoryFocusManager for usage. -static const wchar_t* const kFocusManagerKey = L"__VIEW_CONTAINER__"; - -// Maps to the View associated with a window. -// We register views with window so we can: -// - keep in sync the native focus with the view focus (when the native -// component gets the focus, we get the WM_SETFOCUS event and we can focus the -// associated view). -// - prevent tab key events from being sent to views. -static const wchar_t* const kViewKey = L"__CHROME_VIEW__"; - -// A property set to 1 to indicate whether the focus manager has subclassed that -// window. We are doing this to ensure we are not subclassing several times. -// Subclassing twice is not a problem if no one is subclassing the HWND between -// the 2 subclassings (the 2nd subclassing is ignored since the WinProc is the -// same as the current one). However if some other app goes and subclasses the -// HWND between the 2 subclassings, we will end up subclassing twice. -// This flag lets us test that whether we have or not subclassed yet. -static const wchar_t* const kFocusSubclassInstalled = - L"__FOCUS_SUBCLASS_INSTALLED__"; - namespace views { -#if defined(OS_WIN) -// Callback installed via InstallFocusSubclass. -static LRESULT CALLBACK FocusWindowCallback(HWND window, UINT message, - WPARAM wParam, LPARAM lParam) { - if (!::IsWindow(window)) { - // QEMU has reported crashes when calling GetProp (this seems to happen for - // some weird messages, not sure what they are). - // Here we are just trying to avoid the crasher. - NOTREACHED(); - return 0; - } - - WNDPROC original_handler = win_util::GetSuperclassWNDPROC(window); - DCHECK(original_handler); - FocusManager* focus_manager = FocusManager::GetFocusManager(window); - // There are cases when we have no FocusManager for the window. This happens - // because we subclass certain windows (such as the TabContents window) - // but that window may not have an associated FocusManager. - if (focus_manager) { - switch (message) { - case WM_NCDESTROY: - if (!focus_manager->OnNCDestroy(window)) - return 0; - break; - default: - break; - } - } - return CallWindowProc(original_handler, window, message, wParam, lParam); -} - -#endif - // FocusManager ----------------------------------------------------- -#if defined(OS_WIN) -// static -FocusManager* FocusManager::CreateFocusManager(HWND window, - RootView* root_view) { - DCHECK(window); - DCHECK(root_view); - InstallFocusSubclass(window, NULL); - FocusManager* focus_manager = new FocusManager(window, root_view); - SetProp(window, kFocusManagerKey, focus_manager); - - return focus_manager; -} - -// static -void FocusManager::InstallFocusSubclass(HWND window, View* view) { - DCHECK(window); - - bool already_subclassed = - reinterpret_cast<bool>(GetProp(window, - kFocusSubclassInstalled)); - if (already_subclassed && - !win_util::IsSubclassed(window, &FocusWindowCallback)) { - NOTREACHED() << "window sub-classed by someone other than the FocusManager"; - // Track in UMA so we know if this case happens. - UMA_HISTOGRAM_COUNTS("FocusManager.MultipleSubclass", 1); - } else { - win_util::Subclass(window, &FocusWindowCallback); - SetProp(window, kFocusSubclassInstalled, reinterpret_cast<HANDLE>(true)); - } - if (view) - SetProp(window, kViewKey, view); -} - -void FocusManager::UninstallFocusSubclass(HWND window) { - DCHECK(window); - if (win_util::Unsubclass(window, &FocusWindowCallback)) { - RemoveProp(window, kViewKey); - RemoveProp(window, kFocusSubclassInstalled); - } -} - -#endif - -// static -FocusManager* FocusManager::GetFocusManager(gfx::NativeView window) { -#if defined(OS_WIN) - DCHECK(window); - - // In case parent windows belong to a different process, yet - // have the kFocusManagerKey property set, we have to be careful - // to also check the process id of the window we're checking. - DWORD window_pid = 0, current_pid = GetCurrentProcessId(); - FocusManager* focus_manager; - for (focus_manager = NULL; focus_manager == NULL && IsWindow(window); - window = GetParent(window)) { - GetWindowThreadProcessId(window, &window_pid); - if (current_pid != window_pid) - break; - focus_manager = reinterpret_cast<FocusManager*>( - GetProp(window, kFocusManagerKey)); - } - return focus_manager; -#else - NOTIMPLEMENTED(); - return NULL; -#endif -} - -#if defined(OS_WIN) -// static -View* FocusManager::GetViewForWindow(gfx::NativeView window, bool look_in_parents) { - DCHECK(window); - do { - View* v = reinterpret_cast<View*>(GetProp(window, kViewKey)); - if (v) - return v; - } while (look_in_parents && (window = ::GetParent(window))); - return NULL; -} - -FocusManager::FocusManager(HWND root, RootView* root_view) - : root_(root), - top_root_view_(root_view), - focused_view_(NULL), - ignore_set_focus_msg_(false) { +FocusManager::FocusManager(Widget* widget) + : widget_(widget), + focused_view_(NULL) { + DCHECK(widget_); stored_focused_view_storage_id_ = ViewStorage::GetSharedInstance()->CreateStorageID(); - DCHECK(root_); } -#endif FocusManager::~FocusManager() { // If there are still registered FocusChange listeners, chances are they were @@ -185,29 +43,12 @@ FocusManager::~FocusManager() { #if defined(OS_WIN) // Message handlers. -bool FocusManager::OnNCDestroy(HWND window) { - // Window is being destroyed, undo the subclassing. - FocusManager::UninstallFocusSubclass(window); - - if (window == root_) { - // We are the top window. - - DCHECK(GetProp(window, kFocusManagerKey)); - - // Make sure this is called on the window that was set with the - // FocusManager. - RemoveProp(window, kFocusManagerKey); - - delete this; - } - return true; -} - bool FocusManager::OnKeyDown(HWND window, UINT message, WPARAM wparam, LPARAM lparam) { DCHECK((message == WM_KEYDOWN) || (message == WM_SYSKEYDOWN)); + HWND hwnd = widget_->GetNativeView(); - if (!IsWindowVisible(root_)) { + if (!IsWindowVisible(hwnd)) { // We got a message for a hidden window. Because WidgetWin::Close hides the // window, then destroys it, it it possible to get a message after we've // hidden the window. If we allow the message to be dispatched chances are @@ -245,9 +86,10 @@ bool FocusManager::OnKeyDown(HWND window, UINT message, WPARAM wparam, // Note that we don't do focus traversal if the root window is not part of the // active window hierarchy as this would mean we have no focused view and // would focus the first focusable view. + HWND top_window = widget_->GetNativeView(); HWND active_window = ::GetActiveWindow(); - if ((active_window == root_ || ::IsChild(active_window, root_)) && - IsTabTraversalKeyEvent(key_event)) { + if ((active_window == top_window || ::IsChild(active_window, top_window)) && + IsTabTraversalKeyEvent(key_event)) { AdvanceFocus(win_util::IsShiftPressed()); return false; } @@ -324,9 +166,10 @@ bool FocusManager::ContainsView(View* view) { if (!widget) return false; + gfx::NativeView top_window = widget_->GetNativeView(); gfx::NativeView window = widget->GetNativeView(); while (window) { - if (window == root_) + if (window == top_window) return true; #if defined(OS_WIN) window = ::GetParent(window); @@ -377,7 +220,7 @@ View* FocusManager::GetNextFocusableView(View* original_starting_view, starting_view = original_starting_view; } } else { - focus_traversable = top_root_view_; + focus_traversable = widget_->GetRootView(); } // Traverse the FocusTraversable tree down to find the focusable view. @@ -457,30 +300,9 @@ void FocusManager::SetFocusedView(View* view) { void FocusManager::ClearFocus() { SetFocusedView(NULL); - ClearHWNDFocus(); + ClearNativeFocus(); } -void FocusManager::ClearHWNDFocus() { - // Keep the top root window focused so we get keyboard events. - ignore_set_focus_msg_ = true; -#if defined(OS_WIN) - ::SetFocus(root_); -#else - NOTIMPLEMENTED(); -#endif - ignore_set_focus_msg_ = false; -} - -#if defined(OS_WIN) -void FocusManager::FocusHWND(HWND hwnd) { - ignore_set_focus_msg_ = true; - // Only reset focus if hwnd is not already focused. - if (hwnd && ::GetFocus() != hwnd) - ::SetFocus(hwnd); - ignore_set_focus_msg_ = false; -} -#endif - void FocusManager::StoreFocusedView() { ViewStorage* view_storage = ViewStorage::GetSharedInstance(); if (!view_storage) { @@ -535,19 +357,6 @@ void FocusManager::ClearStoredFocusedView() { view_storage->RemoveView(stored_focused_view_storage_id_); } -FocusManager* FocusManager::GetParentFocusManager() const { -#if defined(OS_WIN) - HWND parent = ::GetParent(root_); -#else - GtkWidget* parent = gtk_widget_get_parent(root_); -#endif - // If we are a top window, we don't have a parent FocusManager. - if (!parent) - return NULL; - - return GetFocusManager(parent); -} - // Find the next (previous if reverse is true) focusable view for the specified // FocusTraversable, starting at the specified view, traversing down the // FocusTraversable hierarchy. @@ -629,13 +438,6 @@ bool FocusManager::ProcessAccelerator(const Accelerator& accelerator) { } } - // When dealing with child windows that have their own FocusManager (such - // as ConstrainedWindow), we still want the parent FocusManager to process - // the accelerator if the child window did not process it. - FocusManager* parent_focus_manager = GetParentFocusManager(); - if (parent_focus_manager) - return parent_focus_manager->ProcessAccelerator(accelerator); - return false; } diff --git a/views/focus/focus_manager.h b/views/focus/focus_manager.h index fb48188..8b4c8c9a 100644 --- a/views/focus/focus_manager.h +++ b/views/focus/focus_manager.h @@ -20,7 +20,7 @@ // focused views and handle keyboard accelerators. // // There are 2 types of focus: -// - the native focus, which is the focus that an HWND has. +// - the native focus, which is the focus that an gfx::NativeView has. // - the view focus, which is the focus that a views::View has. // // Each native view must register with their Focus Manager so the focus manager @@ -32,13 +32,9 @@ // This is already done for you if you subclass the NativeControl class or if // you use the NativeViewHost class. // -// When creating a top window, if it derives from WidgetWin, the -// |has_own_focus_manager| of the Init method lets you specify whether that -// window should have its own focus manager (so focus traversal stays confined -// in that window). If you are not deriving from WidgetWin or one of its -// derived classes (Window, FramelessWindow, ConstrainedWindow), you must -// create a FocusManager when the window is created (it is automatically deleted -// when the window is destroyed). +// When creating a top window (derived from views::Widget) that is not a child +// window, it creates and owns a FocusManager to manage the focus for itself and +// all its child windows. // // The FocusTraversable interface exposes the methods a class should implement // in order to be able to be focus traversed when tab key is pressed. @@ -77,8 +73,9 @@ namespace views { -class View; class RootView; +class View; +class Widget; // The FocusTraversable interface is used by components that want to process // focus traversal events (due to Tab/Shift-Tab key events). @@ -153,22 +150,10 @@ class FocusChangeListener { class FocusManager { public: -#if defined(OS_WIN) - // Creates a FocusManager for the specified window. Top level windows - // must invoked this when created. - // The RootView specified should be the top RootView of the window. - // This also invokes InstallFocusSubclass. - static FocusManager* CreateFocusManager(HWND window, RootView* root_view); -#endif - - static FocusManager* GetFocusManager(gfx::NativeView window); + explicit FocusManager(Widget* widget); + ~FocusManager(); #if defined(OS_WIN) - // Message handlers (for messages received from registered windows). - // Should return true if the message should be forwarded to the window - // original proc function, false otherwise. - bool OnSetFocus(HWND window); - bool OnNCDestroy(HWND window); // OnKeyDown covers WM_KEYDOWN and WM_SYSKEYDOWN. bool OnKeyDown(HWND window, UINT message, @@ -195,27 +180,10 @@ class FocusManager { // the native focus (so we still get keyboard events). void ClearFocus(); - // Clears the HWND that has the focus by focusing the HWND from the top - // RootView (so we still get keyboard events). - // Note that this does not change the currently focused view. - void ClearHWNDFocus(); - -#if defined(OS_WIN) - // Focus the specified |hwnd| without changing the focused view. - void FocusHWND(HWND hwnd); -#endif - // Validates the focused view, clearing it if the window it belongs too is not // attached to the window hierarchy anymore. void ValidateFocusedView(); -#if defined(OS_WIN) - // Returns the view associated with the specified window if any. - // If |look_in_parents| is true, it goes up the window parents until it find - // a view. - static View* GetViewForWindow(HWND window, bool look_in_parents); -#endif - // Stores and restores the focused view. Used when the window becomes // active/inactive. void StoreFocusedView(); @@ -224,11 +192,6 @@ class FocusManager { // Clears the stored focused view. void ClearStoredFocusedView(); - // Returns the FocusManager of the parent window of the window that is the - // root of this FocusManager. This is useful with ConstrainedWindows that have - // their own FocusManager and need to return focus to the browser when closed. - FocusManager* GetParentFocusManager() const; - // Register a keyboard accelerator for the specified target. If multiple // targets are registered for an accelerator, a target registered later has // higher priority. @@ -280,22 +243,17 @@ class FocusManager { // pressed). static bool IsTabTraversalKeyEvent(const KeyEvent& key_event); - private: -#if defined(OS_WIN) - explicit FocusManager(HWND root, RootView* root_view); + // Sets the focus to the specified native view. + virtual void FocusNativeView(gfx::NativeView native_view); - // Subclasses the specified window. The subclassed window procedure listens - // for WM_SETFOCUS notification and keeps the FocusManager's focus owner - // property in sync. - // It's not necessary to explicitly invoke Uninstall, it's automatically done - // when the window is destroyed and Uninstall wasn't invoked. - static void InstallFocusSubclass(HWND window, View* view); + // Clears the native view having the focus. + virtual void ClearNativeFocus(); - // Uninstalls the window subclass installed by InstallFocusSubclass. - static void UninstallFocusSubclass(HWND window); -#endif - ~FocusManager(); + // Retrieves the FocusManager associated with the passed native view. + static FocusManager* GetFocusManagerForNativeView( + gfx::NativeView native_view); + private: // Returns the next focusable view. View* GetNextFocusableView(View* starting_view, bool reverse, bool dont_loop); @@ -307,8 +265,8 @@ class FocusManager { View* starting_view, bool reverse); - // The RootView of the window associated with this FocusManager. - RootView* top_root_view_; + // The top-level Widget this FocusManager is associated with. + Widget* widget_; // The view that currently is focused. View* focused_view_; @@ -317,13 +275,6 @@ class FocusManager { // had focus. int stored_focused_view_storage_id_; - // The window associated with this focus manager. - gfx::NativeView root_; - - // Used to allow setting the focus on an HWND without changing the currently - // focused view. - bool ignore_set_focus_msg_; - // The accelerators and associated targets. typedef std::list<AcceleratorTarget*> AcceleratorTargetList; typedef std::map<Accelerator, AcceleratorTargetList> AcceleratorMap; diff --git a/views/focus/focus_manager_gtk.cc b/views/focus/focus_manager_gtk.cc new file mode 100644 index 0000000..f6454d2 --- /dev/null +++ b/views/focus/focus_manager_gtk.cc @@ -0,0 +1,25 @@ +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "views/focus/focus_manager.h" + +#include "base/logging.h" + +namespace views { + +void FocusManager::ClearNativeFocus() { + NOTIMPLEMENTED(); +} + +void FocusManager::FocusNativeView(gfx::NativeView native_view) { + NOTIMPLEMENTED(); +} + +// static +FocusManager* FocusManager::GetFocusManagerForNativeView( + gfx::NativeView native_view) { + NOTIMPLEMENTED(); +} + +} // namespace views diff --git a/views/focus/focus_manager_unittest.cc b/views/focus/focus_manager_unittest.cc index cc56271..7fff0bd 100644 --- a/views/focus/focus_manager_unittest.cc +++ b/views/focus/focus_manager_unittest.cc @@ -119,7 +119,7 @@ class BorderView : public NativeControl { parent_container, NULL, NULL, NULL); // Create the view container which is a child of the TabControl. widget_ = new WidgetWin(); - widget_->Init(tab_control, gfx::Rect(), false); + widget_->Init(tab_control, gfx::Rect()); widget_->SetContentsView(child_); widget_->SetFocusTraversableParentView(this); ResizeContents(tab_control); @@ -210,7 +210,8 @@ class FocusManagerTest : public testing::Test, public WindowDelegate { } FocusManager* GetFocusManager() { - return FocusManager::GetFocusManager(window_->GetNativeWindow()); + return FocusManager::GetFocusManagerForNativeView( + window_->GetNativeWindow()); } // WindowDelegate Implementation. diff --git a/views/focus/focus_manager_win.cc b/views/focus/focus_manager_win.cc new file mode 100644 index 0000000..a3d01f9 --- /dev/null +++ b/views/focus/focus_manager_win.cc @@ -0,0 +1,33 @@ +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "views/focus/focus_manager.h" + +#include "views/view.h" +#include "views/widget/widget_win.h" + +namespace views { + +void FocusManager::ClearNativeFocus() { + // Keep the top root window focused so we get keyboard events. + ::SetFocus(widget_->GetNativeView()); +} + +void FocusManager::FocusNativeView(gfx::NativeView native_view) { + // Only reset focus if hwnd is not already focused. + if (native_view && ::GetFocus() != native_view) + ::SetFocus(native_view); +} + +// static +FocusManager* FocusManager::GetFocusManagerForNativeView( + gfx::NativeView native_view) { + HWND root = ::GetAncestor(native_view, GA_ROOT); + if (!root) + return NULL; + WidgetWin* widget = WidgetWin::GetWidget(root); + return widget ? widget->GetFocusManager() : NULL; +} + +} // namespace views |