123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- // Copyright (c) 2017 GitHub, Inc.
- // Use of this source code is governed by the MIT license that can be
- // found in the LICENSE file.
- #include <string>
- #include "atom/browser/api/event_subscriber.h"
- #include "atom/common/native_mate_converters/callback.h"
- namespace {
- // A FunctionTemplate lifetime is bound to the v8 context, so it can be safely
- // stored as a global here since there's only one for the main process.
- v8::Global<v8::FunctionTemplate> g_cached_template;
- struct JSHandlerData {
- JSHandlerData(v8::Isolate* isolate,
- mate::internal::EventSubscriberBase* subscriber)
- : handle_(isolate, v8::External::New(isolate, this)),
- subscriber_(subscriber) {
- handle_.SetWeak(this, GC, v8::WeakCallbackType::kFinalizer);
- }
- static void GC(const v8::WeakCallbackInfo<JSHandlerData>& data) {
- delete data.GetParameter();
- }
- v8::Global<v8::External> handle_;
- mate::internal::EventSubscriberBase* subscriber_;
- };
- void InvokeCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
- v8::Locker locker(info.GetIsolate());
- v8::HandleScope handle_scope(info.GetIsolate());
- v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
- v8::Context::Scope context_scope(context);
- mate::Arguments args(info);
- v8::Local<v8::Value> handler, event;
- args.GetNext(&handler);
- args.GetNext(&event);
- DCHECK(handler->IsExternal());
- DCHECK(event->IsString());
- JSHandlerData* handler_data = static_cast<JSHandlerData*>(
- v8::Local<v8::External>::Cast(handler)->Value());
- handler_data->subscriber_->EventEmitted(mate::V8ToString(event), &args);
- }
- } // namespace
- namespace mate {
- namespace internal {
- EventSubscriberBase::EventSubscriberBase(v8::Isolate* isolate,
- v8::Local<v8::Object> emitter)
- : isolate_(isolate), emitter_(isolate, emitter) {
- if (g_cached_template.IsEmpty()) {
- g_cached_template = v8::Global<v8::FunctionTemplate>(
- isolate_, v8::FunctionTemplate::New(isolate_, InvokeCallback));
- }
- }
- EventSubscriberBase::~EventSubscriberBase() {
- if (!isolate_) {
- return;
- }
- RemoveAllListeners();
- emitter_.Reset();
- DCHECK_EQ(js_handlers_.size(), 0u);
- }
- void EventSubscriberBase::On(const std::string& event_name) {
- DCHECK(js_handlers_.find(event_name) == js_handlers_.end());
- v8::Locker locker(isolate_);
- v8::Isolate::Scope isolate_scope(isolate_);
- v8::HandleScope handle_scope(isolate_);
- auto fn_template = g_cached_template.Get(isolate_);
- auto event = mate::StringToV8(isolate_, event_name);
- auto* js_handler_data = new JSHandlerData(isolate_, this);
- v8::Local<v8::Value> fn = internal::BindFunctionWith(
- isolate_, isolate_->GetCurrentContext(), fn_template->GetFunction(),
- js_handler_data->handle_.Get(isolate_), event);
- js_handlers_.insert(
- std::make_pair(event_name, v8::Global<v8::Value>(isolate_, fn)));
- internal::ValueVector converted_args = {event, fn};
- internal::CallMethodWithArgs(isolate_, emitter_.Get(isolate_), "on",
- &converted_args);
- }
- void EventSubscriberBase::Off(const std::string& event_name) {
- v8::Locker locker(isolate_);
- v8::Isolate::Scope isolate_scope(isolate_);
- v8::HandleScope handle_scope(isolate_);
- auto js_handler = js_handlers_.find(event_name);
- DCHECK(js_handler != js_handlers_.end());
- RemoveListener(js_handler);
- }
- void EventSubscriberBase::RemoveAllListeners() {
- v8::Locker locker(isolate_);
- v8::Isolate::Scope isolate_scope(isolate_);
- v8::HandleScope handle_scope(isolate_);
- while (!js_handlers_.empty()) {
- RemoveListener(js_handlers_.begin());
- }
- }
- std::map<std::string, v8::Global<v8::Value>>::iterator
- EventSubscriberBase::RemoveListener(
- std::map<std::string, v8::Global<v8::Value>>::iterator it) {
- internal::ValueVector args = {StringToV8(isolate_, it->first),
- it->second.Get(isolate_)};
- internal::CallMethodWithArgs(
- isolate_, v8::Local<v8::Object>::Cast(emitter_.Get(isolate_)),
- "removeListener", &args);
- it->second.Reset();
- return js_handlers_.erase(it);
- }
- } // namespace internal
- } // namespace mate
|