mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
feat: improve Windows Toast actions support (#48132)
* feat: improve Windows Toast actions support * fix: ensure MSIX compatibility * test: add bad clsid format test
This commit is contained in:
@@ -88,6 +88,7 @@
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "shell/browser/notifications/win/windows_toast_activator.h"
|
||||
#include "shell/browser/ui/win/jump_list.h"
|
||||
#endif
|
||||
|
||||
@@ -1840,6 +1841,10 @@ gin::ObjectTemplateBuilder App::GetObjectTemplateBuilder(v8::Isolate* isolate) {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
.SetMethod("setAppUserModelId",
|
||||
base::BindRepeating(&Browser::SetAppUserModelID, browser))
|
||||
.SetMethod("setToastActivatorCLSID",
|
||||
base::BindRepeating(&App::SetToastActivatorCLSID,
|
||||
base::Unretained(this)))
|
||||
.SetProperty("toastActivatorCLSID", &App::GetToastActivatorCLSID)
|
||||
#endif
|
||||
.SetMethod(
|
||||
"isDefaultProtocolClient",
|
||||
@@ -1967,6 +1972,34 @@ gin::ObjectTemplateBuilder App::GetObjectTemplateBuilder(v8::Isolate* isolate) {
|
||||
.SetMethod("resolveProxy", &App::ResolveProxy);
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
void App::SetToastActivatorCLSID(gin_helper::ErrorThrower thrower,
|
||||
const std::string& id) {
|
||||
std::wstring wide = base::UTF8ToWide(id);
|
||||
CLSID parsed;
|
||||
if (FAILED(::CLSIDFromString(wide.c_str(), &parsed))) {
|
||||
if (!wide.empty() && wide.front() != L'{') {
|
||||
std::wstring with_braces = L"{" + wide + L"}";
|
||||
if (FAILED(::CLSIDFromString(with_braces.c_str(), &parsed))) {
|
||||
thrower.ThrowError("Invalid CLSID format");
|
||||
return;
|
||||
}
|
||||
wide = std::move(with_braces);
|
||||
} else {
|
||||
thrower.ThrowError("Invalid CLSID format");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SetAppToastActivatorCLSID(wide);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> App::GetToastActivatorCLSID(v8::Isolate* isolate) {
|
||||
return gin::ConvertToV8(isolate,
|
||||
base::WideToUTF8(GetAppToastActivatorCLSID()));
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* App::GetHumanReadableName() const {
|
||||
return "Electron / App";
|
||||
}
|
||||
|
||||
@@ -265,6 +265,12 @@ class App final : public gin::Wrappable<App>,
|
||||
|
||||
// Set or remove a custom Jump List for the application.
|
||||
JumpListResult SetJumpList(v8::Isolate* isolate, v8::Local<v8::Value> val);
|
||||
|
||||
// Set the toast activator CLSID.
|
||||
void SetToastActivatorCLSID(gin_helper::ErrorThrower thrower,
|
||||
const std::string& id);
|
||||
// Get the toast activator CLSID.
|
||||
v8::Local<v8::Value> GetToastActivatorCLSID(v8::Isolate* isolate);
|
||||
#endif // BUILDFLAG(IS_WIN)
|
||||
|
||||
std::unique_ptr<ProcessSingleton> process_singleton_;
|
||||
|
||||
@@ -31,6 +31,9 @@ struct Converter<electron::NotificationAction> {
|
||||
return false;
|
||||
}
|
||||
dict.Get("text", &(out->text));
|
||||
std::vector<std::u16string> items;
|
||||
if (dict.Get("items", &items))
|
||||
out->items = std::move(items);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -39,6 +42,9 @@ struct Converter<electron::NotificationAction> {
|
||||
auto dict = gin::Dictionary::CreateEmpty(isolate);
|
||||
dict.Set("text", val.text);
|
||||
dict.Set("type", val.type);
|
||||
if (!val.items.empty()) {
|
||||
dict.Set("items", val.items);
|
||||
}
|
||||
return ConvertToV8(isolate, dict);
|
||||
}
|
||||
};
|
||||
@@ -138,8 +144,20 @@ void Notification::SetToastXml(const std::u16string& new_toast_xml) {
|
||||
toast_xml_ = new_toast_xml;
|
||||
}
|
||||
|
||||
void Notification::NotificationAction(int index) {
|
||||
Emit("action", index);
|
||||
void Notification::NotificationAction(int action_index, int selection_index) {
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
gin_helper::internal::Event* event =
|
||||
gin_helper::internal::Event::New(isolate);
|
||||
v8::Local<v8::Object> event_object =
|
||||
event->GetWrapper(isolate).ToLocalChecked();
|
||||
|
||||
gin_helper::Dictionary dict(isolate, event_object);
|
||||
dict.Set("selectionIndex", selection_index);
|
||||
dict.Set("actionIndex", action_index);
|
||||
|
||||
EmitWithoutEvent("action", event_object, action_index, selection_index);
|
||||
}
|
||||
|
||||
void Notification::NotificationClick() {
|
||||
@@ -147,7 +165,18 @@ void Notification::NotificationClick() {
|
||||
}
|
||||
|
||||
void Notification::NotificationReplied(const std::string& reply) {
|
||||
Emit("reply", reply);
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
gin_helper::internal::Event* event =
|
||||
gin_helper::internal::Event::New(isolate);
|
||||
v8::Local<v8::Object> event_object =
|
||||
event->GetWrapper(isolate).ToLocalChecked();
|
||||
|
||||
gin_helper::Dictionary dict(isolate, event_object);
|
||||
dict.Set("reply", reply);
|
||||
|
||||
EmitWithoutEvent("reply", event_object, reply);
|
||||
}
|
||||
|
||||
void Notification::NotificationDisplayed() {
|
||||
|
||||
@@ -45,7 +45,7 @@ class Notification final : public gin_helper::DeprecatedWrappable<Notification>,
|
||||
static const char* GetClassName() { return "Notification"; }
|
||||
|
||||
// NotificationDelegate:
|
||||
void NotificationAction(int index) override;
|
||||
void NotificationAction(int action_index, int selection_index) override;
|
||||
void NotificationClick() override;
|
||||
void NotificationReplied(const std::string& reply) override;
|
||||
void NotificationDisplayed() override;
|
||||
|
||||
Reference in New Issue
Block a user