[gjs: 8/26] object: Move to C++-style API



commit 615f4eb26ca82d54182261b42f890d6c9f7b3f10
Author: Philip Chimento <philip chimento gmail com>
Date:   Mon Jan 21 20:47:26 2019 -0800

    object: Move to C++-style API
    
    This allows cleaning up the public API in object.h a bit, creating some
    new methods that can be used rather than the C-style APIs, changing some
    methods to be private, and adding missing error checks in calling code.
    
    The idea is to gradually provide more typesafe, C++-style APIs for all
    of the GI wrapper classes, and change calling code to use them rather
    than the old C-style APIs.

 gi/arg.cpp        |   5 +-
 gi/function.cpp   |  12 +++-
 gi/gobject.cpp    |  19 +----
 gi/object.cpp     | 209 +++++++++++++++++++++++++++++++++++-------------------
 gi/object.h       |  62 ++++++++--------
 gi/private.cpp    |  11 ++-
 gi/repo.cpp       |   4 +-
 gi/value.cpp      |  11 ++-
 gi/wrapperutils.h |  10 +++
 gjs/context.cpp   |   4 +-
 10 files changed, 210 insertions(+), 137 deletions(-)
---
diff --git a/gi/arg.cpp b/gi/arg.cpp
index c6a8678b..8fbed25f 100644
--- a/gi/arg.cpp
+++ b/gi/arg.cpp
@@ -2930,8 +2930,9 @@ gjs_value_from_g_argument (JSContext             *context,
             }
 
             if (g_type_is_a(gtype, G_TYPE_OBJECT)) {
-                JSObject *obj;
-                obj = gjs_object_from_g_object(context, G_OBJECT(arg->v_pointer));
+                // arg->v_pointer == nullptr is already handled above
+                JSObject* obj = ObjectInstance::wrapper_from_gobject(
+                    context, G_OBJECT(arg->v_pointer));
                 if (obj)
                     value = JS::ObjectValue(*obj);
             } else if (g_type_is_a(gtype, G_TYPE_BOXED) ||
diff --git a/gi/function.cpp b/gi/function.cpp
index a2b086f9..809dfac2 100644
--- a/gi/function.cpp
+++ b/gi/function.cpp
@@ -236,8 +236,14 @@ gjs_callback_closure(ffi_cif *cif,
 
     JS::RootedObject this_object(context);
     if (trampoline->is_vfunc) {
-        auto this_gobject = static_cast<GObject *>(args[0]->v_pointer);
-        this_object = gjs_object_from_g_object(context, this_gobject);
+        GObject* gobj = G_OBJECT(args[0]->v_pointer);
+        if (gobj) {
+            this_object = ObjectInstance::wrapper_from_gobject(context, gobj);
+            if (!this_object) {
+                gjs_log_exception(context);
+                return;
+            }
+        }
 
         /* "this" is not included in the GI signature, but is in the C (and
          * FFI) signature */
@@ -688,7 +694,7 @@ gjs_fill_method_instance(JSContext       *context,
             if (transfer == GI_TRANSFER_EVERYTHING)
                 g_param_spec_ref ((GParamSpec*) out_arg->v_pointer);
         } else if (G_TYPE_IS_INTERFACE(gtype)) {
-            if (gjs_typecheck_is_object(context, obj, false)) {
+            if (ObjectBase::check_jsclass(context, obj)) {
                 if (!ObjectBase::transfer_to_gi_argument(context, obj, out_arg,
                                                          GI_DIRECTION_OUT,
                                                          transfer, gtype))
diff --git a/gi/gobject.cpp b/gi/gobject.cpp
index f9db5c94..debfa6a5 100644
--- a/gi/gobject.cpp
+++ b/gi/gobject.cpp
@@ -201,24 +201,7 @@ static void gjs_object_custom_init(GTypeInstance* instance, void* klass) {
 
     ObjectInstance::object_init_list.pop();
 
-    priv->associate_js_gobject(cx, object, G_OBJECT(instance));
-
-    /* Custom JS objects will most likely have visible state, so
-     * just do this from the start */
-    priv->ensure_uses_toggle_ref(cx);
-
-    const GjsAtoms& atoms = GjsContextPrivate::atoms(cx);
-    JS::RootedValue v(cx);
-    if (!JS_GetPropertyById(cx, object, atoms.instance_init(), &v)) {
-        gjs_log_exception(cx);
-        return;
-    }
-
-    if (!v.isObject())
-        return;
-
-    JS::RootedValue r(cx);
-    if (!JS_CallFunctionValue(cx, object, v, JS::HandleValueArray::empty(), &r))
+    if (!priv->init_custom_class_from_gobject(cx, object, G_OBJECT(instance)))
         gjs_log_exception(cx);
 }
 
diff --git a/gi/object.cpp b/gi/object.cpp
index b3a5aab3..3d9dc25b 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -70,7 +70,7 @@ static_assert(sizeof(ObjectInstance) <= 88,
 #endif  // x86-64 clang
 
 std::stack<JS::PersistentRootedObject> ObjectInstance::object_init_list{};
-static bool weak_pointer_callback = false;
+bool ObjectInstance::s_weak_pointer_callback = false;
 ObjectInstance *ObjectInstance::wrapped_gobject_list = nullptr;
 
 // clang-format off
@@ -1065,16 +1065,24 @@ ObjectInstance::remove_wrapped_gobjects_if(ObjectInstance::Predicate predicate,
         action(priv);
 }
 
-void
-gjs_object_context_dispose_notify(void    *data,
-                                  GObject *where_the_object_was)
-{
-    ObjectInstance::iterate_wrapped_gobjects(std::mem_fn(&ObjectInstance::context_dispose_notify));
+/*
+ * ObjectInstance::context_dispose_notify:
+ *
+ * Callback called when the #GjsContext is disposed. It just calls
+ * handle_context_dispose() on every ObjectInstance.
+ */
+void ObjectInstance::context_dispose_notify(void* data,
+                                            GObject* where_the_object_was) {
+    ObjectInstance::iterate_wrapped_gobjects(
+        std::mem_fn(&ObjectInstance::handle_context_dispose));
 }
 
-void
-ObjectInstance::context_dispose_notify(void)
-{
+/*
+ * ObjectInstance::handle_context_dispose:
+ *
+ * Called on each existing ObjectInstance when the #GjsContext is disposed.
+ */
+void ObjectInstance::handle_context_dispose(void) {
     if (wrapper_is_rooted()) {
         debug_lifecycle("Was rooted, but unrooting due to GjsContext dispose");
         discard_wrapper();
@@ -1270,9 +1278,13 @@ gjs_object_shutdown_toggle_queue(void)
     toggle_queue.shutdown();
 }
 
-void
-gjs_object_prepare_shutdown(void)
-{
+/*
+ * ObjectInstance::prepare_shutdown:
+ *
+ * Called when the #GjsContext is disposed, in order to release all GC roots of
+ * JSObjects that are held by GObjects.
+ */
+void ObjectInstance::prepare_shutdown(void) {
     /* We iterate over all of the objects, breaking the JS <-> C
      * association.  We avoid the potential recursion implied in:
      *   toggle ref removal -> gobj dispose -> toggle ref notify
@@ -1302,11 +1314,14 @@ bool ObjectPrototype::init(JSContext* cx) {
     return true;
 }
 
-static void
-update_heap_wrapper_weak_pointers(JSContext     *cx,
-                                  JSCompartment *compartment,
-                                  gpointer       data)
-{
+/*
+ * ObjectInstance::update_heap_wrapper_weak_pointers:
+ *
+ * Private callback, called after the JS engine finishes garbage collection, and
+ * notifies when weak pointers need to be either moved or swept.
+ */
+void ObjectInstance::update_heap_wrapper_weak_pointers(
+    JSContext* cx, JSCompartment* compartment, void* data) {
     gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "Weak pointer update callback, "
                         "%zu wrapped GObject(s) to examine",
                         ObjectInstance::num_wrapped_gobjects());
@@ -1332,14 +1347,16 @@ ObjectInstance::weak_pointer_was_finalized(void)
     return false;
 }
 
-static void
-ensure_weak_pointer_callback(JSContext *cx)
-{
-    if (!weak_pointer_callback) {
-        JS_AddWeakPointerCompartmentCallback(cx,
-                                             update_heap_wrapper_weak_pointers,
-                                             nullptr);
-        weak_pointer_callback = true;
+/*
+ * ObjectInstance::ensure_weak_pointer_callback:
+ *
+ * Private method called when adding a weak pointer for the first time.
+ */
+void ObjectInstance::ensure_weak_pointer_callback(JSContext* cx) {
+    if (!s_weak_pointer_callback) {
+        JS_AddWeakPointerCompartmentCallback(
+            cx, &ObjectInstance::update_heap_wrapper_weak_pointers, nullptr);
+        s_weak_pointer_callback = true;
     }
 }
 
@@ -1613,8 +1630,8 @@ JSObject* gjs_lookup_object_constructor_from_info(JSContext* context,
            we need to define it first.
         */
         JS::RootedObject ignored(context);
-        if (!gjs_define_object_class(context, in_object, nullptr, gtype,
-                                     &constructor, &ignored))
+        if (!ObjectPrototype::define_class(context, in_object, nullptr, gtype,
+                                           &constructor, &ignored))
             return nullptr;
     } else {
         if (G_UNLIKELY (!value.isObject()))
@@ -1957,14 +1974,24 @@ bool ObjectPrototype::get_parent_proto(JSContext* cx,
     return true;
 }
 
-bool
-gjs_define_object_class(JSContext              *context,
-                        JS::HandleObject        in_object,
-                        GIObjectInfo           *info,
-                        GType                   gtype,
-                        JS::MutableHandleObject constructor,
-                        JS::MutableHandleObject prototype)
-{
+/*
+ * ObjectPrototype::define_class:
+ * @in_object: Object where the constructor is stored, typically a repo object.
+ * @info: Introspection info for the GObject class.
+ * @gtype: #GType for the GObject class.
+ * @constructor: Return location for the constructor object.
+ * @prototype: Return location for the prototype object.
+ *
+ * Define a GObject class constructor and prototype, including all the
+ * necessary methods and properties that are not introspected. Provides the
+ * constructor and prototype objects as out parameters, for convenience
+ * elsewhere.
+ */
+bool ObjectPrototype::define_class(JSContext* context,
+                                   JS::HandleObject in_object,
+                                   GIObjectInfo* info, GType gtype,
+                                   JS::MutableHandleObject constructor,
+                                   JS::MutableHandleObject prototype) {
     if (!ObjectPrototype::create_class(context, in_object, info, gtype,
                                        constructor, prototype))
         return false;
@@ -1985,41 +2012,91 @@ gjs_define_object_class(JSContext              *context,
     return true;
 }
 
-JSObject*
-gjs_object_from_g_object(JSContext    *context,
-                         GObject      *gobj)
-{
-    if (gobj == NULL)
-        return NULL;
+/*
+ * ObjectInstance::init_custom_class_from_gobject:
+ *
+ * Does all the necessary initialization for an ObjectInstance and JSObject
+ * wrapper, given a newly-created GObject pointer, of a GObject class that was
+ * created in JS with GObject.registerClass(). This is called from the GObject's
+ * instance init function in gobject.cpp, and that's the only reason it's a
+ * public method.
+ */
+bool ObjectInstance::init_custom_class_from_gobject(JSContext* cx,
+                                                    JS::HandleObject wrapper,
+                                                    GObject* gobj) {
+    associate_js_gobject(cx, wrapper, gobj);
 
-    ObjectInstance *priv = ObjectInstance::for_gobject(gobj);
+    // Custom JS objects will most likely have visible state, so just do this
+    // from the start.
+    ensure_uses_toggle_ref(cx);
 
-    if (!priv) {
-        /* We have to create a wrapper */
-        GType gtype;
+    const GjsAtoms& atoms = GjsContextPrivate::atoms(cx);
+    JS::RootedValue v(cx);
+    if (!JS_GetPropertyById(cx, wrapper, atoms.instance_init(), &v))
+        return false;
 
-        gjs_debug_marshal(GJS_DEBUG_GOBJECT,
-                          "Wrapping %s with JSObject",
-                          g_type_name_from_instance((GTypeInstance*) gobj));
+    if (v.isUndefined())
+        return true;
+    if (!v.isObject() || !JS::IsCallable(&v.toObject())) {
+        gjs_throw(cx, "_instance_init property was not a function");
+        return false;
+    }
 
-        gtype = G_TYPE_FROM_INSTANCE(gobj);
+    JS::RootedValue ignored_rval(cx);
+    return JS_CallFunctionValue(cx, wrapper, v, JS::HandleValueArray::empty(),
+                                &ignored_rval);
+}
 
-        JS::RootedObject proto(context,
-            gjs_lookup_object_prototype(context, gtype));
-        if (!proto)
-            return nullptr;
+/*
+ * ObjectInstance::new_for_gobject:
+ *
+ * Creates a new JSObject wrapper for the GObject pointer @gobj, and an
+ * ObjectInstance private structure to go along with it.
+ */
+ObjectInstance* ObjectInstance::new_for_gobject(JSContext* cx, GObject* gobj) {
+    g_assert(gobj && "Cannot create JSObject for null GObject pointer");
 
-        JS::RootedObject obj(context,
-            JS_NewObjectWithGivenProto(context, JS_GetClass(proto), proto));
-        if (!obj)
-            return nullptr;
+    GType gtype = G_TYPE_FROM_INSTANCE(gobj);
 
-        priv = ObjectInstance::new_for_js_object(context, obj);
+    gjs_debug_marshal(GJS_DEBUG_GOBJECT, "Wrapping %s with JSObject",
+                      g_type_name(gtype));
 
-        g_object_ref_sink(gobj);
-        priv->associate_js_gobject(context, obj, gobj);
+    JS::RootedObject proto(cx, gjs_lookup_object_prototype(cx, gtype));
+    if (!proto)
+        return nullptr;
+
+    JS::RootedObject obj(
+        cx, JS_NewObjectWithGivenProto(cx, JS_GetClass(proto), proto));
+    if (!obj)
+        return nullptr;
+
+    ObjectInstance* priv = ObjectInstance::new_for_js_object(cx, obj);
 
-        g_assert(priv->wrapper() == obj.get());
+    g_object_ref_sink(gobj);
+    priv->associate_js_gobject(cx, obj, gobj);
+
+    g_assert(priv->wrapper() == obj.get());
+
+    return priv;
+}
+
+/*
+ * ObjectInstance::wrapper_from_gobject:
+ *
+ * Gets a JSObject wrapper for the GObject pointer @gobj. If one already exists,
+ * then it is returned. Otherwise a new one is created with
+ * ObjectInstance::new_for_gobject().
+ */
+JSObject* ObjectInstance::wrapper_from_gobject(JSContext* cx, GObject* gobj) {
+    g_assert(gobj && "Cannot get JSObject for null GObject pointer");
+
+    ObjectInstance* priv = ObjectInstance::for_gobject(gobj);
+
+    if (!priv) {
+        /* We have to create a wrapper */
+        priv = new_for_gobject(cx, gobj);
+        if (!priv)
+            return nullptr;
     }
 
     return priv->wrapper();
@@ -2083,16 +2160,6 @@ bool ObjectBase::transfer_to_gi_argument(JSContext* cx, JS::HandleObject obj,
     return true;
 }
 
-bool
-gjs_typecheck_is_object(JSContext       *context,
-                        JS::HandleObject object,
-                        bool             throw_error)
-{
-    if (throw_error)
-        return !!ObjectBase::for_js_typecheck(context, object);
-    return !!ObjectBase::for_js(context, object);
-}
-
 // Overrides GIWrapperInstance::typecheck_impl()
 bool ObjectInstance::typecheck_impl(JSContext* cx, GIBaseInfo* expected_info,
                                     GType expected_type) const {
diff --git a/gi/object.h b/gi/object.h
index 195ac504..8a7be4c5 100644
--- a/gi/object.h
+++ b/gi/object.h
@@ -240,6 +240,12 @@ class ObjectPrototype
                                std::vector<const char*>* names,
                                AutoGValueVector* values);
 
+    GJS_JSAPI_RETURN_CONVENTION
+    static bool define_class(JSContext* cx, JS::HandleObject in_object,
+                             GIObjectInfo* info, GType gtype,
+                             JS::MutableHandleObject constructor,
+                             JS::MutableHandleObject prototype);
+
     /* These are currently only needed in the GObject base init and finalize
      * functions, for prototypes, even though m_closures is in ObjectBase. */
     void ref_closures(void) {
@@ -292,6 +298,8 @@ class ObjectInstance : public GIWrapperInstance<ObjectBase, ObjectPrototype,
      * hard ref on the underlying GObject, and may be finalized at will. */
     bool m_uses_toggle_ref : 1;
 
+    static bool s_weak_pointer_callback;
+
  public:
     static std::stack<JS::PersistentRootedObject> object_init_list;
 
@@ -301,6 +309,9 @@ class ObjectInstance : public GIWrapperInstance<ObjectBase, ObjectPrototype,
     ObjectInstance(JSContext* cx, JS::HandleObject obj);
     ~ObjectInstance();
 
+    GJS_JSAPI_RETURN_CONVENTION
+    static ObjectInstance* new_for_gobject(JSContext* cx, GObject* gobj);
+
     // Extra method to get an existing ObjectInstance from qdata
 
  public:
@@ -325,33 +336,45 @@ class ObjectInstance : public GIWrapperInstance<ObjectBase, ObjectPrototype,
     void switch_to_unrooted(void) { m_wrapper.switch_to_unrooted(); }
     GJS_USE
     bool update_after_gc(void) { return m_wrapper.update_after_gc(); }
-
- public:
     GJS_USE
     bool wrapper_is_rooted(void) const { return m_wrapper.rooted(); }
     void release_native_object(void);
     void associate_js_gobject(JSContext* cx, JS::HandleObject obj,
                               GObject* gobj);
     void disassociate_js_gobject(void);
+    void handle_context_dispose(void);
     GJS_USE bool weak_pointer_was_finalized(void);
+    static void ensure_weak_pointer_callback(JSContext* cx);
+    static void update_heap_wrapper_weak_pointers(JSContext* cx,
+                                                  JSCompartment* compartment,
+                                                  void* data);
+
+ public:
     void toggle_down(void);
     void toggle_up(void);
 
+    GJS_JSAPI_RETURN_CONVENTION
+    static JSObject* wrapper_from_gobject(JSContext* cx, GObject* ptr);
+
     /* Helper methods */
 
  private:
     void set_object_qdata(void);
     void unset_object_qdata(void);
     void check_js_object_finalized(void);
-
- public:
     void ensure_uses_toggle_ref(JSContext* cx);
     GJS_USE bool check_gobject_disposed(const char* for_what) const;
+
+ public:
     static GObject* copy_ptr(JSContext* G_GNUC_UNUSED, GType G_GNUC_UNUSED,
                              void* ptr) {
         return G_OBJECT(g_object_ref(G_OBJECT(ptr)));
     }
 
+    GJS_JSAPI_RETURN_CONVENTION
+    bool init_custom_class_from_gobject(JSContext* cx, JS::HandleObject wrapper,
+                                        GObject* gobj);
+
     /* Methods to manipulate the linked list of instances */
 
  private:
@@ -360,10 +383,6 @@ class ObjectInstance : public GIWrapperInstance<ObjectBase, ObjectPrototype,
     ObjectInstance* next(void) const { return m_instance_link.next(); }
     void link(void);
     void unlink(void);
-
- public:
-    GJS_USE
-    GjsListLink* get_link(void) { return &m_instance_link; }
     GJS_USE
     static size_t num_wrapped_gobjects(void) {
         return wrapped_gobject_list
@@ -375,6 +394,10 @@ class ObjectInstance : public GIWrapperInstance<ObjectBase, ObjectPrototype,
     static void iterate_wrapped_gobjects(Action action);
     static void remove_wrapped_gobjects_if(Predicate predicate, Action action);
 
+ public:
+    GJS_USE GjsListLink* get_link(void) { return &m_instance_link; }
+    static void prepare_shutdown(void);
+
     /* JSClass operations */
 
  private:
@@ -424,19 +447,12 @@ class ObjectInstance : public GIWrapperInstance<ObjectBase, ObjectPrototype,
 
  public:
     void gobj_dispose_notify(void);
-    void context_dispose_notify(void);
+    static void context_dispose_notify(void* data,
+                                       GObject* where_the_object_was);
 };
 
 G_BEGIN_DECLS
 
-GJS_JSAPI_RETURN_CONVENTION
-bool gjs_define_object_class(JSContext              *cx,
-                             JS::HandleObject        in_object,
-                             GIObjectInfo           *info,
-                             GType                   gtype,
-                             JS::MutableHandleObject constructor,
-                             JS::MutableHandleObject prototype);
-
 GJS_JSAPI_RETURN_CONVENTION
 bool gjs_lookup_object_constructor(JSContext             *context,
                                    GType                  gtype,
@@ -446,20 +462,8 @@ JSObject* gjs_lookup_object_constructor_from_info(JSContext* cx,
                                                   GIObjectInfo* info,
                                                   GType gtype);
 
-GJS_JSAPI_RETURN_CONVENTION
-JSObject* gjs_object_from_g_object      (JSContext     *context,
-                                         GObject       *gobj);
-
-GJS_USE
-bool      gjs_typecheck_is_object(JSContext       *context,
-                                  JS::HandleObject obj,
-                                  bool             throw_error);
-
-void gjs_object_prepare_shutdown(void);
 void gjs_object_clear_toggles(void);
 void gjs_object_shutdown_toggle_queue(void);
-void gjs_object_context_dispose_notify(void    *data,
-                                       GObject *where_the_object_was);
 
 G_END_DECLS
 
diff --git a/gi/private.cpp b/gi/private.cpp
index 5a99dd7c..4cc29f74 100644
--- a/gi/private.cpp
+++ b/gi/private.cpp
@@ -258,10 +258,7 @@ static bool gjs_register_type(JSContext* cx, unsigned argc, JS::Value* vp) {
                              "properties", &properties))
         return false;
 
-    if (!parent)
-        return false;
-
-    if (!gjs_typecheck_is_object(cx, parent, true))
+    if (!parent || !ObjectBase::for_js_typecheck(cx, parent, argv))
         return false;
 
     uint32_t n_interfaces, n_properties;
@@ -283,7 +280,7 @@ static bool gjs_register_type(JSContext* cx, unsigned argc, JS::Value* vp) {
     }
 
     auto* parent_priv = ObjectPrototype::for_js(cx, parent);
-    /* We checked parent above, in gjs_typecheck_is_object() */
+    /* We checked parent above, in ObjectBase::for_js_typecheck() */
     g_assert(parent_priv);
 
     GTypeQuery query;
@@ -314,8 +311,8 @@ static bool gjs_register_type(JSContext* cx, unsigned argc, JS::Value* vp) {
     /* create a custom JSClass */
     JS::RootedObject module(cx, gjs_lookup_private_namespace(cx));
     JS::RootedObject constructor(cx), prototype(cx);
-    if (!gjs_define_object_class(cx, module, nullptr, instance_type,
-                                 &constructor, &prototype))
+    if (!ObjectPrototype::define_class(cx, module, nullptr, instance_type,
+                                       &constructor, &prototype))
         return false;
 
     auto* priv = ObjectPrototype::for_js(cx, prototype);
diff --git a/gi/repo.cpp b/gi/repo.cpp
index 9ad42ad7..f46d599a 100644
--- a/gi/repo.cpp
+++ b/gi/repo.cpp
@@ -433,8 +433,8 @@ gjs_define_info(JSContext       *context,
                     return false;
             } else if (g_type_is_a (gtype, G_TYPE_OBJECT)) {
                 JS::RootedObject ignored1(context), ignored2(context);
-                if (!gjs_define_object_class(context, in_object, info, gtype,
-                                             &ignored1, &ignored2))
+                if (!ObjectPrototype::define_class(context, in_object, info,
+                                                   gtype, &ignored1, &ignored2))
                     return false;
             } else if (G_TYPE_IS_INSTANTIATABLE(gtype)) {
                 JS::RootedObject ignored1(context), ignored2(context);
diff --git a/gi/value.cpp b/gi/value.cpp
index 20adaac8..18005985 100644
--- a/gi/value.cpp
+++ b/gi/value.cpp
@@ -807,12 +807,17 @@ gjs_value_from_g_value_internal(JSContext             *context,
         value_p.setBoolean(!!v);
     } else if (g_type_is_a(gtype, G_TYPE_OBJECT) || g_type_is_a(gtype, G_TYPE_INTERFACE)) {
         GObject *gobj;
-        JSObject *obj;
 
         gobj = (GObject*) g_value_get_object(gvalue);
 
-        obj = gjs_object_from_g_object(context, gobj);
-        value_p.setObjectOrNull(obj);
+        if (gobj) {
+            JSObject* obj = ObjectInstance::wrapper_from_gobject(context, gobj);
+            if (!obj)
+                return false;
+            value_p.setObject(*obj);
+        } else {
+            value_p.setNull();
+        }
     } else if (gtype == G_TYPE_STRV) {
         if (!gjs_array_from_strv (context,
                                   value_p,
diff --git a/gi/wrapperutils.h b/gi/wrapperutils.h
index 2837df2b..40ba3122 100644
--- a/gi/wrapperutils.h
+++ b/gi/wrapperutils.h
@@ -152,6 +152,16 @@ class GIWrapperBase {
             JS_GetInstancePrivate(cx, wrapper, &Base::klass, nullptr));
     }
 
+    /*
+     * GIWrapperBase::check_jsclass:
+     *
+     * Checks if the given wrapper object has the right JSClass (Base::klass).
+     */
+    GJS_USE
+    static bool check_jsclass(JSContext* cx, JS::HandleObject wrapper) {
+        return !!for_js(cx, wrapper);
+    }
+
     /*
      * GIWrapperBase::for_js_typecheck:
      *
diff --git a/gjs/context.cpp b/gjs/context.cpp
index b2783375..45447641 100644
--- a/gjs/context.cpp
+++ b/gjs/context.cpp
@@ -374,7 +374,7 @@ void GjsContextPrivate::dispose(void) {
          * still exist, but point to NULL.
          */
         gjs_debug(GJS_DEBUG_CONTEXT, "Releasing all native objects");
-        gjs_object_prepare_shutdown();
+        ObjectInstance::prepare_shutdown();
 
         gjs_debug(GJS_DEBUG_CONTEXT, "Disabling auto GC");
         if (m_auto_gc_id > 0) {
@@ -440,7 +440,7 @@ gjs_context_constructed(GObject *object)
 
     setup_dump_heap();
 
-    g_object_weak_ref(object, gjs_object_context_dispose_notify, nullptr);
+    g_object_weak_ref(object, &ObjectInstance::context_dispose_notify, nullptr);
 }
 
 GjsContextPrivate::GjsContextPrivate(JSContext* cx, GjsContext* public_context)


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