[gjs/ewlsh/register-type] Correctly chain constructor prototypes to enable static inheritance



commit a42ca6e4902e5ad155d3488ac4073aa893189172
Author: Evan Welsh <contact evanwelsh com>
Date:   Fri Aug 6 06:20:40 2021 -0700

    Correctly chain constructor prototypes to enable static inheritance

 gi/object.cpp                 | 29 +++++++++++++++++++++++++++--
 gi/object.h                   |  3 +++
 modules/core/overrides/Gtk.js | 39 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 69 insertions(+), 2 deletions(-)
---
diff --git a/gi/object.cpp b/gi/object.cpp
index 6f52c0aa..18d26ec1 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -2433,6 +2433,20 @@ bool ObjectPrototype::get_parent_proto(JSContext* cx,
     return true;
 }
 
+bool ObjectPrototype::get_parent_constructor(
+    JSContext* cx, JS::MutableHandleObject constructor) const {
+    GType parent_type = g_type_parent(gtype());
+
+    if (parent_type != G_TYPE_INVALID) {
+        JS::RootedValue v_constructor(cx);
+        if (!gjs_lookup_object_constructor(cx, parent_type, &v_constructor))
+            return false;
+
+        constructor.set(&v_constructor.toObject());
+    }
+    return true;
+}
+
 /*
  * ObjectPrototype::define_class:
  * @in_object: Object where the constructor is stored, typically a repo object.
@@ -2451,9 +2465,20 @@ bool ObjectPrototype::define_class(JSContext* context,
                                    GIObjectInfo* info, GType gtype,
                                    JS::MutableHandleObject constructor,
                                    JS::MutableHandleObject prototype) {
-    if (!ObjectPrototype::create_class(context, in_object, info, gtype,
-                                       constructor, prototype))
+    ObjectPrototype* priv = ObjectPrototype::create_class(
+        context, in_object, info, gtype, constructor, prototype);
+    if (!priv)
+        return false;
+
+    JS::RootedObject parent_constructor(context);
+    if (!priv->get_parent_constructor(context, &parent_constructor))
         return false;
+    // If this is a fundamental constructor (e.g. GObject.Object) the
+    // parent constructor may be null.
+    if (parent_constructor) {
+        if (!JS_SetPrototype(context, constructor, parent_constructor))
+            return false;
+    }
 
     // hook_up_vfunc and the signal handler matcher functions can't be included
     // in gjs_object_instance_proto_funcs because they are custom symbols.
diff --git a/gi/object.h b/gi/object.h
index 6003bd5e..02bc9258 100644
--- a/gi/object.h
+++ b/gi/object.h
@@ -225,6 +225,9 @@ class ObjectPrototype
  private:
     GJS_JSAPI_RETURN_CONVENTION
     bool get_parent_proto(JSContext* cx, JS::MutableHandleObject proto) const;
+    GJS_JSAPI_RETURN_CONVENTION
+    bool get_parent_constructor(JSContext* cx,
+                                JS::MutableHandleObject constructor) const;
 
     [[nodiscard]] bool is_vfunc_unchanged(GIVFuncInfo* info);
     static void vfunc_invalidated_notify(void* data, GClosure* closure);
diff --git a/modules/core/overrides/Gtk.js b/modules/core/overrides/Gtk.js
index 306f7d3f..305814f5 100644
--- a/modules/core/overrides/Gtk.js
+++ b/modules/core/overrides/Gtk.js
@@ -107,6 +107,45 @@ function _init() {
         return klass;
     };
 
+    Gtk.registerWidgetType = function registerWidgetType(klass) {
+        let template = klass[Gtk.template];
+        let cssName = klass[Gtk.cssName];
+        let children = klass[Gtk.children];
+        let internalChildren = klass[Gtk.internalChildren];
+
+        if (template) {
+            klass.prototype._instance_init = function () {
+                this.init_template();
+            };
+        }
+
+        GObject.registerType(klass);
+
+        if (cssName)
+            Gtk.Widget.set_css_name.call(klass, cssName);
+
+        if (template) {
+            if (typeof template === 'string') {
+                Gtk.Widget.set_template_from_uri.call(klass, template);
+            } else {
+                Gtk.Widget.set_template.call(klass, template);
+            }
+
+            if (BuilderScope)
+                Gtk.Widget.set_template_scope.call(klass, new BuilderScope());
+        }
+
+        if (children) {
+            children.forEach(child =>
+                Gtk.Widget.bind_template_child_full.call(klass, child, false, 0));
+        }
+
+        if (internalChildren) {
+            internalChildren.forEach(child =>
+                Gtk.Widget.bind_template_child_full.call(klass, child, true, 0));
+        }
+    }
+
     if (Gtk.Widget.prototype.get_first_child) {
         Gtk.Widget.prototype[Symbol.iterator] = function* () {
             for (let c = this.get_first_child(); c; c = c.get_next_sibling())


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