| 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 #include <atlbase.h> | 10 #include <atlbase.h> |
| 11 | 11 |
| 12 #include <algorithm> | 12 #include <algorithm> |
| 13 #include <set> | 13 #include <set> |
| 14 | 14 |
| 15 #include "app/gfx/font.h" | 15 #include "app/gfx/font.h" |
| 16 #include "app/l10n_util.h" | 16 #include "app/l10n_util.h" |
| 17 #include "app/win_util.h" | 17 #include "app/win_util.h" |
| 18 #include "base/file_util.h" | 18 #include "base/file_util.h" |
| 19 #include "base/registry.h" | 19 #include "base/registry.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" | |
| 26 | 24 |
| 27 // Helpers to show certain types of Windows shell dialogs in a way that doesn't | 25 // Helpers to show certain types of Windows shell dialogs in a way that doesn't |
| 28 // block the UI of the entire app. | 26 // block the UI of the entire app. |
| 29 | 27 |
| 30 class ShellDialogThread : public base::Thread { | 28 class ShellDialogThread : public base::Thread { |
| 31 public: | 29 public: |
| 32 ShellDialogThread() : base::Thread("Chrome_ShellDialogThread") { } | 30 ShellDialogThread() : base::Thread("Chrome_ShellDialogThread") { } |
| 33 | 31 |
| 34 protected: | 32 protected: |
| 35 void Init() { | 33 void Init() { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 // boxes active, this list will consist of the two browser windows' HWNDs. | 109 // boxes active, this list will consist of the two browser windows' HWNDs. |
| 112 // The derived class must call EndRun once the dialog is done showing to | 110 // The derived class must call EndRun once the dialog is done showing to |
| 113 // remove the owning HWND from this list. | 111 // remove the owning HWND from this list. |
| 114 // This object is static since it is maintained for all instances of this | 112 // This object is static since it is maintained for all instances of this |
| 115 // object - i.e. you can't have a font picker and a file picker open for the | 113 // object - i.e. you can't have a font picker and a file picker open for the |
| 116 // same owner, even though they might be represented by different instances | 114 // same owner, even though they might be represented by different instances |
| 117 // of this object. | 115 // of this object. |
| 118 // This set only contains non-null HWNDs. NULL hwnds are not added to this | 116 // This set only contains non-null HWNDs. NULL hwnds are not added to this |
| 119 // list. | 117 // list. |
| 120 typedef std::set<HWND> Owners; | 118 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 | |
| 126 static Owners owners_; | 119 static Owners owners_; |
| 127 static int instance_count_; | 120 static int instance_count_; |
| 128 | 121 |
| 129 DISALLOW_COPY_AND_ASSIGN(BaseShellDialogImpl); | 122 DISALLOW_COPY_AND_ASSIGN(BaseShellDialogImpl); |
| 130 }; | 123 }; |
| 131 | 124 |
| 132 // static | 125 // static |
| 133 BaseShellDialogImpl::Owners BaseShellDialogImpl::owners_; | 126 BaseShellDialogImpl::Owners BaseShellDialogImpl::owners_; |
| 134 int BaseShellDialogImpl::instance_count_ = 0; | 127 int BaseShellDialogImpl::instance_count_ = 0; |
| 135 | 128 |
| 136 BaseShellDialogImpl::BaseShellDialogImpl() | 129 BaseShellDialogImpl::BaseShellDialogImpl() |
| 137 : ui_loop_(MessageLoop::current()), | 130 : ui_loop_(MessageLoop::current()) { |
| 138 view_storage_id_(views::ViewStorage::GetSharedInstance()-> | |
| 139 CreateStorageID()) { | |
| 140 ++instance_count_; | 131 ++instance_count_; |
| 141 } | 132 } |
| 142 | 133 |
| 143 BaseShellDialogImpl::~BaseShellDialogImpl() { | 134 BaseShellDialogImpl::~BaseShellDialogImpl() { |
| 144 // All runs should be complete by the time this is called! | 135 // All runs should be complete by the time this is called! |
| 145 if (--instance_count_ == 0) | 136 if (--instance_count_ == 0) |
| 146 DCHECK(owners_.empty()); | 137 DCHECK(owners_.empty()); |
| 147 } | 138 } |
| 148 | 139 |
| 149 BaseShellDialogImpl::RunState BaseShellDialogImpl::BeginRun(HWND owner) { | 140 BaseShellDialogImpl::RunState BaseShellDialogImpl::BeginRun(HWND owner) { |
| 150 // Cannot run a modal shell dialog if one is already running for this owner. | 141 // Cannot run a modal shell dialog if one is already running for this owner. |
| 151 DCHECK(!IsRunningDialogForOwner(owner)); | 142 DCHECK(!IsRunningDialogForOwner(owner)); |
| 152 // The owner must be a top level window, otherwise we could end up with two | 143 // The owner must be a top level window, otherwise we could end up with two |
| 153 // entries in our map for the same top level window. | 144 // entries in our map for the same top level window. |
| 154 DCHECK(!owner || owner == GetAncestor(owner, GA_ROOT)); | 145 DCHECK(!owner || owner == GetAncestor(owner, GA_ROOT)); |
| 155 RunState run_state; | 146 RunState run_state; |
| 156 run_state.dialog_thread = CreateDialogThread(); | 147 run_state.dialog_thread = CreateDialogThread(); |
| 157 run_state.owner = owner; | 148 run_state.owner = owner; |
| 158 if (owner) { | 149 if (owner) { |
| 159 owners_.insert(owner); | 150 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 } | |
| 174 DisableOwner(owner); | 151 DisableOwner(owner); |
| 175 } | 152 } |
| 176 return run_state; | 153 return run_state; |
| 177 } | 154 } |
| 178 | 155 |
| 179 void BaseShellDialogImpl::EndRun(RunState run_state) { | 156 void BaseShellDialogImpl::EndRun(RunState run_state) { |
| 180 if (run_state.owner) { | 157 if (run_state.owner) { |
| 181 DCHECK(IsRunningDialogForOwner(run_state.owner)); | 158 DCHECK(IsRunningDialogForOwner(run_state.owner)); |
| 182 EnableOwner(run_state.owner); | 159 EnableOwner(run_state.owner); |
| 183 DCHECK(owners_.find(run_state.owner) != owners_.end()); | 160 DCHECK(owners_.find(run_state.owner) != owners_.end()); |
| 184 owners_.erase(run_state.owner); | 161 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 } | |
| 203 } | 162 } |
| 204 DCHECK(run_state.dialog_thread); | 163 DCHECK(run_state.dialog_thread); |
| 205 delete run_state.dialog_thread; | 164 delete run_state.dialog_thread; |
| 206 } | 165 } |
| 207 | 166 |
| 208 bool BaseShellDialogImpl::IsRunningDialogForOwner(HWND owner) const { | 167 bool BaseShellDialogImpl::IsRunningDialogForOwner(HWND owner) const { |
| 209 return (owner && owners_.find(owner) != owners_.end()); | 168 return (owner && owners_.find(owner) != owners_.end()); |
| 210 } | 169 } |
| 211 | 170 |
| 212 void BaseShellDialogImpl::DisableOwner(HWND owner) { | 171 void BaseShellDialogImpl::DisableOwner(HWND owner) { |
| (...skipping 569 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 782 void SelectFontDialogImpl::FontNotSelected(void* params, RunState run_state) { | 741 void SelectFontDialogImpl::FontNotSelected(void* params, RunState run_state) { |
| 783 if (listener_) | 742 if (listener_) |
| 784 listener_->FontSelectionCanceled(params); | 743 listener_->FontSelectionCanceled(params); |
| 785 EndRun(run_state); | 744 EndRun(run_state); |
| 786 } | 745 } |
| 787 | 746 |
| 788 // static | 747 // static |
| 789 SelectFontDialog* SelectFontDialog::Create(Listener* listener) { | 748 SelectFontDialog* SelectFontDialog::Create(Listener* listener) { |
| 790 return new SelectFontDialogImpl(listener); | 749 return new SelectFontDialogImpl(listener); |
| 791 } | 750 } |
| OLD | NEW |