feat: add signal option to dialog.showMessageBox (#26102)

* mac: add dialog.closeMessageBox API

* win: Implement dialog.closeMessageBox

* mac: Return cancelId with closeMessageBox

* gtk: Implement dialog.closeMessageBox

* win: Fix 32bit build

* win: Reduce the scope of lock

* fix: Build error after rebase

* feat: Use AbortSignal to close message box

* chore: silently handle duplicate ID

* win: Add more notes about the threads

* chore: apply reviews

* fix: base::NoDestructor should be warpped in function

* chore: fix style on windows
This commit is contained in:
Cheng Zhao 2021-07-15 07:59:27 +09:00 committed by GitHub
parent 4b780f9770
commit 05ba6359d0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 276 additions and 24 deletions

View file

@ -2,15 +2,19 @@
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "shell/browser/ui/gtk_util.h"
#include "shell/browser/ui/message_box.h"
#include <map>
#include "base/callback.h"
#include "base/containers/contains.h"
#include "base/no_destructor.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "shell/browser/browser.h"
#include "shell/browser/native_window_observer.h"
#include "shell/browser/native_window_views.h"
#include "shell/browser/ui/gtk_util.h"
#include "shell/browser/unresponsive_suppressor.h"
#include "ui/base/glib/glib_signal.h"
#include "ui/gfx/image/image_skia.h"
@ -38,10 +42,17 @@ MessageBoxSettings::~MessageBoxSettings() = default;
namespace {
// <ID, messageBox> map
std::map<int, GtkWidget*>& GetDialogsMap() {
static base::NoDestructor<std::map<int, GtkWidget*>> dialogs;
return *dialogs;
}
class GtkMessageBox : public NativeWindowObserver {
public:
explicit GtkMessageBox(const MessageBoxSettings& settings)
: cancel_id_(settings.cancel_id),
: id_(settings.id),
cancel_id_(settings.cancel_id),
parent_(static_cast<NativeWindow*>(settings.parent_window)) {
// Create dialog.
dialog_ =
@ -50,6 +61,8 @@ class GtkMessageBox : public NativeWindowObserver {
GetMessageType(settings.type), // type
GTK_BUTTONS_NONE, // no buttons
"%s", settings.message.c_str());
if (id_)
GetDialogsMap()[*id_] = dialog_;
if (!settings.detail.empty())
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog_),
"%s", settings.detail.c_str());
@ -183,6 +196,9 @@ class GtkMessageBox : public NativeWindowObserver {
private:
electron::UnresponsiveSuppressor unresponsive_suppressor_;
// The id of the dialog.
absl::optional<int> id_;
// The id to return when the dialog is closed without pressing buttons.
int cancel_id_ = 0;
@ -196,6 +212,8 @@ class GtkMessageBox : public NativeWindowObserver {
};
void GtkMessageBox::OnResponseDialog(GtkWidget* widget, int response) {
if (id_)
GetDialogsMap().erase(*id_);
gtk_widget_hide(dialog_);
if (response < 0)
@ -217,9 +235,20 @@ int ShowMessageBoxSync(const MessageBoxSettings& settings) {
void ShowMessageBox(const MessageBoxSettings& settings,
MessageBoxCallback callback) {
if (settings.id && base::Contains(GetDialogsMap(), *settings.id))
CloseMessageBox(*settings.id);
(new GtkMessageBox(settings))->RunAsynchronous(std::move(callback));
}
void CloseMessageBox(int id) {
auto it = GetDialogsMap().find(id);
if (it == GetDialogsMap().end()) {
LOG(ERROR) << "CloseMessageBox called with nonexistent ID";
return;
}
gtk_window_close(GTK_WINDOW(it->second));
}
void ShowErrorBox(const std::u16string& title, const std::u16string& content) {
if (Browser::Get()->is_ready()) {
electron::MessageBoxSettings settings;