Index: chrome/browser/ui/views/base_shell_dialog_win.cc |
diff --git a/chrome/browser/ui/views/base_shell_dialog_win.cc b/chrome/browser/ui/views/base_shell_dialog_win.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ffb77ea721a10352f23f14cbb9952c7de74262a5 |
--- /dev/null |
+++ b/chrome/browser/ui/views/base_shell_dialog_win.cc |
@@ -0,0 +1,104 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/ui/views/base_shell_dialog_win.h" |
+ |
+#include <algorithm> |
+ |
+#include "base/threading/thread.h" |
+ |
+// 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(); |
+ |
+ protected: |
+ void Init(); |
+ |
+ void CleanUp(); |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(ShellDialogThread); |
+}; |
+ |
+ShellDialogThread::~ShellDialogThread() { |
+ Stop(); |
+} |
+ |
+void ShellDialogThread::Init() { |
+ // Initializes the COM library on the current thread. |
+ CoInitialize(NULL); |
+} |
+ |
+void ShellDialogThread::CleanUp() { |
+ // Closes the COM library on the current thread. CoInitialize must |
+ // be balanced by a corresponding call to CoUninitialize. |
+ CoUninitialize(); |
+} |
+ |
+// 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); |
+} |