From 1ff00281f39ba0720e9735b541d3b0dedef5ab47 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 7 Jul 2015 15:02:27 +0800 Subject: [PATCH 1/9] Seperate linux's implementation of message box --- atom/browser/ui/message_box_gtk.cc | 63 +++++++++++++++++++ ...essage_box_views.cc => message_box_win.cc} | 43 +------------ filenames.gypi | 3 +- 3 files changed, 66 insertions(+), 43 deletions(-) create mode 100644 atom/browser/ui/message_box_gtk.cc rename atom/browser/ui/{message_box_views.cc => message_box_win.cc} (90%) diff --git a/atom/browser/ui/message_box_gtk.cc b/atom/browser/ui/message_box_gtk.cc new file mode 100644 index 000000000000..90a8d4a04cac --- /dev/null +++ b/atom/browser/ui/message_box_gtk.cc @@ -0,0 +1,63 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/ui/message_box.h" + +#include + +#include "atom/browser/browser.h" +#include "base/callback.h" +#include "base/strings/utf_string_conversions.h" + +#define ANSI_FOREGROUND_RED "\x1b[31m" +#define ANSI_FOREGROUND_BLACK "\x1b[30m" +#define ANSI_TEXT_BOLD "\x1b[1m" +#define ANSI_BACKGROUND_GRAY "\x1b[47m" +#define ANSI_RESET "\x1b[0m" + +namespace atom { + +int ShowMessageBox(NativeWindow* parent_window, + MessageBoxType type, + const std::vector& buttons, + const std::string& title, + const std::string& message, + const std::string& detail, + const gfx::ImageSkia& icon) { + return 0; +} + +void ShowMessageBox(NativeWindow* parent_window, + MessageBoxType type, + const std::vector& buttons, + const std::string& title, + const std::string& message, + const std::string& detail, + const gfx::ImageSkia& icon, + const MessageBoxCallback& callback) { + callback.Run(0); +} + +void ShowErrorBox(const base::string16& title, const base::string16& content) { + if (Browser::Get()->is_ready()) { + GtkWidget* dialog = gtk_message_dialog_new( + NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, + "%s", base::UTF16ToUTF8(title).c_str()); + gtk_message_dialog_format_secondary_text( + GTK_MESSAGE_DIALOG(dialog), + "%s", base::UTF16ToUTF8(content).c_str()); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + } else { + fprintf(stderr, + ANSI_TEXT_BOLD ANSI_BACKGROUND_GRAY + ANSI_FOREGROUND_RED "%s\n" + ANSI_FOREGROUND_BLACK "%s" + ANSI_RESET "\n", + base::UTF16ToUTF8(title).c_str(), + base::UTF16ToUTF8(content).c_str()); + } +} + +} // namespace atom diff --git a/atom/browser/ui/message_box_views.cc b/atom/browser/ui/message_box_win.cc similarity index 90% rename from atom/browser/ui/message_box_views.cc rename to atom/browser/ui/message_box_win.cc index 6e1cc9daa2ba..508d6eb233d9 100644 --- a/atom/browser/ui/message_box_views.cc +++ b/atom/browser/ui/message_box_win.cc @@ -4,10 +4,6 @@ #include "atom/browser/ui/message_box.h" -#if defined(USE_X11) -#include -#endif - #include "atom/browser/native_window.h" #include "base/callback.h" #include "base/message_loop/message_loop.h" @@ -26,21 +22,10 @@ #include "ui/views/widget/widget_delegate.h" #include "ui/wm/core/shadow_types.h" -#if defined(USE_X11) -#include "atom/browser/browser.h" -#include "ui/views/window/native_frame_view.h" -#endif - #if defined(OS_WIN) #include "ui/base/win/message_box_win.h" #endif -#define ANSI_FOREGROUND_RED "\x1b[31m" -#define ANSI_FOREGROUND_BLACK "\x1b[30m" -#define ANSI_TEXT_BOLD "\x1b[1m" -#define ANSI_BACKGROUND_GRAY "\x1b[47m" -#define ANSI_RESET "\x1b[0m" - namespace atom { namespace { @@ -276,13 +261,8 @@ ui::ModalType MessageDialog::GetModalType() const { views::NonClientFrameView* MessageDialog::CreateNonClientFrameView( views::Widget* widget) { - if (!parent_) { -#if defined(USE_X11) - return new views::NativeFrameView(widget); -#else + if (!parent_) return NULL; -#endif - } // Create a bubble style frame like Chrome. views::BubbleFrameView* frame = new views::BubbleFrameView(gfx::Insets()); @@ -390,28 +370,7 @@ void ShowMessageBox(NativeWindow* parent_window, } void ShowErrorBox(const base::string16& title, const base::string16& content) { -#if defined(OS_WIN) ui::MessageBox(NULL, content, title, MB_OK | MB_ICONERROR | MB_TASKMODAL); -#elif defined(USE_X11) - if (Browser::Get()->is_ready()) { - GtkWidget* dialog = gtk_message_dialog_new( - NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, - "%s", base::UTF16ToUTF8(title).c_str()); - gtk_message_dialog_format_secondary_text( - GTK_MESSAGE_DIALOG(dialog), - "%s", base::UTF16ToUTF8(content).c_str()); - gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - } else { - fprintf(stderr, - ANSI_TEXT_BOLD ANSI_BACKGROUND_GRAY - ANSI_FOREGROUND_RED "%s\n" - ANSI_FOREGROUND_BLACK "%s" - ANSI_RESET "\n", - base::UTF16ToUTF8(title).c_str(), - base::UTF16ToUTF8(content).c_str()); - } -#endif } } // namespace atom diff --git a/filenames.gypi b/filenames.gypi index 3f299c066a65..837dd3301cc8 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -175,8 +175,9 @@ 'atom/browser/ui/file_dialog_mac.mm', 'atom/browser/ui/file_dialog_win.cc', 'atom/browser/ui/message_box.h', + 'atom/browser/ui/message_box_gtk.cc', 'atom/browser/ui/message_box_mac.mm', - 'atom/browser/ui/message_box_views.cc', + 'atom/browser/ui/message_box_win.cc', 'atom/browser/ui/tray_icon.cc', 'atom/browser/ui/tray_icon.h', 'atom/browser/ui/tray_icon_gtk.cc', From 8fca1f52d3e40f166aab0d3cd8c936de62fbcbc6 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 7 Jul 2015 15:07:18 +0800 Subject: [PATCH 2/9] Use SetGtkTransientForAura from libgtk2ui --- atom/browser/ui/file_dialog_gtk.cc | 35 ++---------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/atom/browser/ui/file_dialog_gtk.cc b/atom/browser/ui/file_dialog_gtk.cc index 40c14028d4fa..48b9ec534308 100644 --- a/atom/browser/ui/file_dialog_gtk.cc +++ b/atom/browser/ui/file_dialog_gtk.cc @@ -4,49 +4,18 @@ #include "atom/browser/ui/file_dialog.h" -#include -#include -#include - -// This conflicts with mate::Converter, -#undef True -#undef False -// and V8. -#undef None - #include "atom/browser/native_window.h" #include "base/callback.h" #include "base/files/file_util.h" #include "base/strings/string_util.h" #include "chrome/browser/ui/libgtk2ui/gtk2_signal.h" -#include "ui/aura/window.h" -#include "ui/aura/window_tree_host.h" +#include "chrome/browser/ui/libgtk2ui/gtk2_util.h" #include "ui/views/widget/desktop_aura/x11_desktop_handler.h" namespace file_dialog { namespace { -const char kAuraTransientParent[] = "aura-transient-parent"; - -void SetGtkTransientForAura(GtkWidget* dialog, aura::Window* parent) { - if (!parent || !parent->GetHost()) - return; - - gtk_widget_realize(dialog); - GdkWindow* gdk_window = gtk_widget_get_window(dialog); - - // TODO(erg): Check to make sure we're using X11 if wayland or some other - // display server ever happens. Otherwise, this will crash. - XSetTransientForHint(GDK_WINDOW_XDISPLAY(gdk_window), - GDK_WINDOW_XID(gdk_window), - parent->GetHost()->GetAcceleratedWidget()); - - // We also set the |parent| as a property of |dialog|, so that we can unlink - // the two later. - g_object_set_data(G_OBJECT(dialog), kAuraTransientParent, parent); -} - // Makes sure that .jpg also shows .JPG. gboolean FileFilterCaseInsensitive(const GtkFileFilterInfo* file_info, std::string* file_extension) { @@ -81,7 +50,7 @@ class FileChooserDialog { NULL); if (parent_window) { gfx::NativeWindow window = parent_window->GetNativeWindow(); - SetGtkTransientForAura(dialog_, window); + libgtk2ui::SetGtkTransientForAura(dialog_, window); } if (action == GTK_FILE_CHOOSER_ACTION_SAVE) From b98cdf71c493aea68c3a849eee7cb148371e910b Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 7 Jul 2015 15:45:13 +0800 Subject: [PATCH 3/9] gtk: Implement message box APIs --- atom/browser/ui/file_dialog_gtk.cc | 6 +- atom/browser/ui/message_box_gtk.cc | 135 +++++++++++++++++++++++++++-- 2 files changed, 132 insertions(+), 9 deletions(-) diff --git a/atom/browser/ui/file_dialog_gtk.cc b/atom/browser/ui/file_dialog_gtk.cc index 48b9ec534308..6eab9ef89f7b 100644 --- a/atom/browser/ui/file_dialog_gtk.cc +++ b/atom/browser/ui/file_dialog_gtk.cc @@ -34,7 +34,7 @@ class FileChooserDialog { const std::string& title, const base::FilePath& default_path, const Filters& filters) - : dialog_scope_(new atom::NativeWindow::DialogScope(parent_window)) { + : dialog_scope_(parent_window) { const char* confirm_text = GTK_STOCK_OK; if (action == GTK_FILE_CHOOSER_ACTION_SAVE) confirm_text = GTK_STOCK_SAVE; @@ -131,13 +131,13 @@ class FileChooserDialog { private: void AddFilters(const Filters& filters); + atom::NativeWindow::DialogScope dialog_scope_; + GtkWidget* dialog_; SaveDialogCallback save_callback_; OpenDialogCallback open_callback_; - scoped_ptr dialog_scope_; - DISALLOW_COPY_AND_ASSIGN(FileChooserDialog); }; diff --git a/atom/browser/ui/message_box_gtk.cc b/atom/browser/ui/message_box_gtk.cc index 90a8d4a04cac..3f5a1b83ab10 100644 --- a/atom/browser/ui/message_box_gtk.cc +++ b/atom/browser/ui/message_box_gtk.cc @@ -4,11 +4,14 @@ #include "atom/browser/ui/message_box.h" -#include - #include "atom/browser/browser.h" +#include "atom/browser/native_window.h" #include "base/callback.h" +#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h" +#include "chrome/browser/ui/libgtk2ui/gtk2_util.h" +#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h" #define ANSI_FOREGROUND_RED "\x1b[31m" #define ANSI_FOREGROUND_BLACK "\x1b[30m" @@ -18,17 +21,135 @@ namespace atom { -int ShowMessageBox(NativeWindow* parent_window, +namespace { + +class GtkMessageBox { + public: + GtkMessageBox(bool synchronous, + NativeWindow* parent_window, + MessageBoxType type, + const std::vector& buttons, + const std::string& title, + const std::string& message, + const std::string& detail, + const gfx::ImageSkia& icon) + : dialog_scope_(parent_window), + cancel_id_(0) { + // The dialog should be modal when showed synchronous. + int flags = GTK_DIALOG_NO_SEPARATOR; + if (synchronous) + flags |= GTK_DIALOG_MODAL; + + // Create dialog. + dialog_ = gtk_message_dialog_new( + nullptr, // parent + static_cast(flags), // flags + GTK_MESSAGE_OTHER, // no icon + GTK_BUTTONS_NONE, // no buttons + "%s", message.c_str()); + gtk_message_dialog_format_secondary_text( + GTK_MESSAGE_DIALOG(dialog_), + "%s", detail.empty() ? nullptr : detail.c_str()); + + // Set dialog's icon. + if (!icon.isNull()) { + GdkPixbuf* pixbuf = libgtk2ui::GdkPixbufFromSkBitmap(*icon.bitmap()); + GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf); + gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(dialog_), image); + gtk_widget_show(image); + g_object_unref(pixbuf); + } + + // Add buttons. + for (size_t i = 0; i < buttons.size(); ++i) { + gtk_dialog_add_button(GTK_DIALOG(dialog_), + TranslateToStock(i, buttons[i]), + i); + } + + // Parent window. + if (parent_window) { + gfx::NativeWindow window = parent_window->GetNativeWindow(); + libgtk2ui::SetGtkTransientForAura(dialog_, window); + } + } + + ~GtkMessageBox() { + gtk_widget_destroy(dialog_); + } + + const char* TranslateToStock(int id, const std::string& text) { + std::string lower = base::StringToLowerASCII(text); + if (lower == "cancel") { + cancel_id_ = id; + return GTK_STOCK_CANCEL; + } else if (lower == "no") { + cancel_id_ = id; + return GTK_STOCK_NO; + } else if (lower == "ok") { + return GTK_STOCK_OK; + } else if (lower == "yes") { + return GTK_STOCK_YES; + } else { + return text.c_str(); + } + } + + void RunAsynchronous(const MessageBoxCallback& callback) { + callback_ = callback; + g_signal_connect(dialog_, "delete-event", + G_CALLBACK(gtk_widget_hide_on_delete), nullptr); + g_signal_connect(dialog_, "response", + G_CALLBACK(OnResponseDialogThunk), this); + gtk_widget_show_all(dialog_); + } + + CHROMEGTK_CALLBACK_1(GtkMessageBox, void, OnResponseDialog, int); + + GtkWidget* dialog() const { return dialog_; } + int cancel_id() const { return cancel_id_; } + + private: + atom::NativeWindow::DialogScope dialog_scope_; + + // The id to return when the dialog is closed without pressing buttons. + int cancel_id_; + + GtkWidget* dialog_; + MessageBoxCallback callback_; + + DISALLOW_COPY_AND_ASSIGN(GtkMessageBox); +}; + +void GtkMessageBox::OnResponseDialog(GtkWidget* widget, int response) { + gtk_widget_hide_all(dialog_); + + if (response < 0) + callback_.Run(cancel_id_); + else + callback_.Run(response); + delete this; +} + +} // namespace + +int ShowMessageBox(NativeWindow* parent, MessageBoxType type, const std::vector& buttons, const std::string& title, const std::string& message, const std::string& detail, const gfx::ImageSkia& icon) { - return 0; + GtkMessageBox box(true, parent, type, buttons, title, message, detail, icon); + gtk_widget_show_all(box.dialog()); + int response = gtk_dialog_run(GTK_DIALOG(box.dialog())); + if (response < 0) + return box.cancel_id(); + else + return response; } -void ShowMessageBox(NativeWindow* parent_window, +void ShowMessageBox(NativeWindow* parent, MessageBoxType type, const std::vector& buttons, const std::string& title, @@ -36,7 +157,9 @@ void ShowMessageBox(NativeWindow* parent_window, const std::string& detail, const gfx::ImageSkia& icon, const MessageBoxCallback& callback) { - callback.Run(0); + auto box = new GtkMessageBox( + false, parent, type, buttons, title, message, detail, icon); + box->RunAsynchronous(callback); } void ShowErrorBox(const base::string16& title, const base::string16& content) { From 02e28ea7583c32d4ea9cb57c62aa4131d09eb488 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 7 Jul 2015 16:42:03 +0800 Subject: [PATCH 4/9] Fix focusing message box --- atom/browser/ui/message_box_gtk.cc | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/atom/browser/ui/message_box_gtk.cc b/atom/browser/ui/message_box_gtk.cc index 3f5a1b83ab10..571cab5c81c4 100644 --- a/atom/browser/ui/message_box_gtk.cc +++ b/atom/browser/ui/message_box_gtk.cc @@ -12,6 +12,7 @@ #include "chrome/browser/ui/libgtk2ui/gtk2_signal.h" #include "chrome/browser/ui/libgtk2ui/gtk2_util.h" #include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h" +#include "ui/views/widget/desktop_aura/x11_desktop_handler.h" #define ANSI_FOREGROUND_RED "\x1b[31m" #define ANSI_FOREGROUND_BLACK "\x1b[30m" @@ -25,7 +26,7 @@ namespace { class GtkMessageBox { public: - GtkMessageBox(bool synchronous, + GtkMessageBox(bool modal, NativeWindow* parent_window, MessageBoxType type, const std::vector& buttons, @@ -35,15 +36,11 @@ class GtkMessageBox { const gfx::ImageSkia& icon) : dialog_scope_(parent_window), cancel_id_(0) { - // The dialog should be modal when showed synchronous. - int flags = GTK_DIALOG_NO_SEPARATOR; - if (synchronous) - flags |= GTK_DIALOG_MODAL; - // Create dialog. dialog_ = gtk_message_dialog_new( nullptr, // parent - static_cast(flags), // flags + modal ? GTK_DIALOG_MODAL : // modal dialog + static_cast(0), // no flags GTK_MESSAGE_OTHER, // no icon GTK_BUTTONS_NONE, // no buttons "%s", message.c_str()); @@ -95,13 +92,21 @@ class GtkMessageBox { } } + void Show() { + gtk_widget_show_all(dialog_); + // We need to call gtk_window_present after making the widgets visible to + // make sure window gets correctly raised and gets focus. + int time = views::X11DesktopHandler::get()->wm_user_time_ms(); + gtk_window_present_with_time(GTK_WINDOW(dialog_), time); + } + void RunAsynchronous(const MessageBoxCallback& callback) { callback_ = callback; g_signal_connect(dialog_, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), nullptr); g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseDialogThunk), this); - gtk_widget_show_all(dialog_); + Show(); } CHROMEGTK_CALLBACK_1(GtkMessageBox, void, OnResponseDialog, int); @@ -141,7 +146,7 @@ int ShowMessageBox(NativeWindow* parent, const std::string& detail, const gfx::ImageSkia& icon) { GtkMessageBox box(true, parent, type, buttons, title, message, detail, icon); - gtk_widget_show_all(box.dialog()); + box.Show(); int response = gtk_dialog_run(GTK_DIALOG(box.dialog())); if (response < 0) return box.cancel_id(); From 3e6394a00471c95f9d9385e53531c15ed0b05d0d Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 7 Jul 2015 16:52:53 +0800 Subject: [PATCH 5/9] gtk: Map dialog type to message box type --- atom/browser/api/lib/dialog.coffee | 2 +- atom/browser/ui/message_box.h | 4 +++- atom/browser/ui/message_box_gtk.cc | 17 ++++++++++++++++- docs/api/dialog.md | 2 +- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/atom/browser/api/lib/dialog.coffee b/atom/browser/api/lib/dialog.coffee index 95ecf99d3e03..d95fa7426ac5 100644 --- a/atom/browser/api/lib/dialog.coffee +++ b/atom/browser/api/lib/dialog.coffee @@ -9,7 +9,7 @@ fileDialogProperties = multiSelections: 1 << 2 createDirectory: 1 << 3 -messageBoxTypes = ['none', 'info', 'warning'] +messageBoxTypes = ['none', 'info', 'warning', 'error', 'question'] parseArgs = (window, options, callback) -> unless window is null or window?.constructor is BrowserWindow diff --git a/atom/browser/ui/message_box.h b/atom/browser/ui/message_box.h index 04792085b7ae..acd1e3926b34 100644 --- a/atom/browser/ui/message_box.h +++ b/atom/browser/ui/message_box.h @@ -22,7 +22,9 @@ class NativeWindow; enum MessageBoxType { MESSAGE_BOX_TYPE_NONE = 0, MESSAGE_BOX_TYPE_INFORMATION, - MESSAGE_BOX_TYPE_WARNING + MESSAGE_BOX_TYPE_WARNING, + MESSAGE_BOX_TYPE_ERROR, + MESSAGE_BOX_TYPE_QUESTION, }; typedef base::Callback MessageBoxCallback; diff --git a/atom/browser/ui/message_box_gtk.cc b/atom/browser/ui/message_box_gtk.cc index 571cab5c81c4..27a15d9553ce 100644 --- a/atom/browser/ui/message_box_gtk.cc +++ b/atom/browser/ui/message_box_gtk.cc @@ -41,7 +41,7 @@ class GtkMessageBox { nullptr, // parent modal ? GTK_DIALOG_MODAL : // modal dialog static_cast(0), // no flags - GTK_MESSAGE_OTHER, // no icon + GetMessageType(type), // type GTK_BUTTONS_NONE, // no buttons "%s", message.c_str()); gtk_message_dialog_format_secondary_text( @@ -75,6 +75,21 @@ class GtkMessageBox { gtk_widget_destroy(dialog_); } + GtkMessageType GetMessageType(MessageBoxType type) { + switch (type) { + case MESSAGE_BOX_TYPE_INFORMATION: + return GTK_MESSAGE_INFO; + case MESSAGE_BOX_TYPE_WARNING: + return GTK_MESSAGE_WARNING; + case MESSAGE_BOX_TYPE_QUESTION: + return GTK_MESSAGE_QUESTION; + case MESSAGE_BOX_TYPE_ERROR: + return GTK_MESSAGE_ERROR; + default: + return GTK_MESSAGE_OTHER; + } + } + const char* TranslateToStock(int id, const std::string& text) { std::string lower = base::StringToLowerASCII(text); if (lower == "cancel") { diff --git a/docs/api/dialog.md b/docs/api/dialog.md index f8058649ae57..30689d958630 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -70,7 +70,7 @@ will be passed via `callback(filename)` * `browserWindow` BrowserWindow * `options` Object - * `type` String - Can be `"none"`, `"info"` or `"warning"` + * `type` String - Can be `"none"`, `"info"`, `"error"`, `"question"` or `"warning"` * `buttons` Array - Array of texts for buttons * `title` String - Title of the message box, some platforms will not show it * `message` String - Content of the message box From e627592eed98d9771d2088ba9d07d4e745356837 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 7 Jul 2015 16:57:19 +0800 Subject: [PATCH 6/9] Reuse ShowMessageBox in ShowErrorBox --- atom/browser/ui/message_box_gtk.cc | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/atom/browser/ui/message_box_gtk.cc b/atom/browser/ui/message_box_gtk.cc index 27a15d9553ce..a7c50eae6c7b 100644 --- a/atom/browser/ui/message_box_gtk.cc +++ b/atom/browser/ui/message_box_gtk.cc @@ -184,14 +184,12 @@ void ShowMessageBox(NativeWindow* parent, void ShowErrorBox(const base::string16& title, const base::string16& content) { if (Browser::Get()->is_ready()) { - GtkWidget* dialog = gtk_message_dialog_new( - NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, - "%s", base::UTF16ToUTF8(title).c_str()); - gtk_message_dialog_format_secondary_text( - GTK_MESSAGE_DIALOG(dialog), - "%s", base::UTF16ToUTF8(content).c_str()); - gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); + GtkMessageBox box(true, nullptr, MESSAGE_BOX_TYPE_ERROR, { "OK" }, "Error", + base::UTF16ToUTF8(title).c_str(), + base::UTF16ToUTF8(content).c_str(), + gfx::ImageSkia()); + box.Show(); + gtk_dialog_run(GTK_DIALOG(box.dialog())); } else { fprintf(stderr, ANSI_TEXT_BOLD ANSI_BACKGROUND_GRAY From 810f14aecb350d0167c9c7486a3f5083eaf04125 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 7 Jul 2015 17:03:47 +0800 Subject: [PATCH 7/9] Simplify the code --- atom/browser/ui/message_box_gtk.cc | 43 ++++++++++++++---------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/atom/browser/ui/message_box_gtk.cc b/atom/browser/ui/message_box_gtk.cc index a7c50eae6c7b..4a78398b0fa3 100644 --- a/atom/browser/ui/message_box_gtk.cc +++ b/atom/browser/ui/message_box_gtk.cc @@ -26,8 +26,7 @@ namespace { class GtkMessageBox { public: - GtkMessageBox(bool modal, - NativeWindow* parent_window, + GtkMessageBox(NativeWindow* parent_window, MessageBoxType type, const std::vector& buttons, const std::string& title, @@ -39,8 +38,7 @@ class GtkMessageBox { // Create dialog. dialog_ = gtk_message_dialog_new( nullptr, // parent - modal ? GTK_DIALOG_MODAL : // modal dialog - static_cast(0), // no flags + static_cast(0), // no flags GetMessageType(type), // type GTK_BUTTONS_NONE, // no buttons "%s", message.c_str()); @@ -115,6 +113,16 @@ class GtkMessageBox { gtk_window_present_with_time(GTK_WINDOW(dialog_), time); } + int RunSynchronous() { + gtk_window_set_modal(GTK_WINDOW(dialog_), TRUE); + Show(); + int response = gtk_dialog_run(GTK_DIALOG(dialog_)); + if (response < 0) + return cancel_id_; + else + return response; + } + void RunAsynchronous(const MessageBoxCallback& callback) { callback_ = callback; g_signal_connect(dialog_, "delete-event", @@ -126,9 +134,6 @@ class GtkMessageBox { CHROMEGTK_CALLBACK_1(GtkMessageBox, void, OnResponseDialog, int); - GtkWidget* dialog() const { return dialog_; } - int cancel_id() const { return cancel_id_; } - private: atom::NativeWindow::DialogScope dialog_scope_; @@ -160,13 +165,8 @@ int ShowMessageBox(NativeWindow* parent, const std::string& message, const std::string& detail, const gfx::ImageSkia& icon) { - GtkMessageBox box(true, parent, type, buttons, title, message, detail, icon); - box.Show(); - int response = gtk_dialog_run(GTK_DIALOG(box.dialog())); - if (response < 0) - return box.cancel_id(); - else - return response; + return GtkMessageBox(parent, type, buttons, title, message, detail, + icon).RunSynchronous(); } void ShowMessageBox(NativeWindow* parent, @@ -177,19 +177,16 @@ void ShowMessageBox(NativeWindow* parent, const std::string& detail, const gfx::ImageSkia& icon, const MessageBoxCallback& callback) { - auto box = new GtkMessageBox( - false, parent, type, buttons, title, message, detail, icon); - box->RunAsynchronous(callback); + (new GtkMessageBox(parent, type, buttons, title, message, detail, + icon))->RunAsynchronous(callback); } void ShowErrorBox(const base::string16& title, const base::string16& content) { if (Browser::Get()->is_ready()) { - GtkMessageBox box(true, nullptr, MESSAGE_BOX_TYPE_ERROR, { "OK" }, "Error", - base::UTF16ToUTF8(title).c_str(), - base::UTF16ToUTF8(content).c_str(), - gfx::ImageSkia()); - box.Show(); - gtk_dialog_run(GTK_DIALOG(box.dialog())); + GtkMessageBox(nullptr, MESSAGE_BOX_TYPE_ERROR, { "OK" }, "Error", + base::UTF16ToUTF8(title).c_str(), + base::UTF16ToUTF8(content).c_str(), + gfx::ImageSkia()).RunSynchronous(); } else { fprintf(stderr, ANSI_TEXT_BOLD ANSI_BACKGROUND_GRAY From 9b25c16980c659e8ea5a99c9416287388c6f86cd Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 7 Jul 2015 17:08:30 +0800 Subject: [PATCH 8/9] Allow "detail" to be empty --- atom/browser/ui/message_box_gtk.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/atom/browser/ui/message_box_gtk.cc b/atom/browser/ui/message_box_gtk.cc index 4a78398b0fa3..09bff182a168 100644 --- a/atom/browser/ui/message_box_gtk.cc +++ b/atom/browser/ui/message_box_gtk.cc @@ -42,9 +42,9 @@ class GtkMessageBox { GetMessageType(type), // type GTK_BUTTONS_NONE, // no buttons "%s", message.c_str()); - gtk_message_dialog_format_secondary_text( - GTK_MESSAGE_DIALOG(dialog_), - "%s", detail.empty() ? nullptr : detail.c_str()); + if (!detail.empty()) + gtk_message_dialog_format_secondary_text( + GTK_MESSAGE_DIALOG(dialog_), "%s", detail.c_str()); // Set dialog's icon. if (!icon.isNull()) { From a2d1ec2c1f160bfd42be36f414a049738e6b9493 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 7 Jul 2015 17:09:58 +0800 Subject: [PATCH 9/9] Make "title" work --- atom/browser/ui/message_box_gtk.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/atom/browser/ui/message_box_gtk.cc b/atom/browser/ui/message_box_gtk.cc index 09bff182a168..626f16704dde 100644 --- a/atom/browser/ui/message_box_gtk.cc +++ b/atom/browser/ui/message_box_gtk.cc @@ -45,6 +45,8 @@ class GtkMessageBox { if (!detail.empty()) gtk_message_dialog_format_secondary_text( GTK_MESSAGE_DIALOG(dialog_), "%s", detail.c_str()); + if (!title.empty()) + gtk_window_set_title(GTK_WINDOW(dialog_), title.c_str()); // Set dialog's icon. if (!icon.isNull()) {