summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gi/boxed.cpp63
-rw-r--r--gi/boxed.h18
-rw-r--r--installed-tests/js/testGObject.js11
3 files changed, 79 insertions, 13 deletions
diff --git a/gi/boxed.cpp b/gi/boxed.cpp
index 7327c317..16eb6e61 100644
--- a/gi/boxed.cpp
+++ b/gi/boxed.cpp
@@ -25,6 +25,7 @@
#include <jsapi.h> // for IdVector, JS_AtomizeAndPinJSString
#include <mozilla/HashTable.h>
+#include "gi/arg-cache.h"
#include "gi/arg-inl.h"
#include "gi/arg.h"
#include "gi/boxed.h"
@@ -45,7 +46,8 @@ BoxedInstance::BoxedInstance(JSContext* cx, JS::HandleObject obj)
GJS_INC_COUNTER(boxed_instance);
}
-[[nodiscard]] static bool struct_is_simple(GIStructInfo* info);
+[[nodiscard]] static bool struct_is_simple(
+ GIStructInfo* info, Gjs::DirectAllocationPolicy allocation_policy);
// See GIWrapperBase::resolve().
bool BoxedPrototype::resolve_impl(JSContext* cx, JS::HandleObject obj,
@@ -366,7 +368,8 @@ bool BoxedInstance::constructor_impl(JSContext* context, JS::HandleObject obj,
debug_lifecycle("Boxed pointer created from zero-args constructor");
- } else if (proto->can_allocate_directly()) {
+ } else if (proto->can_allocate_directly(
+ Gjs::DirectAllocationPolicy::NO_POINTERS)) {
allocate_directly();
} else if (proto->has_default_constructor()) {
/* for simplicity, we simply delegate all the work to the actual JS
@@ -391,6 +394,8 @@ bool BoxedInstance::constructor_impl(JSContext* context, JS::HandleObject obj,
"boxed object discarded");
return true;
+ } else if (get_prototype()->can_allocate_directly()) {
+ allocate_directly();
} else {
gjs_throw(context,
"Unable to construct struct type %s since it has no default "
@@ -476,7 +481,8 @@ bool BoxedInstance::get_nested_interface_object(
GIBaseInfo* interface_info, JS::MutableHandleValue value) const {
int offset;
- if (!struct_is_simple ((GIStructInfo *)interface_info)) {
+ if (!struct_is_simple(reinterpret_cast<GIStructInfo*>(interface_info),
+ Gjs::DirectAllocationPolicy::ALLOCATE_POINTERS)) {
gjs_throw(context, "Reading field %s.%s is not supported", name(),
g_base_info_get_name(field_info));
@@ -552,6 +558,31 @@ bool BoxedInstance::field_getter_impl(JSContext* cx, JSObject* obj,
return false;
}
+ if (g_type_info_get_tag(type_info) == GI_TYPE_TAG_ARRAY &&
+ g_type_info_get_array_length(type_info) != -1) {
+ auto length_field_ix = g_type_info_get_array_length(type_info);
+ GjsAutoFieldInfo length_field_info =
+ get_field_info(cx, length_field_ix);
+ if (!length_field_info) {
+ gjs_throw(cx, "Reading field %s.%s is not supported", name(),
+ g_base_info_get_name(length_field_info));
+ return false;
+ }
+
+ GIArgument length_arg;
+ if (!g_field_info_get_field(length_field_info, m_ptr, &length_arg)) {
+ gjs_throw(cx, "Reading field %s.%s is not supported", name(),
+ g_base_info_get_name(length_field_info));
+ return false;
+ }
+
+ GjsAutoTypeInfo length_type_info =
+ g_field_info_get_type(length_field_info);
+ size_t length = gjs_g_argument_get_array_length(
+ g_type_info_get_tag(length_type_info), &length_arg);
+ return gjs_value_from_explicit_array(cx, rval, type_info, &arg, length);
+ }
+
return gjs_value_from_g_argument(cx, rval, type_info, &arg, true);
}
@@ -573,7 +604,8 @@ bool BoxedInstance::set_nested_interface_object(JSContext* context,
JS::HandleValue value) {
int offset;
- if (!struct_is_simple ((GIStructInfo *)interface_info)) {
+ if (!struct_is_simple(reinterpret_cast<GIStructInfo*>(interface_info),
+ Gjs::DirectAllocationPolicy::ALLOCATE_POINTERS)) {
gjs_throw(context, "Writing field %s.%s is not supported", name(),
g_base_info_get_name(field_info));
@@ -749,7 +781,7 @@ const struct JSClass BoxedBase::klass = {
// clang-format on
[[nodiscard]] static bool type_can_be_allocated_directly(
- GITypeInfo* type_info) {
+ GITypeInfo* type_info, Gjs::DirectAllocationPolicy allocation_policy) {
bool is_simple = true;
if (g_type_info_is_pointer(type_info)) {
@@ -757,9 +789,13 @@ const struct JSClass BoxedBase::klass = {
g_type_info_get_array_type(type_info) == GI_ARRAY_TYPE_C) {
GjsAutoBaseInfo param_info =
g_type_info_get_param_type(type_info, 0);
- is_simple = type_can_be_allocated_directly(param_info);
+ is_simple =
+ type_can_be_allocated_directly(param_info, allocation_policy);
} else if (g_type_info_get_tag(type_info) == GI_TYPE_TAG_VOID) {
return true;
+ } else if (allocation_policy ==
+ Gjs::DirectAllocationPolicy::ALLOCATE_POINTERS) {
+ return true;
} else {
is_simple = false;
}
@@ -771,7 +807,9 @@ const struct JSClass BoxedBase::klass = {
switch (g_base_info_get_type(interface)) {
case GI_INFO_TYPE_BOXED:
case GI_INFO_TYPE_STRUCT:
- if (!struct_is_simple((GIStructInfo *)interface))
+ if (!struct_is_simple(
+ interface.as<GIStructInfo>(),
+ Gjs::DirectAllocationPolicy::ALLOCATE_POINTERS))
is_simple = false;
break;
case GI_INFO_TYPE_UNION:
@@ -836,7 +874,8 @@ const struct JSClass BoxedBase::klass = {
* type that we know how to assign to. If so, then we can allocate and free
* instances without needing a constructor.
*/
-[[nodiscard]] static bool struct_is_simple(GIStructInfo* info) {
+[[nodiscard]] static bool struct_is_simple(
+ GIStructInfo* info, Gjs::DirectAllocationPolicy allocation_policy) {
int n_fields = g_struct_info_get_n_fields(info);
bool is_simple = true;
int i;
@@ -849,7 +888,8 @@ const struct JSClass BoxedBase::klass = {
GjsAutoBaseInfo field_info = g_struct_info_get_field(info, i);
GjsAutoBaseInfo type_info = g_field_info_get_type(field_info);
- is_simple = type_can_be_allocated_directly(type_info);
+ is_simple =
+ type_can_be_allocated_directly(type_info, allocation_policy);
}
return is_simple;
@@ -860,7 +900,10 @@ BoxedPrototype::BoxedPrototype(GIStructInfo* info, GType gtype)
m_zero_args_constructor(-1),
m_default_constructor(-1),
m_default_constructor_name(JSID_VOID),
- m_can_allocate_directly(struct_is_simple(info)) {
+ m_can_allocate_directly(
+ struct_is_simple(info, Gjs::DirectAllocationPolicy::NO_POINTERS)),
+ m_can_allocate_directly_with_pointers(struct_is_simple(
+ info, Gjs::DirectAllocationPolicy::ALLOCATE_POINTERS)) {
GJS_INC_COUNTER(boxed_prototype);
}
diff --git a/gi/boxed.h b/gi/boxed.h
index 7c1cd49c..6287aea9 100644
--- a/gi/boxed.h
+++ b/gi/boxed.h
@@ -37,6 +37,13 @@ namespace js {
class SystemAllocPolicy;
}
+namespace Gjs {
+enum class DirectAllocationPolicy {
+ NO_POINTERS,
+ ALLOCATE_POINTERS,
+};
+};
+
/* To conserve memory, we have two different kinds of private data for GBoxed
* JS wrappers: BoxedInstance, and BoxedPrototype. Both inherit from BoxedBase
* for their common functionality. For more information, see the notes in
@@ -90,6 +97,7 @@ class BoxedPrototype : public GIWrapperPrototype<BoxedBase, BoxedPrototype,
JS::Heap<jsid> m_default_constructor_name;
std::unique_ptr<FieldMap> m_field_map;
bool m_can_allocate_directly : 1;
+ bool m_can_allocate_directly_with_pointers : 1;
explicit BoxedPrototype(GIStructInfo* info, GType gtype);
~BoxedPrototype(void);
@@ -101,8 +109,14 @@ class BoxedPrototype : public GIWrapperPrototype<BoxedBase, BoxedPrototype,
// Accessors
public:
- [[nodiscard]] bool can_allocate_directly() const {
- return m_can_allocate_directly;
+ [[nodiscard]] bool can_allocate_directly(
+ Gjs::DirectAllocationPolicy allocation_policy =
+ Gjs::DirectAllocationPolicy::ALLOCATE_POINTERS) const {
+ if (allocation_policy == Gjs::DirectAllocationPolicy::NO_POINTERS) {
+ return m_can_allocate_directly;
+ }
+
+ return m_can_allocate_directly_with_pointers;
}
[[nodiscard]] bool has_zero_args_constructor() const {
return m_zero_args_constructor >= 0;
diff --git a/installed-tests/js/testGObject.js b/installed-tests/js/testGObject.js
index 885a93fb..bdc1f6f4 100644
--- a/installed-tests/js/testGObject.js
+++ b/installed-tests/js/testGObject.js
@@ -20,7 +20,7 @@ describe('GObject overrides', function () {
Signals: {
test: {},
},
- }, class TestObj extends GObject.Object {});
+ }, class TestObj extends GObject.Object { });
it('GObject.set()', function () {
const o = new TestObj();
@@ -70,4 +70,13 @@ describe('GObject should', function () {
expect(gtype.name).toEqual(type);
});
});
+
+ it('be able to query signals', function () {
+ const query = GObject.signal_query(1);
+
+ expect(query instanceof GObject.SignalQuery).toBeTruthy();
+ expect(query.param_types).not.toBeNull();
+ expect(Array.isArray(query.param_types)).toBeTruthy();
+ expect(query.signal_id).toBe(1);
+ });
});