diff --git a/src/cpp/include/nodegui/QtGui/QApplication/napplication.hpp b/src/cpp/include/nodegui/QtGui/QApplication/napplication.hpp index 3d051945c..ebbb881b5 100644 --- a/src/cpp/include/nodegui/QtGui/QApplication/napplication.hpp +++ b/src/cpp/include/nodegui/QtGui/QApplication/napplication.hpp @@ -30,7 +30,7 @@ class DLL_EXPORT NApplication : public QApplication, public EventWidget { Napi::Env env = this->emitOnNode.Env(); Napi::HandleScope scope(env); auto instance = - WrapperCache::instance.get(env, screen); + WrapperCache::instance.get(env, screen, false); this->emitOnNode.Call( {Napi::String::New(env, "primaryScreenChanged"), instance}); }); @@ -39,7 +39,7 @@ class DLL_EXPORT NApplication : public QApplication, public EventWidget { Napi::Env env = this->emitOnNode.Env(); Napi::HandleScope scope(env); auto instance = - WrapperCache::instance.get(env, screen); + WrapperCache::instance.get(env, screen, false); this->emitOnNode.Call({Napi::String::New(env, "screenAdded"), instance}); }); @@ -48,7 +48,7 @@ class DLL_EXPORT NApplication : public QApplication, public EventWidget { Napi::Env env = this->emitOnNode.Env(); Napi::HandleScope scope(env); auto instance = - WrapperCache::instance.get(env, screen); + WrapperCache::instance.get(env, screen, false); this->emitOnNode.Call( {Napi::String::New(env, "screenRemoved"), instance}); }); diff --git a/src/cpp/include/nodegui/QtWidgets/QWidget/qwidget_macro.h b/src/cpp/include/nodegui/QtWidgets/QWidget/qwidget_macro.h index c4edc7dcd..c9a0d0355 100644 --- a/src/cpp/include/nodegui/QtWidgets/QWidget/qwidget_macro.h +++ b/src/cpp/include/nodegui/QtWidgets/QWidget/qwidget_macro.h @@ -427,7 +427,7 @@ Napi::Env env = info.Env(); \ QWindow* window = this->instance->windowHandle(); \ if (window) { \ - return WrapperCache::instance.get(env, window); \ + return WrapperCache::instance.get(env, window, false); \ } else { \ return env.Null(); \ } \ diff --git a/src/cpp/include/nodegui/core/WrapperCache/wrappercache.h b/src/cpp/include/nodegui/core/WrapperCache/wrappercache.h index 4c43d33b4..984820bd3 100644 --- a/src/cpp/include/nodegui/core/WrapperCache/wrappercache.h +++ b/src/cpp/include/nodegui/core/WrapperCache/wrappercache.h @@ -6,7 +6,8 @@ #include #include "Extras/Export/export.h" -#include "QtGui/QScreen/qscreen_wrap.h" +#include "Extras/Utils/nutils.h" + struct CachedObject { napi_ref ref; @@ -24,7 +25,7 @@ class DLL_EXPORT WrapperCache : public QObject { Q_OBJECT private: - QMap cache; + QMap cache; public: /** @@ -44,29 +45,53 @@ class DLL_EXPORT WrapperCache : public QObject { * @return The JS wrapper object. */ template - Napi::Object get(Napi::Env env, T* object) { - if (this->cache.contains(object)) { + Napi::Object get(Napi::Env env, T* object, bool isCreatedByNodeGui) { + uint64_t ptrHash = extrautils::hashPointerTo53bit(object); + if (this->cache.contains(ptrHash)) { napi_value result = nullptr; - napi_get_reference_value(env, this->cache[object].ref, &result); - return Napi::Object(env, result); + napi_get_reference_value(env, this->cache[ptrHash].ref, &result); + + napi_valuetype valuetype; + napi_typeof(env, result, &valuetype); + if (valuetype != napi_null) { + return Napi::Object(env, result); + } } Napi::Object wrapper = W::constructor.New({Napi::External::New(env, object)}); - napi_ref ref = nullptr; - napi_create_reference(env, wrapper, 1, &ref); - this->cache[object].env = napi_env(env); - this->cache[object].ref = ref; - - QObject::connect(object, &QObject::destroyed, this, - &WrapperCache::handleDestroyed); + store(env, extrautils::hashPointerTo53bit(object), object, wrapper, isCreatedByNodeGui); return wrapper; } + /** + * Store a mapping from Qt Object to wrapper + * + * @param T - (template argument) The Qt class of the object being cached, + * e.g. `QScreen`. + * @param W - (template argument) The wrapper type which matches the object + * `QScreenWrap`. + * @param env = Napi environment + * @param object - Pointer to the QObject for which a wrapper is required. + * @param wrapper - The wrapper object matching `object`. + */ + void store(Napi::Env env, uint64_t ptrHash, QObject *qobject, Napi::Object wrapper, bool isWeak) { + napi_ref ref = nullptr; + + napi_create_reference(env, wrapper, isWeak ? 0 : 1, &ref); + this->cache[ptrHash].env = napi_env(env); + this->cache[ptrHash].ref = ref; + + QObject::connect(qobject, &QObject::destroyed, this, + &WrapperCache::handleDestroyed); + } + static Napi::Object init(Napi::Env env, Napi::Object exports) { exports.Set("WrapperCache_injectCallback", Napi::Function::New(env)); + // exports.Set("WrapperCache_storeJS", + // Napi::Function::New(env)); return exports; } @@ -81,7 +106,8 @@ class DLL_EXPORT WrapperCache : public QObject { public Q_SLOTS: void handleDestroyed(const QObject* object) { - if (!this->cache.contains(object)) { + uint64_t ptrHash = extrautils::hashPointerTo53bit(object); + if (!this->cache.contains(ptrHash)) { return; } @@ -92,12 +118,14 @@ class DLL_EXPORT WrapperCache : public QObject { Napi::HandleScope scope(env); destroyedCallback.Call( env.Global(), - {Napi::Value::From(env, extrautils::hashPointerTo53bit(object))}); + {Napi::Value::From(env, ptrHash)}); } uint32_t result = 0; - napi_reference_unref(this->cache[object].env, this->cache[object].ref, +// TODO: Grab the wrapper C++ object and null out its ref to the Qt object. + + napi_reference_unref(this->cache[ptrHash].env, this->cache[ptrHash].ref, &result); - this->cache.remove(object); + this->cache.remove(ptrHash); } }; diff --git a/src/cpp/lib/QtGui/QApplication/qapplication_wrap.cpp b/src/cpp/lib/QtGui/QApplication/qapplication_wrap.cpp index 17189e12b..964fcb56c 100644 --- a/src/cpp/lib/QtGui/QApplication/qapplication_wrap.cpp +++ b/src/cpp/lib/QtGui/QApplication/qapplication_wrap.cpp @@ -119,7 +119,7 @@ Napi::Value StaticQApplicationWrapMethods::clipboard( QClipboard* clipboard = QApplication::clipboard(); if (clipboard) { return WrapperCache::instance.get(env, - clipboard); + clipboard, false); } else { return env.Null(); } @@ -163,7 +163,7 @@ Napi::Value StaticQApplicationWrapMethods::primaryScreen( Napi::Env env = info.Env(); auto screen = QApplication::primaryScreen(); if (screen) { - return WrapperCache::instance.get(env, screen); + return WrapperCache::instance.get(env, screen, false); } else { return env.Null(); } @@ -177,7 +177,7 @@ Napi::Value StaticQApplicationWrapMethods::screens( for (int i = 0; i < screens.size(); i++) { QScreen* screen = screens[i]; auto instance = - WrapperCache::instance.get(env, screen); + WrapperCache::instance.get(env, screen, false); jsArray[i] = instance; } return jsArray; diff --git a/src/cpp/lib/QtGui/QWindow/qwindow_wrap.cpp b/src/cpp/lib/QtGui/QWindow/qwindow_wrap.cpp index 00b0d98a7..8412070ff 100644 --- a/src/cpp/lib/QtGui/QWindow/qwindow_wrap.cpp +++ b/src/cpp/lib/QtGui/QWindow/qwindow_wrap.cpp @@ -56,7 +56,7 @@ void QWindowWrap::connectSignalsToEventEmitter() { Napi::Env env = this->emitOnNode.Env(); Napi::HandleScope scope(env); auto instance = - WrapperCache::instance.get(env, screen); + WrapperCache::instance.get(env, screen, false); this->emitOnNode.Call( {Napi::String::New(env, "screenChanged"), instance}); }); @@ -81,7 +81,7 @@ Napi::Value QWindowWrap::screen(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); QScreen* screen = this->instance->screen(); if (screen) { - return WrapperCache::instance.get(env, screen); + return WrapperCache::instance.get(env, screen, false); } else { return env.Null(); } diff --git a/src/cpp/lib/test/cachetestqobject_wrap.cpp b/src/cpp/lib/test/cachetestqobject_wrap.cpp index 1eaf062f6..9beca174f 100644 --- a/src/cpp/lib/test/cachetestqobject_wrap.cpp +++ b/src/cpp/lib/test/cachetestqobject_wrap.cpp @@ -48,7 +48,7 @@ Napi::Value CacheTestQObjectWrap::foo(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); CacheTestQObject* foo = this->instance->foo(); return WrapperCache::instance.get( - env, foo); + env, foo, false); } Napi::Value CacheTestQObjectWrap::clearFoo(const Napi::CallbackInfo& info) { @@ -61,5 +61,5 @@ Napi::Value CacheTestQObjectWrap::bar(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); CacheTestQObject* bar = this->instance->bar(); return WrapperCache::instance.get( - env, bar); + env, bar, false); }