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

Side by Side Diff: chrome/browser/views/shell_dialogs_win.cc

Issue 195065: Fix focus bug with shell dialogs (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 3 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 | « no previous file | no next file » | 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 "chrome/browser/shell_dialogs.h" 5 #include "chrome/browser/shell_dialogs.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 #include <commdlg.h> 8 #include <commdlg.h>
9 #include <shlobj.h> 9 #include <shlobj.h>
10 10
11 #include <algorithm> 11 #include <algorithm>
12 #include <set> 12 #include <set>
13 13
14 #include "app/gfx/font.h" 14 #include "app/gfx/font.h"
15 #include "app/l10n_util.h" 15 #include "app/l10n_util.h"
16 #include "app/win_util.h" 16 #include "app/win_util.h"
17 #include "base/file_util.h" 17 #include "base/file_util.h"
18 #include "base/registry.h" 18 #include "base/registry.h"
19 #include "base/scoped_comptr_win.h" 19 #include "base/scoped_comptr_win.h"
20 #include "base/string_util.h" 20 #include "base/string_util.h"
21 #include "base/thread.h" 21 #include "base/thread.h"
22 #include "chrome/browser/browser_process.h" 22 #include "chrome/browser/browser_process.h"
23 #include "grit/generated_resources.h" 23 #include "grit/generated_resources.h"
24 #include "views/focus/focus_manager.h"
25 #include "views/focus/view_storage.h"
24 26
25 // Helpers to show certain types of Windows shell dialogs in a way that doesn't 27 // Helpers to show certain types of Windows shell dialogs in a way that doesn't
26 // block the UI of the entire app. 28 // block the UI of the entire app.
27 29
28 class ShellDialogThread : public base::Thread { 30 class ShellDialogThread : public base::Thread {
29 public: 31 public:
30 ShellDialogThread() : base::Thread("Chrome_ShellDialogThread") { } 32 ShellDialogThread() : base::Thread("Chrome_ShellDialogThread") { }
31 33
32 protected: 34 protected:
33 void Init() { 35 void Init() {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 // boxes active, this list will consist of the two browser windows' HWNDs. 111 // boxes active, this list will consist of the two browser windows' HWNDs.
110 // The derived class must call EndRun once the dialog is done showing to 112 // The derived class must call EndRun once the dialog is done showing to
111 // remove the owning HWND from this list. 113 // remove the owning HWND from this list.
112 // This object is static since it is maintained for all instances of this 114 // This object is static since it is maintained for all instances of this
113 // object - i.e. you can't have a font picker and a file picker open for the 115 // object - i.e. you can't have a font picker and a file picker open for the
114 // same owner, even though they might be represented by different instances 116 // same owner, even though they might be represented by different instances
115 // of this object. 117 // of this object.
116 // This set only contains non-null HWNDs. NULL hwnds are not added to this 118 // This set only contains non-null HWNDs. NULL hwnds are not added to this
117 // list. 119 // list.
118 typedef std::set<HWND> Owners; 120 typedef std::set<HWND> Owners;
121
122 // Storage id used to store the last focused view so we can restore focus
123 // appropriately.
124 int view_storage_id_;
125
119 static Owners owners_; 126 static Owners owners_;
120 static int instance_count_; 127 static int instance_count_;
121 128
122 DISALLOW_COPY_AND_ASSIGN(BaseShellDialogImpl); 129 DISALLOW_COPY_AND_ASSIGN(BaseShellDialogImpl);
123 }; 130 };
124 131
125 // static 132 // static
126 BaseShellDialogImpl::Owners BaseShellDialogImpl::owners_; 133 BaseShellDialogImpl::Owners BaseShellDialogImpl::owners_;
127 int BaseShellDialogImpl::instance_count_ = 0; 134 int BaseShellDialogImpl::instance_count_ = 0;
128 135
129 BaseShellDialogImpl::BaseShellDialogImpl() 136 BaseShellDialogImpl::BaseShellDialogImpl()
130 : ui_loop_(MessageLoop::current()) { 137 : ui_loop_(MessageLoop::current()),
138 view_storage_id_(views::ViewStorage::GetSharedInstance()->
139 CreateStorageID()) {
131 ++instance_count_; 140 ++instance_count_;
132 } 141 }
133 142
134 BaseShellDialogImpl::~BaseShellDialogImpl() { 143 BaseShellDialogImpl::~BaseShellDialogImpl() {
135 // All runs should be complete by the time this is called! 144 // All runs should be complete by the time this is called!
136 if (--instance_count_ == 0) 145 if (--instance_count_ == 0)
137 DCHECK(owners_.empty()); 146 DCHECK(owners_.empty());
138 } 147 }
139 148
140 BaseShellDialogImpl::RunState BaseShellDialogImpl::BeginRun(HWND owner) { 149 BaseShellDialogImpl::RunState BaseShellDialogImpl::BeginRun(HWND owner) {
141 // Cannot run a modal shell dialog if one is already running for this owner. 150 // Cannot run a modal shell dialog if one is already running for this owner.
142 DCHECK(!IsRunningDialogForOwner(owner)); 151 DCHECK(!IsRunningDialogForOwner(owner));
143 // The owner must be a top level window, otherwise we could end up with two 152 // The owner must be a top level window, otherwise we could end up with two
144 // entries in our map for the same top level window. 153 // entries in our map for the same top level window.
145 DCHECK(!owner || owner == GetAncestor(owner, GA_ROOT)); 154 DCHECK(!owner || owner == GetAncestor(owner, GA_ROOT));
146 RunState run_state; 155 RunState run_state;
147 run_state.dialog_thread = CreateDialogThread(); 156 run_state.dialog_thread = CreateDialogThread();
148 run_state.owner = owner; 157 run_state.owner = owner;
149 if (owner) { 158 if (owner) {
150 owners_.insert(owner); 159 owners_.insert(owner);
160 // Disabling the owner causes the browser to be disabled when the dialog is
161 // closed and the browser gets the activation. This messes up the normal
162 // focus restoration process. To work-around this, we'll restore the focus
163 // ourselves after we have reenabled the owner.
164 views::FocusManager* focus_manager =
165 views::FocusManager::GetFocusManagerForNativeView(owner);
166 if (focus_manager) {
167 views::View* focused_view = focus_manager->GetFocusedView();
168 if (focused_view)
169 views::ViewStorage::GetSharedInstance()->StoreView(view_storage_id_,
170 focused_view);
171 } else {
172 NOTREACHED();
173 }
151 DisableOwner(owner); 174 DisableOwner(owner);
152 } 175 }
153 return run_state; 176 return run_state;
154 } 177 }
155 178
156 void BaseShellDialogImpl::EndRun(RunState run_state) { 179 void BaseShellDialogImpl::EndRun(RunState run_state) {
157 if (run_state.owner) { 180 if (run_state.owner) {
158 DCHECK(IsRunningDialogForOwner(run_state.owner)); 181 DCHECK(IsRunningDialogForOwner(run_state.owner));
159 EnableOwner(run_state.owner); 182 EnableOwner(run_state.owner);
160 DCHECK(owners_.find(run_state.owner) != owners_.end()); 183 DCHECK(owners_.find(run_state.owner) != owners_.end());
161 owners_.erase(run_state.owner); 184 owners_.erase(run_state.owner);
185 // Now that the owner is enabled, restore the focus if applicable.
186 views::View* view_to_focus =
187 views::ViewStorage::GetSharedInstance()->RetrieveView(view_storage_id_);
188 if (view_to_focus) {
189 views::ViewStorage::GetSharedInstance()->RemoveView(view_storage_id_);
190 views::FocusManager* focus_manager =
191 views::FocusManager::GetFocusManagerForNativeView(run_state.owner);
192 if (focus_manager) {
193 // We need to clear focus as when the focus is restored when the dialog
194 // is closed, only setting the native focus fails. Meaning the focused
195 // manager still believes the right view has focus, and would ignore
196 // requesting focus to what it thinks is already focused.
197 focus_manager->ClearFocus();
198 view_to_focus->RequestFocus();
199 } else {
200 NOTREACHED();
201 }
202 }
162 } 203 }
163 DCHECK(run_state.dialog_thread); 204 DCHECK(run_state.dialog_thread);
164 delete run_state.dialog_thread; 205 delete run_state.dialog_thread;
165 } 206 }
166 207
167 bool BaseShellDialogImpl::IsRunningDialogForOwner(HWND owner) const { 208 bool BaseShellDialogImpl::IsRunningDialogForOwner(HWND owner) const {
168 return (owner && owners_.find(owner) != owners_.end()); 209 return (owner && owners_.find(owner) != owners_.end());
169 } 210 }
170 211
171 void BaseShellDialogImpl::DisableOwner(HWND owner) { 212 void BaseShellDialogImpl::DisableOwner(HWND owner) {
(...skipping 569 matching lines...) Expand 10 before | Expand all | Expand 10 after
741 void SelectFontDialogImpl::FontNotSelected(void* params, RunState run_state) { 782 void SelectFontDialogImpl::FontNotSelected(void* params, RunState run_state) {
742 if (listener_) 783 if (listener_)
743 listener_->FontSelectionCanceled(params); 784 listener_->FontSelectionCanceled(params);
744 EndRun(run_state); 785 EndRun(run_state);
745 } 786 }
746 787
747 // static 788 // static
748 SelectFontDialog* SelectFontDialog::Create(Listener* listener) { 789 SelectFontDialog* SelectFontDialog::Create(Listener* listener) {
749 return new SelectFontDialogImpl(listener); 790 return new SelectFontDialogImpl(listener);
750 } 791 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698