#include "base/basictypes.h"
#include "base/compiler_specific.h"
-#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_pump_dispatcher.h"
-#include "base/run_loop.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/ui/views/constrained_window_views.h"
-#include "grit/generated_resources.h"
+#include "chrome/grit/generated_resources.h"
+#include "ui/aura/window.h"
#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/controls/message_box_view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/dialog_delegate.h"
+#include "ui/wm/public/dispatcher_client.h"
-#if defined(USE_AURA)
-#include "ui/aura/client/dispatcher_client.h"
-#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
#if defined(OS_WIN)
-#include "chrome/browser/ui/views/simple_message_box_win.h"
-#endif
+#include "ui/base/win/message_box_win.h"
+#include "ui/views/win/hwnd_util.h"
#endif
namespace chrome {
namespace {
-// Multiple SimpleMessageBoxViews can show up at the same time. Each of these
-// start a nested message-loop. However, these SimpleMessageBoxViews can be
-// deleted in any order. This creates problems if a box in an inner-loop gets
-// destroyed before a box in an outer-loop. So to avoid this, ref-counting is
-// used so that the SimpleMessageBoxViews gets deleted at the right time.
-class SimpleMessageBoxViews : public views::DialogDelegate,
- public base::MessagePumpDispatcher,
- public base::RefCounted<SimpleMessageBoxViews> {
+class SimpleMessageBoxViews : public views::DialogDelegate {
public:
SimpleMessageBoxViews(const base::string16& title,
const base::string16& message,
MessageBoxType type,
const base::string16& yes_text,
- const base::string16& no_text);
+ const base::string16& no_text,
+ bool is_system_modal);
+ virtual ~SimpleMessageBoxViews();
- MessageBoxResult result() const { return result_; }
+ MessageBoxResult RunDialogAndGetResult();
// Overridden from views::DialogDelegate:
virtual int GetDialogButtons() const OVERRIDE;
virtual views::Widget* GetWidget() OVERRIDE;
virtual const views::Widget* GetWidget() const OVERRIDE;
- // Overridden from MessagePumpDispatcher:
- virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
-
private:
- friend class base::RefCounted<SimpleMessageBoxViews>;
- virtual ~SimpleMessageBoxViews();
+
+ // This terminates the nested message-loop.
+ void Done();
const base::string16 window_title_;
const MessageBoxType type_;
base::string16 yes_text_;
base::string16 no_text_;
- MessageBoxResult result_;
+ MessageBoxResult* result_;
+ bool is_system_modal_;
views::MessageBoxView* message_box_view_;
-
- // Set to false as soon as the user clicks a dialog button; this tells the
- // dispatcher we're done.
- bool should_show_dialog_;
+ base::Closure quit_runloop_;
DISALLOW_COPY_AND_ASSIGN(SimpleMessageBoxViews);
};
const base::string16& message,
MessageBoxType type,
const base::string16& yes_text,
- const base::string16& no_text)
+ const base::string16& no_text,
+ bool is_system_modal)
: window_title_(title),
type_(type),
yes_text_(yes_text),
no_text_(no_text),
- result_(MESSAGE_BOX_RESULT_NO),
+ result_(NULL),
+ is_system_modal_(is_system_modal),
message_box_view_(new views::MessageBoxView(
- views::MessageBoxView::InitParams(message))),
- should_show_dialog_(true) {
- AddRef();
-
+ views::MessageBoxView::InitParams(message))) {
if (yes_text_.empty()) {
if (type_ == MESSAGE_BOX_TYPE_QUESTION)
yes_text_ =
}
}
+SimpleMessageBoxViews::~SimpleMessageBoxViews() {
+}
+
+MessageBoxResult SimpleMessageBoxViews::RunDialogAndGetResult() {
+ MessageBoxResult result = MESSAGE_BOX_RESULT_NO;
+ result_ = &result;
+ // Use the widget's window itself so that the message loop exists when the
+ // dialog is closed by some other means than |Cancel| or |Accept|.
+ aura::Window* anchor = GetWidget()->GetNativeWindow();
+ aura::client::DispatcherRunLoop run_loop(
+ aura::client::GetDispatcherClient(anchor->GetRootWindow()), NULL);
+ quit_runloop_ = run_loop.QuitClosure();
+ run_loop.Run();
+ return result;
+}
+
int SimpleMessageBoxViews::GetDialogButtons() const {
if (type_ == MESSAGE_BOX_TYPE_QUESTION ||
type_ == MESSAGE_BOX_TYPE_OK_CANCEL) {
}
bool SimpleMessageBoxViews::Cancel() {
- should_show_dialog_= false;
- result_ = MESSAGE_BOX_RESULT_NO;
+ *result_ = MESSAGE_BOX_RESULT_NO;
+ Done();
return true;
}
bool SimpleMessageBoxViews::Accept() {
- should_show_dialog_ = false;
- result_ = MESSAGE_BOX_RESULT_YES;
+ *result_ = MESSAGE_BOX_RESULT_YES;
+ Done();
return true;
}
}
void SimpleMessageBoxViews::DeleteDelegate() {
- Release();
+ delete this;
}
ui::ModalType SimpleMessageBoxViews::GetModalType() const {
- return ui::MODAL_TYPE_WINDOW;
+ return is_system_modal_ ? ui::MODAL_TYPE_SYSTEM : ui::MODAL_TYPE_WINDOW;
}
views::View* SimpleMessageBoxViews::GetContentsView() {
return message_box_view_->GetWidget();
}
-bool SimpleMessageBoxViews::Dispatch(const base::NativeEvent& event) {
-#if defined(OS_WIN)
- TranslateMessage(&event);
- DispatchMessage(&event);
-#elif defined(USE_AURA)
- aura::Env::GetInstance()->GetDispatcher()->Dispatch(event);
-#endif
- return should_show_dialog_;
-}
-
////////////////////////////////////////////////////////////////////////////////
// SimpleMessageBoxViews, private:
-SimpleMessageBoxViews::~SimpleMessageBoxViews() {
+void SimpleMessageBoxViews::Done() {
+ CHECK(!quit_runloop_.is_null());
+ quit_runloop_.Run();
+}
+
+#if defined(OS_WIN)
+UINT GetMessageBoxFlagsFromType(MessageBoxType type) {
+ UINT flags = MB_SETFOREGROUND;
+ switch (type) {
+ case MESSAGE_BOX_TYPE_INFORMATION:
+ return flags | MB_OK | MB_ICONINFORMATION;
+ case MESSAGE_BOX_TYPE_WARNING:
+ return flags | MB_OK | MB_ICONWARNING;
+ case MESSAGE_BOX_TYPE_QUESTION:
+ return flags | MB_YESNO | MB_ICONQUESTION;
+ case MESSAGE_BOX_TYPE_OK_CANCEL:
+ return flags | MB_OKCANCEL | MB_ICONWARNING;
+ }
+ NOTREACHED();
+ return flags | MB_OK | MB_ICONWARNING;
}
+#endif
MessageBoxResult ShowMessageBoxImpl(gfx::NativeWindow parent,
const base::string16& title,
MessageBoxType type,
const base::string16& yes_text,
const base::string16& no_text) {
-
-#if defined(USE_AURA) && defined(OS_WIN)
- // If we're very early, we can't show a GPU-based dialog, so fallback to
- // plain Windows MessageBox.
- if (!ui::ContextFactory::GetInstance())
- return NativeShowMessageBox(NULL, title, message, type);
-#endif
-
- scoped_refptr<SimpleMessageBoxViews> dialog(
- new SimpleMessageBoxViews(title, message, type, yes_text, no_text));
- CreateBrowserModalDialogViews(dialog.get(), parent)->Show();
-
-#if defined(USE_AURA)
- aura::Window* anchor = parent;
- aura::client::DispatcherClient* client = anchor ?
- aura::client::GetDispatcherClient(anchor->GetRootWindow()) : NULL;
- if (!client) {
- // Use the widget's window itself so that the message loop
- // exists when the dialog is closed by some other means than
- // |Cancel| or |Accept|.
- anchor = dialog->GetWidget()->GetNativeWindow();
- client = aura::client::GetDispatcherClient(anchor->GetRootWindow());
+ // Views dialogs cannot be shown outside the UI thread message loop or if the
+ // ResourceBundle is not initialized yet.
+ // Fallback to logging with a default response or a Windows MessageBox.
+#if defined(OS_WIN)
+ if (!base::MessageLoopForUI::IsCurrent() ||
+ !base::MessageLoopForUI::current()->is_running() ||
+ !ResourceBundle::HasSharedInstance()) {
+ int result = ui::MessageBox(views::HWNDForNativeWindow(parent), message,
+ title, GetMessageBoxFlagsFromType(type));
+ return (result == IDYES || result == IDOK) ?
+ MESSAGE_BOX_RESULT_YES : MESSAGE_BOX_RESULT_NO;
}
- client->RunWithDispatcher(dialog.get(), anchor, true);
#else
- {
- base::MessageLoop::ScopedNestableTaskAllower allow(
- base::MessageLoopForUI::current());
- base::RunLoop run_loop(dialog);
- run_loop.Run();
+ if (!base::MessageLoopForUI::IsCurrent() ||
+ !ResourceBundle::HasSharedInstance()) {
+ LOG(ERROR) << "Unable to show a dialog outside the UI thread message loop: "
+ << title << " - " << message;
+ return MESSAGE_BOX_RESULT_NO;
}
#endif
- return dialog->result();
+
+ SimpleMessageBoxViews* dialog =
+ new SimpleMessageBoxViews(title,
+ message,
+ type,
+ yes_text,
+ no_text,
+ parent == NULL // is_system_modal
+ );
+ CreateBrowserModalDialogViews(dialog, parent)->Show();
+
+ // NOTE: |dialog| may have been deleted by the time |RunDialogAndGetResult()|
+ // returns.
+ return dialog->RunDialogAndGetResult();
}
} // namespace
parent, title, message, type, base::string16(), base::string16());
}
-#if defined(USE_AURA)
MessageBoxResult ShowMessageBoxWithButtonText(gfx::NativeWindow parent,
const base::string16& title,
const base::string16& message,
return ShowMessageBoxImpl(
parent, title, message, MESSAGE_BOX_TYPE_QUESTION, yes_text, no_text);
}
-#endif
} // namespace chrome