| Index: chrome/browser/ui/views/select_file_dialog_win.cc
|
| diff --git a/chrome/browser/ui/views/select_file_dialog_win.cc b/chrome/browser/ui/views/select_file_dialog_win.cc
|
| index 5414b422fab6d12ae0840615e679aeb0174e1d1e..80dedf20154887143caf45b5c5af84cc7772629b 100644
|
| --- a/chrome/browser/ui/views/select_file_dialog_win.cc
|
| +++ b/chrome/browser/ui/views/select_file_dialog_win.cc
|
| @@ -22,6 +22,7 @@
|
| #include "base/win/registry.h"
|
| #include "base/win/scoped_comptr.h"
|
| #include "base/win/windows_version.h"
|
| +#include "chrome/browser/ui/views/base_shell_dialog_win.h"
|
| #include "content/public/browser/browser_thread.h"
|
| #include "grit/generated_resources.h"
|
| #include "grit/ui_strings.h"
|
| @@ -389,169 +390,6 @@ bool SaveFileAs(HWND owner,
|
|
|
| } // namespace
|
|
|
| -// Helpers to show certain types of Windows shell dialogs in a way that doesn't
|
| -// block the UI of the entire app.
|
| -
|
| -class ShellDialogThread : public base::Thread {
|
| - public:
|
| - ShellDialogThread() : base::Thread("Chrome_ShellDialogThread") { }
|
| - ~ShellDialogThread() {
|
| - Stop();
|
| - }
|
| -
|
| - protected:
|
| - void Init() {
|
| - // Initializes the COM library on the current thread.
|
| - CoInitialize(NULL);
|
| - }
|
| -
|
| - void CleanUp() {
|
| - // Closes the COM library on the current thread. CoInitialize must
|
| - // be balanced by a corresponding call to CoUninitialize.
|
| - CoUninitialize();
|
| - }
|
| -
|
| - private:
|
| - DISALLOW_COPY_AND_ASSIGN(ShellDialogThread);
|
| -};
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -// A base class for all shell dialog implementations that handles showing a
|
| -// shell dialog modally on its own thread.
|
| -class BaseShellDialogImpl {
|
| - public:
|
| - BaseShellDialogImpl();
|
| - virtual ~BaseShellDialogImpl();
|
| -
|
| - protected:
|
| - // Represents a run of a dialog.
|
| - struct RunState {
|
| - // Owning HWND, may be null.
|
| - HWND owner;
|
| -
|
| - // Thread dialog is run on.
|
| - base::Thread* dialog_thread;
|
| - };
|
| -
|
| - // Called at the beginning of a modal dialog run. Disables the owner window
|
| - // and tracks it. Returns the message loop of the thread that the dialog will
|
| - // be run on.
|
| - RunState BeginRun(HWND owner);
|
| -
|
| - // Cleans up after a dialog run. If the run_state has a valid HWND this makes
|
| - // sure that the window is enabled. This is essential because BeginRun
|
| - // aggressively guards against multiple modal dialogs per HWND. Must be called
|
| - // on the UI thread after the result of the dialog has been determined.
|
| - //
|
| - // In addition this deletes the Thread in RunState.
|
| - void EndRun(RunState run_state);
|
| -
|
| - // Returns true if a modal shell dialog is currently active for the specified
|
| - // owner. Must be called on the UI thread.
|
| - bool IsRunningDialogForOwner(HWND owner) const;
|
| -
|
| - // Disables the window |owner|. Can be run from either the ui or the dialog
|
| - // thread. Can be called on either the UI or the dialog thread. This function
|
| - // is called on the dialog thread after the modal Windows Common dialog
|
| - // functions return because Windows automatically re-enables the owning
|
| - // window when those functions return, but we don't actually want them to be
|
| - // re-enabled until the response of the dialog propagates back to the UI
|
| - // thread, so we disable the owner manually after the Common dialog function
|
| - // returns.
|
| - void DisableOwner(HWND owner);
|
| -
|
| - private:
|
| - // Creates a thread to run a shell dialog on. Each dialog requires its own
|
| - // thread otherwise in some situations where a singleton owns a single
|
| - // instance of this object we can have a situation where a modal dialog in
|
| - // one window blocks the appearance of a modal dialog in another.
|
| - static base::Thread* CreateDialogThread();
|
| -
|
| - // Enables the window |owner_|. Can only be run from the ui thread.
|
| - void EnableOwner(HWND owner);
|
| -
|
| - // A list of windows that currently own active shell dialogs for this
|
| - // instance. For example, if the DownloadManager owns an instance of this
|
| - // object and there are two browser windows open both with Save As dialog
|
| - // boxes active, this list will consist of the two browser windows' HWNDs.
|
| - // The derived class must call EndRun once the dialog is done showing to
|
| - // remove the owning HWND from this list.
|
| - // This object is static since it is maintained for all instances of this
|
| - // object - i.e. you can't have two file pickers open for the
|
| - // same owner, even though they might be represented by different instances
|
| - // of this object.
|
| - // This set only contains non-null HWNDs. NULL hwnds are not added to this
|
| - // list.
|
| - typedef std::set<HWND> Owners;
|
| - static Owners owners_;
|
| - static int instance_count_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(BaseShellDialogImpl);
|
| -};
|
| -
|
| -// static
|
| -BaseShellDialogImpl::Owners BaseShellDialogImpl::owners_;
|
| -int BaseShellDialogImpl::instance_count_ = 0;
|
| -
|
| -BaseShellDialogImpl::BaseShellDialogImpl() {
|
| - ++instance_count_;
|
| -}
|
| -
|
| -BaseShellDialogImpl::~BaseShellDialogImpl() {
|
| - // All runs should be complete by the time this is called!
|
| - if (--instance_count_ == 0)
|
| - DCHECK(owners_.empty());
|
| -}
|
| -
|
| -BaseShellDialogImpl::RunState BaseShellDialogImpl::BeginRun(HWND owner) {
|
| - // Cannot run a modal shell dialog if one is already running for this owner.
|
| - DCHECK(!IsRunningDialogForOwner(owner));
|
| - // The owner must be a top level window, otherwise we could end up with two
|
| - // entries in our map for the same top level window.
|
| - DCHECK(!owner || owner == GetAncestor(owner, GA_ROOT));
|
| - RunState run_state;
|
| - run_state.dialog_thread = CreateDialogThread();
|
| - run_state.owner = owner;
|
| - if (owner) {
|
| - owners_.insert(owner);
|
| - DisableOwner(owner);
|
| - }
|
| - return run_state;
|
| -}
|
| -
|
| -void BaseShellDialogImpl::EndRun(RunState run_state) {
|
| - if (run_state.owner) {
|
| - DCHECK(IsRunningDialogForOwner(run_state.owner));
|
| - EnableOwner(run_state.owner);
|
| - DCHECK(owners_.find(run_state.owner) != owners_.end());
|
| - owners_.erase(run_state.owner);
|
| - }
|
| - DCHECK(run_state.dialog_thread);
|
| - delete run_state.dialog_thread;
|
| -}
|
| -
|
| -bool BaseShellDialogImpl::IsRunningDialogForOwner(HWND owner) const {
|
| - return (owner && owners_.find(owner) != owners_.end());
|
| -}
|
| -
|
| -void BaseShellDialogImpl::DisableOwner(HWND owner) {
|
| - if (IsWindow(owner))
|
| - EnableWindow(owner, FALSE);
|
| -}
|
| -
|
| -// static
|
| -base::Thread* BaseShellDialogImpl::CreateDialogThread() {
|
| - base::Thread* thread = new ShellDialogThread;
|
| - bool started = thread->Start();
|
| - DCHECK(started);
|
| - return thread;
|
| -}
|
| -
|
| -void BaseShellDialogImpl::EnableOwner(HWND owner) {
|
| - if (IsWindow(owner))
|
| - EnableWindow(owner, TRUE);
|
| -}
|
| -
|
| // Implementation of SelectFileDialog that shows a Windows common dialog for
|
| // choosing a file or folder.
|
| class SelectFileDialogImpl : public SelectFileDialog,
|
|
|