[gjs/ewlsh/interface-resolution: 1/2] gi: Use GJS wrapper to define interface methods
- From: Evan Welsh <ewlsh src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs/ewlsh/interface-resolution: 1/2] gi: Use GJS wrapper to define interface methods
- Date: Thu, 26 Aug 2021 01:11:15 +0000 (UTC)
commit fea9b72e85418a3dc447d29a1d7f42ddb597c079
Author: Evan Welsh <contact evanwelsh com>
Date: Wed Aug 25 18:06:16 2021 -0700
gi: Use GJS wrapper to define interface methods
This change uses the GJS interface wrapper to resolve interface methods
instead of defining unique copies for each interface method.
This allows for overriding methods on interfaces as long as the override
exists before the method is resolved for the first time.
Fixes #189
gi/object.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 47 insertions(+), 4 deletions(-)
---
diff --git a/gi/object.cpp b/gi/object.cpp
index 77acf3f4..9174a319 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -641,6 +641,42 @@ bool ObjectPrototype::lazy_define_gobject_property(JSContext* cx,
return true;
}
+static bool copy_interface_method(JSContext* cx, GIObjectInfo* iface_info,
+ const char* method_name,
+ JS::HandleObject target_prototype) {
+ GType gtype = g_base_info_get_type(iface_info);
+ JS::RootedObject constr(
+ cx, gjs_lookup_object_constructor_from_info(cx, iface_info, gtype));
+ if (!constr)
+ return false;
+
+ JS::RootedValue v_prototype(cx);
+ if (!JS_GetProperty(cx, constr, "prototype", &v_prototype))
+ return false;
+
+ JS::RootedObject prototype(cx, &v_prototype.toObject());
+ JS::RootedId method_name_id(cx, gjs_intern_string_to_id(cx, method_name));
+ bool target_has_property(cx);
+ JS::Rooted<JS::PropertyDescriptor> descr(cx);
+ if (!JS_HasPropertyById(cx, target_prototype, method_name_id,
+ &target_has_property))
+ return false;
+
+ // Don't overwrite an existing method implementation...
+ if (target_has_property)
+ return true;
+
+ // TODO(ewlsh): Handle copying descriptor...
+ if (!JS_GetPropertyDescriptorById(cx, prototype, method_name_id, &descr))
+ return false;
+
+ if (!JS_SetPropertyById(cx, target_prototype, method_name_id,
+ descr.value()))
+ return false;
+
+ return true;
+}
+
bool ObjectPrototype::resolve_no_info(JSContext* cx, JS::HandleObject obj,
JS::HandleId id, bool* resolved,
const char* name,
@@ -688,7 +724,8 @@ bool ObjectPrototype::resolve_no_info(JSContext* cx, JS::HandleObject obj,
g_interface_info_find_method(iface_info, name);
if (method_info) {
if (g_function_info_get_flags (method_info) & GI_FUNCTION_IS_METHOD) {
- if (!gjs_define_function(cx, obj, m_gtype, method_info))
+ if (!copy_interface_method(cx, iface_info, method_info.name(),
+ obj))
return false;
*resolved = true;
@@ -876,8 +913,10 @@ bool ObjectPrototype::uncached_resolve(JSContext* context, JS::HandleObject obj,
* introduces the iface)
*/
+ GjsAutoBaseInfo implementor_info;
GjsAutoFunctionInfo method_info =
- g_object_info_find_method_using_interfaces(m_info, name, nullptr);
+ g_object_info_find_method_using_interfaces(m_info, name,
+ implementor_info.out());
/**
* Search through any interfaces implemented by the GType;
@@ -896,9 +935,13 @@ bool ObjectPrototype::uncached_resolve(JSContext* context, JS::HandleObject obj,
gjs_debug(GJS_DEBUG_GOBJECT,
"Defining method %s in prototype for %s (%s.%s)",
method_info.name(), type_name(), ns(), this->name());
-
- if (!gjs_define_function(context, obj, m_gtype, method_info))
+ if (GI_IS_INTERFACE_INFO(implementor_info)) {
+ if (!copy_interface_method(context, implementor_info,
+ method_info.name(), obj))
+ return false;
+ } else if (!gjs_define_function(context, obj, m_gtype, method_info)) {
return false;
+ }
*resolved = true; /* we defined the prop in obj */
} else {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]