refactor: ginify Menu (#22916)
This commit is contained in:
parent
1d158399a6
commit
6159066c26
14 changed files with 241 additions and 150 deletions
|
@ -10,43 +10,51 @@ const { Menu } = bindings;
|
|||
let applicationMenu = null;
|
||||
let groupIdIndex = 0;
|
||||
|
||||
Object.setPrototypeOf(Menu.prototype, EventEmitter.prototype);
|
||||
|
||||
// Menu Delegate.
|
||||
// This object should hold no reference to |Menu| to avoid cyclic reference.
|
||||
const delegate = {
|
||||
isCommandIdChecked: (menu, id) => menu.commandsMap[id] ? menu.commandsMap[id].checked : undefined,
|
||||
isCommandIdEnabled: (menu, id) => menu.commandsMap[id] ? menu.commandsMap[id].enabled : undefined,
|
||||
shouldCommandIdWorkWhenHidden: (menu, id) => menu.commandsMap[id] ? menu.commandsMap[id].acceleratorWorksWhenHidden : undefined,
|
||||
isCommandIdVisible: (menu, id) => menu.commandsMap[id] ? menu.commandsMap[id].visible : undefined,
|
||||
getAcceleratorForCommandId: (menu, id, useDefaultAccelerator) => {
|
||||
const command = menu.commandsMap[id];
|
||||
if (!command) return;
|
||||
if (command.accelerator != null) return command.accelerator;
|
||||
if (useDefaultAccelerator) return command.getDefaultRoleAccelerator();
|
||||
},
|
||||
shouldRegisterAcceleratorForCommandId: (menu, id) => menu.commandsMap[id] ? menu.commandsMap[id].registerAccelerator : undefined,
|
||||
executeCommand: (menu, event, id) => {
|
||||
const command = menu.commandsMap[id];
|
||||
if (!command) return;
|
||||
command.click(event, TopLevelWindow.getFocusedWindow(), webContents.getFocusedWebContents());
|
||||
},
|
||||
menuWillShow: (menu) => {
|
||||
// Ensure radio groups have at least one menu item selected
|
||||
for (const id of Object.keys(menu.groupsMap)) {
|
||||
const found = menu.groupsMap[id].find(item => item.checked) || null;
|
||||
if (!found) v8Util.setHiddenValue(menu.groupsMap[id][0], 'checked', true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Instance Methods */
|
||||
|
||||
Menu.prototype._init = function () {
|
||||
this.commandsMap = {};
|
||||
this.groupsMap = {};
|
||||
this.items = [];
|
||||
this.delegate = delegate;
|
||||
};
|
||||
|
||||
Menu.prototype._isCommandIdChecked = function (id) {
|
||||
return this.commandsMap[id] ? this.commandsMap[id].checked : undefined;
|
||||
};
|
||||
|
||||
Menu.prototype._isCommandIdEnabled = function (id) {
|
||||
return this.commandsMap[id] ? this.commandsMap[id].enabled : undefined;
|
||||
};
|
||||
Menu.prototype._shouldCommandIdWorkWhenHidden = function (id) {
|
||||
return this.commandsMap[id] ? this.commandsMap[id].acceleratorWorksWhenHidden : undefined;
|
||||
};
|
||||
Menu.prototype._isCommandIdVisible = function (id) {
|
||||
return this.commandsMap[id] ? this.commandsMap[id].visible : undefined;
|
||||
};
|
||||
|
||||
Menu.prototype._getAcceleratorForCommandId = function (id, useDefaultAccelerator) {
|
||||
const command = this.commandsMap[id];
|
||||
if (!command) return;
|
||||
if (command.accelerator != null) return command.accelerator;
|
||||
if (useDefaultAccelerator) return command.getDefaultRoleAccelerator();
|
||||
};
|
||||
|
||||
Menu.prototype._shouldRegisterAcceleratorForCommandId = function (id) {
|
||||
return this.commandsMap[id] ? this.commandsMap[id].registerAccelerator : undefined;
|
||||
};
|
||||
|
||||
Menu.prototype._executeCommand = function (event, id) {
|
||||
const command = this.commandsMap[id];
|
||||
if (!command) return;
|
||||
command.click(event, TopLevelWindow.getFocusedWindow(), webContents.getFocusedWebContents());
|
||||
};
|
||||
|
||||
Menu.prototype._menuWillShow = function () {
|
||||
// Ensure radio groups have at least one menu item selected
|
||||
for (const id of Object.keys(this.groupsMap)) {
|
||||
const found = this.groupsMap[id].find(item => item.checked) || null;
|
||||
if (!found) v8Util.setHiddenValue(this.groupsMap[id][0], 'checked', true);
|
||||
}
|
||||
};
|
||||
|
||||
Menu.prototype.popup = function (options = {}) {
|
||||
|
|
|
@ -93,4 +93,5 @@ gpu_notify_when_dxdiag_request_fails.patch
|
|||
feat_allow_embedders_to_add_observers_on_created_hunspell.patch
|
||||
feat_add_onclose_to_messageport.patch
|
||||
gin_allow_passing_an_objecttemplate_to_objecttemplatebuilder.patch
|
||||
gin_forward_args_when_dispatching.patch
|
||||
fix_undo_redo_broken_in_webviews.patch
|
||||
|
|
94
patches/chromium/gin_forward_args_when_dispatching.patch
Normal file
94
patches/chromium/gin_forward_args_when_dispatching.patch
Normal file
|
@ -0,0 +1,94 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jeremy Apthorp <jeremya@chromium.org>
|
||||
Date: Wed, 1 Apr 2020 01:06:45 +0000
|
||||
Subject: gin: forward args when dispatching
|
||||
|
||||
This allows passing arguments with move-only semantics.
|
||||
|
||||
Change-Id: I852eb343398e6f763abfe2a44e623f28353d79a5
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2129029
|
||||
Commit-Queue: Jeremy Apthorp <jeremya@chromium.org>
|
||||
Reviewed-by: Jeremy Roman <jbroman@chromium.org>
|
||||
Auto-Submit: Jeremy Apthorp <jeremya@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/master@{#755196}
|
||||
|
||||
diff --git a/gin/converter_unittest.cc b/gin/converter_unittest.cc
|
||||
index 6f9205f06a3e4747e70149c440c4548e54045001..162572385bdd8a54612eb64414fe80e0f9d619d1 100644
|
||||
--- a/gin/converter_unittest.cc
|
||||
+++ b/gin/converter_unittest.cc
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "base/stl_util.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
+#include "gin/function_template.h"
|
||||
#include "gin/handle.h"
|
||||
#include "gin/public/isolate_holder.h"
|
||||
#include "gin/test/v8_test.h"
|
||||
@@ -224,4 +225,45 @@ TEST_F(ConverterTest, VectorOfWrappables) {
|
||||
EXPECT_THAT(out_value2, testing::ContainerEq(vector));
|
||||
}
|
||||
|
||||
+namespace {
|
||||
+
|
||||
+class MoveOnlyObject {
|
||||
+ public:
|
||||
+ MoveOnlyObject() = default;
|
||||
+ MoveOnlyObject(const MoveOnlyObject&) = delete;
|
||||
+ MoveOnlyObject& operator=(const MoveOnlyObject&) = delete;
|
||||
+
|
||||
+ MoveOnlyObject(MoveOnlyObject&&) noexcept = default;
|
||||
+ MoveOnlyObject& operator=(MoveOnlyObject&&) noexcept = default;
|
||||
+};
|
||||
+
|
||||
+} // namespace
|
||||
+
|
||||
+template <>
|
||||
+struct Converter<MoveOnlyObject> {
|
||||
+ static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, MoveOnlyObject in) {
|
||||
+ return v8::Undefined(isolate);
|
||||
+ }
|
||||
+ static bool FromV8(v8::Isolate* isolate,
|
||||
+ v8::Local<v8::Value> val,
|
||||
+ MoveOnlyObject* out) {
|
||||
+ *out = MoveOnlyObject();
|
||||
+ return true;
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+TEST_F(ConverterTest, MoveOnlyParameters) {
|
||||
+ v8::Isolate* isolate = instance_->isolate();
|
||||
+ v8::HandleScope handle_scope(isolate);
|
||||
+
|
||||
+ auto receives_move_only_obj = [](MoveOnlyObject obj) {};
|
||||
+ auto func_templ = gin::CreateFunctionTemplate(
|
||||
+ isolate, base::BindRepeating(receives_move_only_obj));
|
||||
+
|
||||
+ v8::Local<v8::Context> context = instance_->isolate()->GetCurrentContext();
|
||||
+ auto func = func_templ->GetFunction(context).ToLocalChecked();
|
||||
+ v8::Local<v8::Value> argv[] = {v8::Undefined(isolate)};
|
||||
+ func->Call(context, v8::Undefined(isolate), 1, argv).ToLocalChecked();
|
||||
+}
|
||||
+
|
||||
} // namespace gin
|
||||
diff --git a/gin/function_template.h b/gin/function_template.h
|
||||
index 7edcc9e20dfa6367dde5f58237cca5f4ca637f7a..8c641d934fdeebb9a90f6eb49960e4fe06217913 100644
|
||||
--- a/gin/function_template.h
|
||||
+++ b/gin/function_template.h
|
||||
@@ -166,14 +166,15 @@ class Invoker<std::index_sequence<indices...>, ArgTypes...>
|
||||
template <typename ReturnType>
|
||||
void DispatchToCallback(
|
||||
base::RepeatingCallback<ReturnType(ArgTypes...)> callback) {
|
||||
- args_->Return(callback.Run(ArgumentHolder<indices, ArgTypes>::value...));
|
||||
+ args_->Return(
|
||||
+ callback.Run(std::move(ArgumentHolder<indices, ArgTypes>::value)...));
|
||||
}
|
||||
|
||||
// In C++, you can declare the function foo(void), but you can't pass a void
|
||||
// expression to foo. As a result, we must specialize the case of Callbacks
|
||||
// that have the void return type.
|
||||
void DispatchToCallback(base::RepeatingCallback<void(ArgTypes...)> callback) {
|
||||
- callback.Run(ArgumentHolder<indices, ArgTypes>::value...);
|
||||
+ callback.Run(std::move(ArgumentHolder<indices, ArgTypes>::value)...);
|
||||
}
|
||||
|
||||
private:
|
|
@ -155,6 +155,9 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
|
|||
// |media_list_sources|.
|
||||
if (!webrtc::DxgiDuplicatorController::Instance()->GetDeviceNames(
|
||||
&device_names)) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope scope(isolate);
|
||||
gin_helper::CallMethod(this, "_onerror", "Failed to get sources.");
|
||||
return;
|
||||
}
|
||||
|
@ -184,9 +187,13 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
|
|||
std::back_inserter(captured_sources_));
|
||||
}
|
||||
|
||||
if (!capture_window_ && !capture_screen_)
|
||||
if (!capture_window_ && !capture_screen_) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope scope(isolate);
|
||||
gin_helper::CallMethod(this, "_onfinished", captured_sources_,
|
||||
fetch_window_icons_);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
@ -16,21 +16,13 @@
|
|||
#include "shell/common/gin_helper/object_template_builder.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// We need this map to keep references to currently opened menus.
|
||||
// Without this menus would be destroyed by js garbage collector
|
||||
// even when they are still displayed.
|
||||
std::map<uint32_t, v8::Global<v8::Object>> g_menus;
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace api {
|
||||
|
||||
gin::WrapperInfo Menu::kWrapperInfo = {gin::kEmbedderNativeGin};
|
||||
|
||||
Menu::Menu(gin::Arguments* args) : model_(new ElectronMenuModel(this)) {
|
||||
InitWithArgs(args);
|
||||
model_->AddObserver(this);
|
||||
}
|
||||
|
||||
|
@ -40,74 +32,82 @@ Menu::~Menu() {
|
|||
}
|
||||
}
|
||||
|
||||
void Menu::AfterInit(v8::Isolate* isolate) {
|
||||
gin::Dictionary wrappable(isolate, GetWrapper());
|
||||
gin::Dictionary delegate(nullptr);
|
||||
if (!wrappable.Get("delegate", &delegate))
|
||||
return;
|
||||
|
||||
delegate.Get("isCommandIdChecked", &is_checked_);
|
||||
delegate.Get("isCommandIdEnabled", &is_enabled_);
|
||||
delegate.Get("isCommandIdVisible", &is_visible_);
|
||||
delegate.Get("shouldCommandIdWorkWhenHidden", &works_when_hidden_);
|
||||
delegate.Get("getAcceleratorForCommandId", &get_accelerator_);
|
||||
delegate.Get("shouldRegisterAcceleratorForCommandId",
|
||||
&should_register_accelerator_);
|
||||
delegate.Get("executeCommand", &execute_command_);
|
||||
delegate.Get("menuWillShow", &menu_will_show_);
|
||||
bool InvokeBoolMethod(const Menu* menu,
|
||||
const char* method,
|
||||
int command_id,
|
||||
bool default_value = false) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
// We need to cast off const here because GetWrapper() is non-const, but
|
||||
// ui::SimpleMenuModel::Delegate's methods are const.
|
||||
v8::Local<v8::Value> val = gin_helper::CallMethod(
|
||||
isolate, const_cast<Menu*>(menu), method, command_id);
|
||||
bool ret = false;
|
||||
return gin::ConvertFromV8(isolate, val, &ret) ? ret : default_value;
|
||||
}
|
||||
|
||||
bool Menu::IsCommandIdChecked(int command_id) const {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
return is_checked_.Run(GetWrapper(), command_id);
|
||||
return InvokeBoolMethod(this, "_isCommandIdChecked", command_id);
|
||||
}
|
||||
|
||||
bool Menu::IsCommandIdEnabled(int command_id) const {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
return is_enabled_.Run(GetWrapper(), command_id);
|
||||
return InvokeBoolMethod(this, "_isCommandIdEnabled", command_id);
|
||||
}
|
||||
|
||||
bool Menu::IsCommandIdVisible(int command_id) const {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
return is_visible_.Run(GetWrapper(), command_id);
|
||||
return InvokeBoolMethod(this, "_isCommandIdVisible", command_id);
|
||||
}
|
||||
|
||||
bool Menu::ShouldCommandIdWorkWhenHidden(int command_id) const {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
return works_when_hidden_.Run(GetWrapper(), command_id);
|
||||
return InvokeBoolMethod(this, "_shouldCommandIdWorkWhenHidden", command_id);
|
||||
}
|
||||
|
||||
bool Menu::GetAcceleratorForCommandIdWithParams(
|
||||
int command_id,
|
||||
bool use_default_accelerator,
|
||||
ui::Accelerator* accelerator) const {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
v8::Local<v8::Value> val =
|
||||
get_accelerator_.Run(GetWrapper(), command_id, use_default_accelerator);
|
||||
return gin::ConvertFromV8(isolate(), val, accelerator);
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
v8::Local<v8::Value> val = gin_helper::CallMethod(
|
||||
isolate, const_cast<Menu*>(this), "_getAcceleratorForCommandId",
|
||||
command_id, use_default_accelerator);
|
||||
return gin::ConvertFromV8(isolate, val, accelerator);
|
||||
}
|
||||
|
||||
bool Menu::ShouldRegisterAcceleratorForCommandId(int command_id) const {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
return should_register_accelerator_.Run(GetWrapper(), command_id);
|
||||
return InvokeBoolMethod(this, "_shouldRegisterAcceleratorForCommandId",
|
||||
command_id);
|
||||
}
|
||||
|
||||
void Menu::ExecuteCommand(int command_id, int flags) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
execute_command_.Run(GetWrapper(), CreateEventFromFlags(flags), command_id);
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
gin_helper::CallMethod(isolate, const_cast<Menu*>(this), "_executeCommand",
|
||||
CreateEventFromFlags(flags), command_id);
|
||||
}
|
||||
|
||||
void Menu::OnMenuWillShow(ui::SimpleMenuModel* source) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
menu_will_show_.Run(GetWrapper());
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
gin_helper::CallMethod(isolate, const_cast<Menu*>(this), "_menuWillShow");
|
||||
}
|
||||
|
||||
base::OnceClosure Menu::BindSelfToClosure(base::OnceClosure callback) {
|
||||
// return ((callback, ref) => { callback() }).bind(null, callback, this)
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope scope(isolate);
|
||||
v8::Local<v8::Object> self;
|
||||
if (GetWrapper(isolate).ToLocal(&self)) {
|
||||
v8::Global<v8::Value> ref(isolate, self);
|
||||
return base::BindOnce(
|
||||
[](base::OnceClosure callback, v8::Global<v8::Value> ref) {
|
||||
std::move(callback).Run();
|
||||
},
|
||||
std::move(callback), std::move(ref));
|
||||
} else {
|
||||
return base::DoNothing();
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::InsertItemAt(int index,
|
||||
|
@ -208,32 +208,20 @@ bool Menu::WorksWhenHiddenAt(int index) const {
|
|||
}
|
||||
|
||||
void Menu::OnMenuWillClose() {
|
||||
g_menus.erase(weak_map_id());
|
||||
Unpin();
|
||||
Emit("menu-will-close");
|
||||
}
|
||||
|
||||
void Menu::OnMenuWillShow() {
|
||||
v8::HandleScope scope(isolate());
|
||||
g_menus[weak_map_id()] = v8::Global<v8::Object>(isolate(), GetWrapper());
|
||||
Pin(v8::Isolate::GetCurrent());
|
||||
Emit("menu-will-show");
|
||||
}
|
||||
|
||||
base::OnceClosure Menu::BindSelfToClosure(base::OnceClosure callback) {
|
||||
// return ((callback, ref) => { callback() }).bind(null, callback, this)
|
||||
v8::Global<v8::Value> ref(isolate(), GetWrapper());
|
||||
return base::BindOnce(
|
||||
[](base::OnceClosure callback, v8::Global<v8::Value> ref) {
|
||||
std::move(callback).Run();
|
||||
},
|
||||
std::move(callback), std::move(ref));
|
||||
}
|
||||
|
||||
// static
|
||||
void Menu::BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::FunctionTemplate> prototype) {
|
||||
prototype->SetClassName(gin::StringToV8(isolate, "Menu"));
|
||||
gin_helper::Destroyable::MakeDestroyable(isolate, prototype);
|
||||
gin_helper::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
|
||||
v8::Local<v8::ObjectTemplate> Menu::FillObjectTemplate(
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::ObjectTemplate> templ) {
|
||||
return gin::ObjectTemplateBuilder(isolate, "Menu", templ)
|
||||
.SetMethod("insertItem", &Menu::InsertItemAt)
|
||||
.SetMethod("insertCheckItem", &Menu::InsertCheckItemAt)
|
||||
.SetMethod("insertRadioItem", &Menu::InsertRadioItemAt)
|
||||
|
@ -256,7 +244,8 @@ void Menu::BuildPrototype(v8::Isolate* isolate,
|
|||
.SetMethod("worksWhenHiddenAt", &Menu::WorksWhenHiddenAt)
|
||||
.SetMethod("isVisibleAt", &Menu::IsVisibleAt)
|
||||
.SetMethod("popupAt", &Menu::PopupAt)
|
||||
.SetMethod("closePopupAt", &Menu::ClosePopupAt);
|
||||
.SetMethod("closePopupAt", &Menu::ClosePopupAt)
|
||||
.Build();
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
@ -272,12 +261,9 @@ void Initialize(v8::Local<v8::Object> exports,
|
|||
v8::Local<v8::Context> context,
|
||||
void* priv) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
Menu::SetConstructor(isolate, base::BindRepeating(&Menu::New));
|
||||
|
||||
gin_helper::Dictionary dict(isolate, exports);
|
||||
dict.Set(
|
||||
"Menu",
|
||||
Menu::GetConstructor(isolate)->GetFunction(context).ToLocalChecked());
|
||||
dict.Set("Menu", Menu::GetConstructor(context));
|
||||
#if defined(OS_MACOSX)
|
||||
dict.SetMethod("setApplicationMenu", &Menu::SetApplicationMenu);
|
||||
dict.SetMethod("sendActionToFirstResponder",
|
||||
|
|
|
@ -11,21 +11,30 @@
|
|||
#include "base/callback.h"
|
||||
#include "gin/arguments.h"
|
||||
#include "shell/browser/api/electron_api_top_level_window.h"
|
||||
#include "shell/browser/event_emitter_mixin.h"
|
||||
#include "shell/browser/ui/electron_menu_model.h"
|
||||
#include "shell/common/gin_helper/trackable_object.h"
|
||||
#include "shell/common/gin_helper/constructible.h"
|
||||
#include "shell/common/gin_helper/pinnable.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace api {
|
||||
|
||||
class Menu : public gin_helper::TrackableObject<Menu>,
|
||||
class Menu : public gin::Wrappable<Menu>,
|
||||
public gin_helper::EventEmitterMixin<Menu>,
|
||||
public gin_helper::Constructible<Menu>,
|
||||
public gin_helper::Pinnable<Menu>,
|
||||
public ElectronMenuModel::Delegate,
|
||||
public ElectronMenuModel::Observer {
|
||||
public:
|
||||
static gin_helper::WrappableBase* New(gin::Arguments* args);
|
||||
// gin_helper::Constructible
|
||||
static gin::Handle<Menu> New(gin::Arguments* args);
|
||||
static v8::Local<v8::ObjectTemplate> FillObjectTemplate(
|
||||
v8::Isolate*,
|
||||
v8::Local<v8::ObjectTemplate>);
|
||||
|
||||
static void BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::FunctionTemplate> prototype);
|
||||
// gin::Wrappable
|
||||
static gin::WrapperInfo kWrapperInfo;
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
// Set the global menubar.
|
||||
|
@ -41,8 +50,9 @@ class Menu : public gin_helper::TrackableObject<Menu>,
|
|||
explicit Menu(gin::Arguments* args);
|
||||
~Menu() override;
|
||||
|
||||
// gin_helper::Wrappable:
|
||||
void AfterInit(v8::Isolate* isolate) override;
|
||||
// Returns a new callback which keeps references of the JS wrapper until the
|
||||
// passed |callback| is called.
|
||||
base::OnceClosure BindSelfToClosure(base::OnceClosure callback);
|
||||
|
||||
// ui::SimpleMenuModel::Delegate:
|
||||
bool IsCommandIdChecked(int command_id) const override;
|
||||
|
@ -71,11 +81,6 @@ class Menu : public gin_helper::TrackableObject<Menu>,
|
|||
void OnMenuWillClose() override;
|
||||
void OnMenuWillShow() override;
|
||||
|
||||
protected:
|
||||
// Returns a new callback which keeps references of the JS wrapper until the
|
||||
// passed |callback| is called.
|
||||
base::OnceClosure BindSelfToClosure(base::OnceClosure callback);
|
||||
|
||||
private:
|
||||
void InsertItemAt(int index, int command_id, const base::string16& label);
|
||||
void InsertSeparatorAt(int index);
|
||||
|
@ -107,19 +112,6 @@ class Menu : public gin_helper::TrackableObject<Menu>,
|
|||
bool IsVisibleAt(int index) const;
|
||||
bool WorksWhenHiddenAt(int index) const;
|
||||
|
||||
// Stored delegate methods.
|
||||
base::RepeatingCallback<bool(v8::Local<v8::Value>, int)> is_checked_;
|
||||
base::RepeatingCallback<bool(v8::Local<v8::Value>, int)> is_enabled_;
|
||||
base::RepeatingCallback<bool(v8::Local<v8::Value>, int)> is_visible_;
|
||||
base::RepeatingCallback<bool(v8::Local<v8::Value>, int)> works_when_hidden_;
|
||||
base::RepeatingCallback<v8::Local<v8::Value>(v8::Local<v8::Value>, int, bool)>
|
||||
get_accelerator_;
|
||||
base::RepeatingCallback<bool(v8::Local<v8::Value>, int)>
|
||||
should_register_accelerator_;
|
||||
base::RepeatingCallback<void(v8::Local<v8::Value>, v8::Local<v8::Value>, int)>
|
||||
execute_command_;
|
||||
base::RepeatingCallback<void(v8::Local<v8::Value>)> menu_will_show_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Menu);
|
||||
};
|
||||
|
||||
|
|
|
@ -177,8 +177,11 @@ void Menu::SendActionToFirstResponder(const std::string& action) {
|
|||
}
|
||||
|
||||
// static
|
||||
gin_helper::WrappableBase* Menu::New(gin::Arguments* args) {
|
||||
return new MenuMac(args);
|
||||
gin::Handle<Menu> Menu::New(gin::Arguments* args) {
|
||||
auto handle =
|
||||
gin::CreateHandle(args->isolate(), static_cast<Menu*>(new MenuMac(args)));
|
||||
gin_helper::CallMethod(args->isolate(), handle.get(), "_init");
|
||||
return handle;
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -84,8 +84,11 @@ void MenuViews::OnClosed(int32_t window_id, base::OnceClosure callback) {
|
|||
}
|
||||
|
||||
// static
|
||||
gin_helper::WrappableBase* Menu::New(gin::Arguments* args) {
|
||||
return new MenuViews(args);
|
||||
gin::Handle<Menu> Menu::New(gin::Arguments* args) {
|
||||
auto handle = gin::CreateHandle(args->isolate(),
|
||||
static_cast<Menu*>(new MenuViews(args)));
|
||||
gin_helper::CallMethod(args->isolate(), handle.get(), "_init");
|
||||
return handle;
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -687,7 +687,6 @@ void TopLevelWindow::SetMenu(v8::Isolate* isolate, v8::Local<v8::Value> value) {
|
|||
gin::Handle<Menu> menu;
|
||||
v8::Local<v8::Object> object;
|
||||
if (value->IsObject() && value->ToObject(context).ToLocal(&object) &&
|
||||
gin::V8ToString(isolate, object->GetConstructorName()) == "Menu" &&
|
||||
gin::ConvertFromV8(isolate, value, &menu) && !menu.IsEmpty()) {
|
||||
menu_.Reset(isolate, menu.ToV8());
|
||||
window_->SetMenu(menu->model());
|
||||
|
|
|
@ -21,7 +21,7 @@ v8::Local<v8::Value> CallMethodWithArgs(v8::Isolate* isolate,
|
|||
// Use node::MakeCallback to call the callback, and it will also run pending
|
||||
// tasks in Node.js.
|
||||
v8::MaybeLocal<v8::Value> ret = node::MakeCallback(
|
||||
isolate, obj, method, args->size(), &args->front(), {0, 0});
|
||||
isolate, obj, method, args->size(), args->data(), {0, 0});
|
||||
// If the JS function throws an exception (doesn't return a value) the result
|
||||
// of MakeCallback will be empty and therefore ToLocal will be false, in this
|
||||
// case we need to return "false" as that indicates that the event emitter did
|
||||
|
|
|
@ -69,11 +69,11 @@ v8::Local<v8::Value> CallMethod(v8::Isolate* isolate,
|
|||
gin::Wrappable<T>* object,
|
||||
const char* method_name,
|
||||
Args&&... args) {
|
||||
v8::HandleScope scope(isolate);
|
||||
v8::EscapableHandleScope scope(isolate);
|
||||
v8::Local<v8::Object> v8_object;
|
||||
if (object->GetWrapper(isolate).ToLocal(&v8_object))
|
||||
return CustomEmit(isolate, v8_object, method_name,
|
||||
std::forward<Args>(args)...);
|
||||
return scope.Escape(CustomEmit(isolate, v8_object, method_name,
|
||||
std::forward<Args>(args)...));
|
||||
else
|
||||
return v8::Local<v8::Value>();
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ class Wrappable : public WrappableBase {
|
|||
template <typename Sig>
|
||||
static void SetConstructor(v8::Isolate* isolate,
|
||||
const base::Callback<Sig>& constructor) {
|
||||
v8::Local<v8::FunctionTemplate> templ = CreateFunctionTemplate(
|
||||
v8::Local<v8::FunctionTemplate> templ = gin_helper::CreateFunctionTemplate(
|
||||
isolate, base::Bind(&internal::InvokeNew<Sig>, constructor));
|
||||
templ->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
T::BuildPrototype(isolate, templ);
|
||||
|
|
6
spec-main/ambient.d.ts
vendored
6
spec-main/ambient.d.ts
vendored
|
@ -2,10 +2,8 @@ declare let standardScheme: string;
|
|||
|
||||
declare namespace Electron {
|
||||
interface Menu {
|
||||
delegate: {
|
||||
executeCommand(menu: Menu, event: any, id: number): void;
|
||||
menuWillShow(menu: Menu): void;
|
||||
};
|
||||
_executeCommand(event: any, id: number): void;
|
||||
_menuWillShow(): void;
|
||||
getAcceleratorTextAt(index: number): string;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ describe('MenuItems', () => {
|
|||
done();
|
||||
}
|
||||
}]);
|
||||
menu.delegate.executeCommand(menu, {}, menu.items[0].commandId);
|
||||
menu._executeCommand({}, menu.items[0].commandId);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -60,7 +60,7 @@ describe('MenuItems', () => {
|
|||
}]);
|
||||
|
||||
expect(menu.items[0].checked).to.be.false('menu item checked');
|
||||
menu.delegate.executeCommand(menu, {}, menu.items[0].commandId);
|
||||
menu._executeCommand({}, menu.items[0].commandId);
|
||||
expect(menu.items[0].checked).to.be.true('menu item checked');
|
||||
});
|
||||
|
||||
|
@ -70,9 +70,9 @@ describe('MenuItems', () => {
|
|||
type: 'radio'
|
||||
}]);
|
||||
|
||||
menu.delegate.executeCommand(menu, {}, menu.items[0].commandId);
|
||||
menu._executeCommand({}, menu.items[0].commandId);
|
||||
expect(menu.items[0].checked).to.be.true('menu item checked');
|
||||
menu.delegate.executeCommand(menu, {}, menu.items[0].commandId);
|
||||
menu._executeCommand({}, menu.items[0].commandId);
|
||||
expect(menu.items[0].checked).to.be.true('menu item checked');
|
||||
});
|
||||
|
||||
|
@ -123,7 +123,7 @@ describe('MenuItems', () => {
|
|||
|
||||
it('at least have one item checked in each group', () => {
|
||||
const menu = Menu.buildFromTemplate(template);
|
||||
menu.delegate.menuWillShow(menu);
|
||||
menu._menuWillShow();
|
||||
|
||||
const groups = findRadioGroups(template);
|
||||
|
||||
|
|
Loading…
Reference in a new issue