From 3c3ba740c63a178807cc0c1a563080e0adbfe143 Mon Sep 17 00:00:00 2001 From: "jcampan@chromium.org" Date: Sat, 20 Jun 2009 04:22:44 +0000 Subject: 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 --- views/focus/focus_manager.cc | 224 +++---------------------------------------- 1 file changed, 13 insertions(+), 211 deletions(-) (limited to 'views/focus/focus_manager.cc') 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 #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(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(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( - 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(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; } -- cgit v1.1