| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |