diff options
author | jcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-11 22:15:32 +0000 |
---|---|---|
committer | jcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-11 22:15:32 +0000 |
commit | 26012f91aa8cb47d845d68af6afdcec483e92754 (patch) | |
tree | a54f903d79ed3ddfb368eadcd6fc21a55bec4ca0 | |
parent | e32642f68ec20a267002648f335b0ca7c94dd4c3 (diff) | |
download | chromium_src-26012f91aa8cb47d845d68af6afdcec483e92754.zip chromium_src-26012f91aa8cb47d845d68af6afdcec483e92754.tar.gz chromium_src-26012f91aa8cb47d845d68af6afdcec483e92754.tar.bz2 |
The shell dialog code explicitly disables the browser HWND before calling the Windows API to select a file.
When the dialog is closed, the browser HWND gets a WM_ACTIVATE but is still disabled, which messes up with the focus restoration.
This patch ensures we restore the focus explicitly when the browser HWND is reenabled to work-around that issue.
BUG=3380
TEST=Set the focus on a page with scroll-bars, right-click to do a 'save as'. Close the dialog. The arrow keys should let you scroll the page. Accelerators such as Ctrl-T should still work. Test 'open a file', 'print' and the font selection dialog (in the options). When closing the dialog the focus should return to the view that last had focus.
Review URL: http://codereview.chromium.org/195065
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@26029 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/views/shell_dialogs_win.cc | 43 |
1 files changed, 42 insertions, 1 deletions
diff --git a/chrome/browser/views/shell_dialogs_win.cc b/chrome/browser/views/shell_dialogs_win.cc index 5c5b1f9..fa2b6f0 100644 --- a/chrome/browser/views/shell_dialogs_win.cc +++ b/chrome/browser/views/shell_dialogs_win.cc @@ -21,6 +21,8 @@ #include "base/thread.h" #include "chrome/browser/browser_process.h" #include "grit/generated_resources.h" +#include "views/focus/focus_manager.h" +#include "views/focus/view_storage.h" // Helpers to show certain types of Windows shell dialogs in a way that doesn't // block the UI of the entire app. @@ -116,6 +118,11 @@ class BaseShellDialogImpl { // This set only contains non-null HWNDs. NULL hwnds are not added to this // list. typedef std::set<HWND> Owners; + + // Storage id used to store the last focused view so we can restore focus + // appropriately. + int view_storage_id_; + static Owners owners_; static int instance_count_; @@ -127,7 +134,9 @@ BaseShellDialogImpl::Owners BaseShellDialogImpl::owners_; int BaseShellDialogImpl::instance_count_ = 0; BaseShellDialogImpl::BaseShellDialogImpl() - : ui_loop_(MessageLoop::current()) { + : ui_loop_(MessageLoop::current()), + view_storage_id_(views::ViewStorage::GetSharedInstance()-> + CreateStorageID()) { ++instance_count_; } @@ -148,6 +157,20 @@ BaseShellDialogImpl::RunState BaseShellDialogImpl::BeginRun(HWND owner) { run_state.owner = owner; if (owner) { owners_.insert(owner); + // Disabling the owner causes the browser to be disabled when the dialog is + // closed and the browser gets the activation. This messes up the normal + // focus restoration process. To work-around this, we'll restore the focus + // ourselves after we have reenabled the owner. + views::FocusManager* focus_manager = + views::FocusManager::GetFocusManagerForNativeView(owner); + if (focus_manager) { + views::View* focused_view = focus_manager->GetFocusedView(); + if (focused_view) + views::ViewStorage::GetSharedInstance()->StoreView(view_storage_id_, + focused_view); + } else { + NOTREACHED(); + } DisableOwner(owner); } return run_state; @@ -159,6 +182,24 @@ void BaseShellDialogImpl::EndRun(RunState run_state) { EnableOwner(run_state.owner); DCHECK(owners_.find(run_state.owner) != owners_.end()); owners_.erase(run_state.owner); + // Now that the owner is enabled, restore the focus if applicable. + views::View* view_to_focus = + views::ViewStorage::GetSharedInstance()->RetrieveView(view_storage_id_); + if (view_to_focus) { + views::ViewStorage::GetSharedInstance()->RemoveView(view_storage_id_); + views::FocusManager* focus_manager = + views::FocusManager::GetFocusManagerForNativeView(run_state.owner); + if (focus_manager) { + // We need to clear focus as when the focus is restored when the dialog + // is closed, only setting the native focus fails. Meaning the focused + // manager still believes the right view has focus, and would ignore + // requesting focus to what it thinks is already focused. + focus_manager->ClearFocus(); + view_to_focus->RequestFocus(); + } else { + NOTREACHED(); + } + } } DCHECK(run_state.dialog_thread); delete run_state.dialog_thread; |