[gjs/ewlsh/register-type] GObject.registerType more functional prototype




commit 1d5d526ce5d47a790d0d77893d653faa47252416
Author: Evan Welsh <noreply evanwelsh com>
Date:   Thu Oct 15 10:36:44 2020 -0500

    GObject.registerType more functional prototype

 gi/object.cpp                     | 22 +++++++++++++++++++---
 gi/wrapperutils.h                 | 28 +++++++++++++++++++++++++++-
 gjs/atoms.h                       |  1 +
 modules/core/overrides/GObject.js | 16 ++++++++++++++++
 4 files changed, 63 insertions(+), 4 deletions(-)
---
diff --git a/gi/object.cpp b/gi/object.cpp
index fd338090..9079d4f1 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -1595,9 +1595,25 @@ bool ObjectInstance::constructor_impl(JSContext* context,
         return false;
     }
 
-    return gjs_object_require_property(context, object, "GObject instance",
-                                       gjs->atoms().init(), &initer) &&
-           gjs->call_function(object, initer, argv, argv.rval());
+    // If our instance is an instance of &klass it is an instance of a native
+    // class.
+    if (JS_InstanceOf(context, object, &klass, nullptr)) {
+        return gjs_object_require_property(context, object, "GObject instance",
+                                           gjs->atoms().init(), &initer) &&
+               gjs->call_function(object, initer, argv, argv.rval());
+        // Otherwise it is a JS-based class and we should call the constructor
+        // directly.
+    } else {
+        // TODO: This needs error guards.
+        ObjectBase* priv = ObjectBase::for_js(context, object);
+
+        if (!priv->check_is_instance(context, "initialize"))
+            return false;
+
+        JS::RootedObject obj(context, object);
+
+        return priv->to_instance()->init_impl(context, argv, &obj);
+    }
 }
 
 void ObjectInstance::trace_impl(JSTracer* tracer) {
diff --git a/gi/wrapperutils.h b/gi/wrapperutils.h
index 89b77342..fc819b99 100644
--- a/gi/wrapperutils.h
+++ b/gi/wrapperutils.h
@@ -514,7 +514,19 @@ class GIWrapperBase {
         JS::RootedObject proto(cx);
         if (!JS_GetPrototype(cx, obj, &proto))
             return false;
-        if (JS_GetClass(proto) != &Base::klass) {
+
+        JS::RootedValue gproto(cx);
+
+        bool has_property = false;
+
+        if (!JS_HasOwnProperty(cx, proto, "$gprototype", &has_property)) {
+            return false;
+        }
+
+        if (JS_GetClass(proto) != &Base::klass &&
+            (!has_property ||
+             (JS_GetProperty(cx, proto, "$gprototype", &gproto) &&
+              gproto.isObject()))) {
             gjs_throw(cx, "Tried to construct an object without a GType");
             return false;
         }
@@ -976,6 +988,20 @@ class GIWrapperPrototype : public Base {
                                                      JS::HandleObject wrapper) {
         JS::RootedObject proto(cx);
         JS_GetPrototype(cx, wrapper, &proto);
+
+        if (JS_GetClass(proto) != &Base::klass) {
+            JS::RootedValue gproto(cx);
+
+            // TODO: Use a unique symbol instead.
+            // TODO: Don't store the entire prototype in $gprototype
+            if (JS_GetProperty(cx, proto, "$gprototype", &gproto) &&
+                gproto.isObject()) {
+                proto.set(&gproto.toObject());
+            }
+
+            // TODO: Handle assertions with errors instead.
+        }
+
         Base* retval = Base::for_js(cx, proto);
         g_assert(retval);
         return retval->to_prototype();
diff --git a/gjs/atoms.h b/gjs/atoms.h
index 966999c8..2705678a 100644
--- a/gjs/atoms.h
+++ b/gjs/atoms.h
@@ -33,6 +33,7 @@ class JSTracer;
     macro(glib, "GLib") \
     macro(gobject, "GObject") \
     macro(gtype, "$gtype") \
+    macro(gprototype, "$gprototype") \
     macro(height, "height") \
     macro(imports, "imports") \
     macro(init, "_init") \
diff --git a/modules/core/overrides/GObject.js b/modules/core/overrides/GObject.js
index 50deb7dc..3bf30c6d 100644
--- a/modules/core/overrides/GObject.js
+++ b/modules/core/overrides/GObject.js
@@ -78,6 +78,21 @@ function registerClass(...args) {
     return initclass._classInit(klass);
 }
 
+function registerType(klass, options) {
+    let gtypename = _createGTypeName(klass);
+    let gflags = klass.hasOwnProperty(GTypeFlags) ? klass[GTypeFlags] : 0;
+
+    let parent = Object.getPrototypeOf(klass);
+    
+    let registered_type = Gi.register_type(parent.prototype, gtypename, gflags, [], []);
+
+    // TODO: Construct a better "wrapper" than the registered prototype
+    // TODO: Avoid discarding a constructed constructor
+    klass.prototype.$gprototype = registered_type.prototype;
+
+    return registered_type.$gtype;
+}
+
 // Some common functions between GObject.Class and GObject.Interface
 
 function _createSignals(gtype, sigs) {
@@ -420,6 +435,7 @@ function _init() {
     };
 
     GObject.registerClass = registerClass;
+    GObject.registerType = registerType;
 
     GObject.Object._classInit = function (klass) {
         let gtypename = _createGTypeName(klass);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]