Branch data Line data Source code
1 : : /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 : : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
3 : : // SPDX-FileCopyrightText: 2008 litl, LLC
4 : : // SPDX-FileCopyrightText: 2018 Philip Chimento <philip.chimento@gmail.com>
5 : :
6 : : #include <config.h>
7 : :
8 : : #include <stdint.h>
9 : :
10 : : #include <glib-object.h>
11 : : #include <glib.h>
12 : :
13 : : #include <js/Array.h> // for JS::GetArrayLength,
14 : : #include <js/CallArgs.h>
15 : : #include <js/PropertyAndElement.h>
16 : : #include <js/PropertySpec.h>
17 : : #include <js/RootingAPI.h>
18 : : #include <js/TypeDecls.h>
19 : : #include <js/Utility.h> // for UniqueChars
20 : : #include <js/Value.h>
21 : : #include <js/ValueArray.h>
22 : : #include <jsapi.h> // for JS_NewPlainObject
23 : :
24 : : #include "gi/gobject.h"
25 : : #include "gi/gtype.h"
26 : : #include "gi/interface.h"
27 : : #include "gi/object.h"
28 : : #include "gi/param.h"
29 : : #include "gi/private.h"
30 : : #include "gi/repo.h"
31 : : #include "gjs/atoms.h"
32 : : #include "gjs/context-private.h"
33 : : #include "gjs/jsapi-util-args.h"
34 : : #include "gjs/jsapi-util.h"
35 : : #include "gjs/macros.h"
36 : :
37 : : /* gi/private.cpp - private "imports._gi" module with operations that we need
38 : : * to use from JS in order to create GObject classes, but should not be exposed
39 : : * to client code.
40 : : */
41 : :
42 : : GJS_JSAPI_RETURN_CONVENTION
43 : 25 : static bool gjs_override_property(JSContext* cx, unsigned argc, JS::Value* vp) {
44 : 25 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
45 : 25 : JS::UniqueChars name;
46 : 25 : JS::RootedObject type(cx);
47 : :
48 [ - + ]: 25 : if (!gjs_parse_call_args(cx, "override_property", args, "so", "name", &name,
49 : : "type", &type))
50 : 0 : return false;
51 : :
52 : : GType gtype;
53 [ - + ]: 25 : if (!gjs_gtype_get_actual_gtype(cx, type, >ype))
54 : 0 : return false;
55 [ - + ]: 25 : if (gtype == G_TYPE_INVALID) {
56 : 0 : gjs_throw(cx, "Invalid parameter type was not a GType");
57 : 0 : return false;
58 : : }
59 : :
60 : : GParamSpec* pspec;
61 [ + - + + : 25 : if (g_type_is_a(gtype, G_TYPE_INTERFACE)) {
+ + ]
62 : : auto* interface_type =
63 : 19 : static_cast<GTypeInterface*>(g_type_default_interface_ref(gtype));
64 : 19 : pspec = g_object_interface_find_property(interface_type, name.get());
65 : 19 : g_type_default_interface_unref(interface_type);
66 : : } else {
67 : 6 : GjsAutoTypeClass<GObjectClass> class_type(gtype);
68 : 6 : pspec = g_object_class_find_property(class_type, name.get());
69 : 6 : }
70 : :
71 [ + + ]: 25 : if (!pspec) {
72 : 2 : gjs_throw(cx, "No such property '%s' to override on type '%s'",
73 : : name.get(), g_type_name(gtype));
74 : 2 : return false;
75 : : }
76 : :
77 : 23 : GjsAutoParam new_pspec = g_param_spec_override(name.get(), pspec);
78 : :
79 : 23 : g_param_spec_set_qdata(new_pspec, ObjectBase::custom_property_quark(),
80 : : GINT_TO_POINTER(1));
81 : :
82 : 23 : args.rval().setObject(*gjs_param_from_g_param(cx, new_pspec));
83 : :
84 : 23 : return true;
85 : 25 : }
86 : :
87 : : GJS_JSAPI_RETURN_CONVENTION
88 : 121 : static bool validate_interfaces_and_properties_args(JSContext* cx,
89 : : JS::HandleObject interfaces,
90 : : JS::HandleObject properties,
91 : : uint32_t* n_interfaces,
92 : : uint32_t* n_properties) {
93 : : bool is_array;
94 [ - + ]: 121 : if (!JS::IsArrayObject(cx, interfaces, &is_array))
95 : 0 : return false;
96 [ - + ]: 121 : if (!is_array) {
97 : 0 : gjs_throw(cx, "Invalid parameter interfaces (expected Array)");
98 : 0 : return false;
99 : : }
100 : :
101 : : uint32_t n_int;
102 [ - + ]: 121 : if (!JS::GetArrayLength(cx, interfaces, &n_int))
103 : 0 : return false;
104 : :
105 [ - + ]: 121 : if (!JS::IsArrayObject(cx, properties, &is_array))
106 : 0 : return false;
107 [ - + ]: 121 : if (!is_array) {
108 : 0 : gjs_throw(cx, "Invalid parameter properties (expected Array)");
109 : 0 : return false;
110 : : }
111 : :
112 : : uint32_t n_prop;
113 [ - + ]: 121 : if (!JS::GetArrayLength(cx, properties, &n_prop))
114 : 0 : return false;
115 : :
116 [ + - ]: 121 : if (n_interfaces)
117 : 121 : *n_interfaces = n_int;
118 [ + - ]: 121 : if (n_properties)
119 : 121 : *n_properties = n_prop;
120 : 121 : return true;
121 : : }
122 : :
123 : : GJS_JSAPI_RETURN_CONVENTION
124 : 121 : static bool save_properties_for_class_init(JSContext* cx,
125 : : JS::HandleObject properties,
126 : : uint32_t n_properties, GType gtype) {
127 : 121 : AutoParamArray properties_native;
128 : 121 : JS::RootedValue prop_val(cx);
129 : 121 : JS::RootedObject prop_obj(cx);
130 [ + + ]: 189 : for (uint32_t i = 0; i < n_properties; i++) {
131 [ - + ]: 68 : if (!JS_GetElement(cx, properties, i, &prop_val))
132 : 0 : return false;
133 : :
134 [ - + ]: 68 : if (!prop_val.isObject()) {
135 : 0 : gjs_throw(cx, "Invalid parameter, expected object");
136 : 0 : return false;
137 : : }
138 : :
139 : 68 : prop_obj = &prop_val.toObject();
140 [ - + ]: 68 : if (!gjs_typecheck_param(cx, prop_obj, G_TYPE_NONE, true))
141 : 0 : return false;
142 : :
143 : 68 : properties_native.emplace_back(
144 : 68 : g_param_spec_ref(gjs_g_param_from_param(cx, prop_obj)));
145 : : }
146 : 121 : push_class_init_properties(gtype, &properties_native);
147 : 121 : return true;
148 : 121 : }
149 : :
150 : : GJS_JSAPI_RETURN_CONVENTION
151 : 121 : static bool get_interface_gtypes(JSContext* cx, JS::HandleObject interfaces,
152 : : uint32_t n_interfaces, GType* iface_types) {
153 [ + + ]: 171 : for (uint32_t ix = 0; ix < n_interfaces; ix++) {
154 : 50 : JS::RootedValue iface_val(cx);
155 [ - + ]: 50 : if (!JS_GetElement(cx, interfaces, ix, &iface_val))
156 : 0 : return false;
157 : :
158 [ - + ]: 50 : if (!iface_val.isObject()) {
159 : 0 : gjs_throw(
160 : : cx, "Invalid parameter interfaces (element %d was not a GType)",
161 : : ix);
162 : 0 : return false;
163 : : }
164 : :
165 : 50 : JS::RootedObject iface(cx, &iface_val.toObject());
166 : : GType iface_type;
167 [ - + ]: 50 : if (!gjs_gtype_get_actual_gtype(cx, iface, &iface_type))
168 : 0 : return false;
169 [ - + ]: 50 : if (iface_type == G_TYPE_INVALID) {
170 : 0 : gjs_throw(
171 : : cx, "Invalid parameter interfaces (element %d was not a GType)",
172 : : ix);
173 : 0 : return false;
174 : : }
175 : :
176 : 50 : iface_types[ix] = iface_type;
177 [ + - + - ]: 50 : }
178 : 121 : return true;
179 : : }
180 : :
181 : : GJS_JSAPI_RETURN_CONVENTION
182 : 89 : static bool create_wrapper_array(JSContext* cx, JS::HandleObject prototype,
183 : : GType type, JS::MutableHandleValue rval) {
184 : : JS::RootedObject gtype_wrapper(cx,
185 : 89 : gjs_gtype_create_gtype_wrapper(cx, type));
186 [ - + ]: 89 : if (!gtype_wrapper)
187 : 0 : return false;
188 : :
189 : 89 : JS::RootedValueArray<2> tuple(cx);
190 : 89 : tuple[0].setObject(*prototype);
191 : 89 : tuple[1].setObject(*gtype_wrapper);
192 : :
193 : 89 : JS::RootedObject array(cx, JS::NewArrayObject(cx, tuple));
194 [ - + ]: 89 : if (!array)
195 : 0 : return false;
196 : :
197 : 89 : rval.setObject(*array);
198 : 89 : return true;
199 : 89 : }
200 : :
201 : : GJS_JSAPI_RETURN_CONVENTION
202 : 9 : static bool gjs_register_interface_impl(JSContext* cx, const char* name,
203 : : JS::HandleObject interfaces,
204 : : JS::HandleObject properties,
205 : : GType* gtype) {
206 : : uint32_t n_interfaces, n_properties;
207 [ - + ]: 9 : if (!validate_interfaces_and_properties_args(cx, interfaces, properties,
208 : : &n_interfaces, &n_properties))
209 : 0 : return false;
210 : :
211 : 9 : GjsAutoPointer<GType> iface_types = g_new(GType, n_interfaces);
212 : :
213 : : /* We do interface addition in two passes so that any failure
214 : : is caught early, before registering the GType (which we can't undo) */
215 [ - + ]: 9 : if (!get_interface_gtypes(cx, interfaces, n_interfaces, iface_types))
216 : 0 : return false;
217 : :
218 [ - + ]: 9 : if (g_type_from_name(name) != G_TYPE_INVALID) {
219 : 0 : gjs_throw(cx, "Type name %s is already registered", name);
220 : 0 : return false;
221 : : }
222 : :
223 : 9 : GTypeInfo type_info = gjs_gobject_interface_info;
224 : 9 : GType interface_type = g_type_register_static(G_TYPE_INTERFACE, name,
225 : : &type_info, GTypeFlags(0));
226 : :
227 : 9 : g_type_set_qdata(interface_type, ObjectBase::custom_type_quark(),
228 : : GINT_TO_POINTER(1));
229 : :
230 [ - + ]: 9 : if (!save_properties_for_class_init(cx, properties, n_properties,
231 : : interface_type))
232 : 0 : return false;
233 : :
234 [ + + ]: 20 : for (uint32_t ix = 0; ix < n_interfaces; ix++)
235 : 11 : g_type_interface_add_prerequisite(interface_type, iface_types[ix]);
236 : :
237 : 9 : *gtype = interface_type;
238 : 9 : return true;
239 : 9 : }
240 : :
241 : : GJS_JSAPI_RETURN_CONVENTION
242 : 6 : static bool gjs_register_interface(JSContext* cx, unsigned argc,
243 : : JS::Value* vp) {
244 : 6 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
245 : :
246 : 6 : JS::UniqueChars name;
247 : 6 : JS::RootedObject interfaces(cx), properties(cx);
248 [ - + ]: 6 : if (!gjs_parse_call_args(cx, "register_interface", args, "soo", "name",
249 : : &name, "interfaces", &interfaces, "properties",
250 : : &properties))
251 : 0 : return false;
252 : :
253 : : GType interface_type;
254 [ - + ]: 6 : if (!gjs_register_interface_impl(cx, name.get(), interfaces, properties,
255 : : &interface_type))
256 : 0 : return false;
257 : :
258 : : /* create a custom JSClass */
259 : 6 : JS::RootedObject module(cx, gjs_lookup_private_namespace(cx));
260 [ - + ]: 6 : if (!module)
261 : 0 : return false; // error will have been thrown already
262 : :
263 : 6 : JS::RootedObject constructor(cx), ignored_prototype(cx);
264 [ - + ]: 6 : if (!InterfacePrototype::create_class(cx, module, nullptr, interface_type,
265 : : &constructor, &ignored_prototype))
266 : 0 : return false;
267 : :
268 : 6 : args.rval().setObject(*constructor);
269 : 6 : return true;
270 : 6 : }
271 : :
272 : : GJS_JSAPI_RETURN_CONVENTION
273 : 3 : static bool gjs_register_interface_with_class(JSContext* cx, unsigned argc,
274 : : JS::Value* vp) {
275 : 3 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
276 : :
277 : 3 : JS::UniqueChars name;
278 : 3 : JS::RootedObject klass(cx), interfaces(cx), properties(cx);
279 [ - + ]: 3 : if (!gjs_parse_call_args(cx, "register_interface_with_class", args, "osoo",
280 : : "class", &klass, "name", &name, "interfaces",
281 : : &interfaces, "properties", &properties))
282 : 0 : return false;
283 : :
284 : : GType interface_type;
285 [ - + ]: 3 : if (!gjs_register_interface_impl(cx, name.get(), interfaces, properties,
286 : : &interface_type))
287 : 0 : return false;
288 : :
289 : : /* create a custom JSClass */
290 : 3 : JS::RootedObject module(cx, gjs_lookup_private_namespace(cx));
291 [ - + ]: 3 : if (!module)
292 : 0 : return false; // error will have been thrown already
293 : :
294 : 3 : JS::RootedObject prototype(cx);
295 [ - + ]: 3 : if (!InterfacePrototype::wrap_class(cx, module, nullptr, interface_type,
296 : : klass, &prototype))
297 : 0 : return false;
298 : :
299 : 3 : return create_wrapper_array(cx, prototype, interface_type, args.rval());
300 : 3 : }
301 : :
302 : 39 : static inline void gjs_add_interface(GType instance_type,
303 : : GType interface_type) {
304 : : static GInterfaceInfo interface_vtable{nullptr, nullptr, nullptr};
305 : 39 : g_type_add_interface_static(instance_type, interface_type,
306 : : &interface_vtable);
307 : 39 : }
308 : :
309 : : GJS_JSAPI_RETURN_CONVENTION
310 : 113 : static bool gjs_register_type_impl(JSContext* cx, const char* name,
311 : : GTypeFlags type_flags,
312 : : JS::HandleObject parent,
313 : : JS::HandleObject interfaces,
314 : : JS::HandleObject properties,
315 : : GType** iface_types_out,
316 : : uint32_t* n_interfaces_out, GType* gtype) {
317 [ - + ]: 113 : if (!parent)
318 : 0 : return false;
319 : :
320 : : /* Don't pass the argv to it, as otherwise we will log about the callee
321 : : * while we only care about the parent object type. */
322 : : ObjectBase* parent_priv;
323 [ + + ]: 113 : if (!ObjectBase::for_js_typecheck(cx, parent, &parent_priv))
324 : 1 : return false;
325 : :
326 : : uint32_t n_interfaces, n_properties;
327 [ - + ]: 112 : if (!validate_interfaces_and_properties_args(cx, interfaces, properties,
328 : : &n_interfaces, &n_properties))
329 : 0 : return false;
330 : :
331 : 112 : GjsAutoPointer<GType> iface_types = g_new(GType, n_interfaces);
332 : :
333 : : /* We do interface addition in two passes so that any failure
334 : : is caught early, before registering the GType (which we can't undo) */
335 [ - + ]: 112 : if (!get_interface_gtypes(cx, interfaces, n_interfaces, iface_types))
336 : 0 : return false;
337 : :
338 [ - + ]: 112 : if (g_type_from_name(name) != G_TYPE_INVALID) {
339 : 0 : gjs_throw(cx, "Type name %s is already registered", name);
340 : 0 : return false;
341 : : }
342 : :
343 : : /* We checked parent above, in ObjectBase::for_js_typecheck() */
344 : 112 : g_assert(parent_priv);
345 : :
346 : : GTypeQuery query;
347 : 112 : parent_priv->type_query_dynamic_safe(&query);
348 [ - + ]: 112 : if (G_UNLIKELY(query.type == 0)) {
349 : 0 : gjs_throw(cx,
350 : : "Cannot inherit from a non-gjs dynamic type [bug 687184]");
351 : 0 : return false;
352 : : }
353 : :
354 : 112 : GTypeInfo type_info = gjs_gobject_class_info;
355 : 112 : type_info.class_size = query.class_size;
356 : 112 : type_info.instance_size = query.instance_size;
357 : :
358 : 112 : GType instance_type = g_type_register_static(parent_priv->gtype(), name,
359 : : &type_info, type_flags);
360 : :
361 : 112 : g_type_set_qdata(instance_type, ObjectBase::custom_type_quark(),
362 : : GINT_TO_POINTER(1));
363 : :
364 [ - + ]: 112 : if (!save_properties_for_class_init(cx, properties, n_properties,
365 : : instance_type))
366 : 0 : return false;
367 : :
368 [ + + ]: 151 : for (uint32_t ix = 0; ix < n_interfaces; ix++)
369 : 39 : gjs_add_interface(instance_type, iface_types[ix]);
370 : :
371 : 112 : *gtype = instance_type;
372 : 112 : *n_interfaces_out = n_interfaces;
373 : 112 : *iface_types_out = iface_types.release();
374 : 112 : return true;
375 : 112 : }
376 : :
377 : : GJS_JSAPI_RETURN_CONVENTION
378 : 26 : static bool gjs_register_type(JSContext* cx, unsigned argc, JS::Value* vp) {
379 : 26 : JS::CallArgs argv = JS::CallArgsFromVp(argc, vp);
380 : :
381 : 26 : JS::UniqueChars name;
382 : : GTypeFlags type_flags;
383 : 26 : JS::RootedObject parent(cx), interfaces(cx), properties(cx);
384 [ - + ]: 26 : if (!gjs_parse_call_args(cx, "register_type", argv, "osioo", "parent",
385 : : &parent, "name", &name, "flags", &type_flags,
386 : : "interfaces", &interfaces, "properties",
387 : : &properties))
388 : 0 : return false;
389 : :
390 : : GType instance_type;
391 : 26 : GjsAutoPointer<GType> iface_types;
392 : : uint32_t n_interfaces;
393 [ - + ]: 26 : if (!gjs_register_type_impl(cx, name.get(), type_flags, parent, interfaces,
394 : : properties, iface_types.out(), &n_interfaces,
395 : : &instance_type))
396 : 0 : return false;
397 : :
398 : : /* create a custom JSClass */
399 : 26 : JS::RootedObject module(cx, gjs_lookup_private_namespace(cx));
400 : 26 : JS::RootedObject constructor(cx), prototype(cx);
401 [ - + ]: 26 : if (!ObjectPrototype::define_class(cx, module, nullptr, instance_type,
402 : : iface_types, n_interfaces, &constructor,
403 : : &prototype))
404 : 0 : return false;
405 : :
406 : 26 : auto* priv = ObjectPrototype::for_js(cx, prototype);
407 : 26 : priv->set_type_qdata();
408 : :
409 : 26 : argv.rval().setObject(*constructor);
410 : :
411 : 26 : return true;
412 : 26 : }
413 : :
414 : : GJS_JSAPI_RETURN_CONVENTION
415 : 87 : static bool gjs_register_type_with_class(JSContext* cx, unsigned argc,
416 : : JS::Value* vp) {
417 : 87 : JS::CallArgs argv = JS::CallArgsFromVp(argc, vp);
418 : :
419 : 87 : JS::UniqueChars name;
420 : : GTypeFlags type_flags;
421 : 87 : JS::RootedObject klass(cx), parent(cx), interfaces(cx), properties(cx);
422 [ - + ]: 87 : if (!gjs_parse_call_args(cx, "register_type_with_class", argv, "oosioo",
423 : : "class", &klass, "parent", &parent, "name", &name,
424 : : "flags", &type_flags, "interfaces", &interfaces,
425 : : "properties", &properties))
426 : 0 : return false;
427 : :
428 : : GType instance_type;
429 : : uint32_t n_interfaces;
430 : 87 : GjsAutoPointer<GType> iface_types;
431 [ + + ]: 87 : if (!gjs_register_type_impl(cx, name.get(), type_flags, parent, interfaces,
432 : : properties, iface_types.out(), &n_interfaces,
433 : : &instance_type))
434 : 1 : return false;
435 : :
436 : : // create a custom JSClass
437 : 86 : JS::RootedObject module(cx, gjs_lookup_private_namespace(cx));
438 [ - + ]: 86 : if (!module)
439 : 0 : return false;
440 : :
441 : 86 : JS::RootedObject prototype(cx);
442 : 86 : ObjectPrototype* priv = ObjectPrototype::wrap_class(
443 : : cx, module, nullptr, instance_type, klass, &prototype);
444 [ - + ]: 86 : if (!priv)
445 : 0 : return false;
446 : :
447 : 86 : priv->set_interfaces(iface_types, n_interfaces);
448 : 86 : priv->set_type_qdata();
449 : :
450 : 86 : return create_wrapper_array(cx, prototype, instance_type, argv.rval());
451 : 87 : }
452 : :
453 : : GJS_JSAPI_RETURN_CONVENTION
454 : 33 : static bool gjs_signal_new(JSContext* cx, unsigned argc, JS::Value* vp) {
455 : 33 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
456 : :
457 : 33 : JS::UniqueChars signal_name;
458 : : int32_t flags, accumulator_enum;
459 : 33 : JS::RootedObject gtype_obj(cx), return_gtype_obj(cx), params_obj(cx);
460 [ - + ]: 33 : if (!gjs_parse_call_args(cx, "signal_new", args, "osiioo", "gtype",
461 : : >ype_obj, "signal name", &signal_name, "flags",
462 : : &flags, "accumulator", &accumulator_enum,
463 : : "return gtype", &return_gtype_obj, "params",
464 : : ¶ms_obj))
465 : 0 : return false;
466 : :
467 : : /* we only support standard accumulators for now */
468 : : GSignalAccumulator accumulator;
469 [ + - + ]: 33 : switch (accumulator_enum) {
470 : 4 : case 1:
471 : 4 : accumulator = g_signal_accumulator_first_wins;
472 : 4 : break;
473 : 0 : case 2:
474 : 0 : accumulator = g_signal_accumulator_true_handled;
475 : 0 : break;
476 : 29 : case 0:
477 : : default:
478 : 29 : accumulator = nullptr;
479 : : }
480 : :
481 : : GType return_type;
482 [ - + ]: 33 : if (!gjs_gtype_get_actual_gtype(cx, return_gtype_obj, &return_type))
483 : 0 : return false;
484 : :
485 [ - + ]: 33 : if (accumulator == g_signal_accumulator_true_handled &&
486 [ # # ]: 0 : return_type != G_TYPE_BOOLEAN) {
487 : 0 : gjs_throw(cx,
488 : : "GObject.SignalAccumulator.TRUE_HANDLED can only be used "
489 : : "with boolean signals");
490 : 0 : return false;
491 : : }
492 : :
493 : : uint32_t n_parameters;
494 [ - + ]: 33 : if (!JS::GetArrayLength(cx, params_obj, &n_parameters))
495 : 0 : return false;
496 : :
497 : 66 : GjsAutoPointer<GType> params = g_new(GType, n_parameters);
498 : 66 : JS::RootedValue gtype_val(cx);
499 [ + + ]: 53 : for (uint32_t ix = 0; ix < n_parameters; ix++) {
500 [ + - - + ]: 40 : if (!JS_GetElement(cx, params_obj, ix, >ype_val) ||
501 [ - + ]: 20 : !gtype_val.isObject()) {
502 : 0 : gjs_throw(cx, "Invalid signal parameter number %d", ix);
503 : 0 : return false;
504 : : }
505 : :
506 : 20 : JS::RootedObject gjs_gtype(cx, >ype_val.toObject());
507 [ - + ]: 20 : if (!gjs_gtype_get_actual_gtype(cx, gjs_gtype, ¶ms[ix]))
508 : 0 : return false;
509 [ + - ]: 20 : }
510 : :
511 : : GType gtype;
512 [ - + ]: 33 : if (!gjs_gtype_get_actual_gtype(cx, gtype_obj, >ype))
513 : 0 : return false;
514 : :
515 : 66 : unsigned signal_id = g_signal_newv(
516 : 33 : signal_name.get(), gtype, GSignalFlags(flags),
517 : : /* class closure */ nullptr, accumulator, /* accu_data */ nullptr,
518 : : /* c_marshaller */ nullptr, return_type, n_parameters, params);
519 : :
520 : : // FIXME: what if ID is greater than int32 max?
521 : 33 : args.rval().setInt32(signal_id);
522 : 33 : return true;
523 : 33 : }
524 : :
525 : : GJS_JSAPI_RETURN_CONVENTION
526 : 11 : static bool gjs_lookup_constructor(JSContext* cx, unsigned argc,
527 : : JS::Value* vp) {
528 : 11 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
529 : :
530 : 11 : JS::RootedObject gtype_obj(cx);
531 [ - + ]: 11 : if (!gjs_parse_call_args(cx, "lookupConstructor", args, "o", "gtype",
532 : : >ype_obj))
533 : 0 : return false;
534 : :
535 : : GType gtype;
536 [ - + ]: 11 : if (!gjs_gtype_get_actual_gtype(cx, gtype_obj, >ype))
537 : 0 : return false;
538 : :
539 [ - + ]: 11 : if (gtype == G_TYPE_NONE) {
540 : 0 : gjs_throw(cx, "Invalid GType for constructor lookup");
541 : 0 : return false;
542 : : }
543 : :
544 : 11 : return gjs_lookup_object_constructor(cx, gtype, args.rval());
545 : 11 : }
546 : :
547 : : template <GjsSymbolAtom GjsAtoms::*member>
548 : 268 : GJS_JSAPI_RETURN_CONVENTION static bool symbol_getter(JSContext* cx,
549 : : unsigned argc,
550 : : JS::Value* vp) {
551 : 268 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
552 : 268 : const GjsAtoms& atoms = GjsContextPrivate::atoms(cx);
553 : 268 : args.rval().setSymbol((atoms.*member)().toSymbol());
554 : 268 : return true;
555 : : }
556 : :
557 : : static JSFunctionSpec private_module_funcs[] = {
558 : : JS_FN("override_property", gjs_override_property, 2, GJS_MODULE_PROP_FLAGS),
559 : : JS_FN("register_interface", gjs_register_interface, 3,
560 : : GJS_MODULE_PROP_FLAGS),
561 : : JS_FN("register_interface_with_class", gjs_register_interface_with_class, 4,
562 : : GJS_MODULE_PROP_FLAGS),
563 : : JS_FN("register_type", gjs_register_type, 4, GJS_MODULE_PROP_FLAGS),
564 : : JS_FN("register_type_with_class", gjs_register_type_with_class, 5,
565 : : GJS_MODULE_PROP_FLAGS),
566 : : JS_FN("signal_new", gjs_signal_new, 6, GJS_MODULE_PROP_FLAGS),
567 : : JS_FN("lookupConstructor", gjs_lookup_constructor, 1, 0),
568 : : JS_FS_END,
569 : : };
570 : :
571 : : static JSPropertySpec private_module_props[] = {
572 : : JS_PSG("gobject_prototype_symbol",
573 : : symbol_getter<&GjsAtoms::gobject_prototype>, GJS_MODULE_PROP_FLAGS),
574 : : JS_PSG("hook_up_vfunc_symbol", symbol_getter<&GjsAtoms::hook_up_vfunc>,
575 : : GJS_MODULE_PROP_FLAGS),
576 : : JS_PSG("signal_find_symbol", symbol_getter<&GjsAtoms::signal_find>,
577 : : GJS_MODULE_PROP_FLAGS),
578 : : JS_PSG("signals_block_symbol", symbol_getter<&GjsAtoms::signals_block>,
579 : : GJS_MODULE_PROP_FLAGS),
580 : : JS_PSG("signals_unblock_symbol", symbol_getter<&GjsAtoms::signals_unblock>,
581 : : GJS_MODULE_PROP_FLAGS),
582 : : JS_PSG("signals_disconnect_symbol",
583 : : symbol_getter<&GjsAtoms::signals_disconnect>, GJS_MODULE_PROP_FLAGS),
584 : : JS_PS_END};
585 : :
586 : 57 : bool gjs_define_private_gi_stuff(JSContext* cx,
587 : : JS::MutableHandleObject module) {
588 : 57 : module.set(JS_NewPlainObject(cx));
589 [ + - + - ]: 114 : return JS_DefineFunctions(cx, module, private_module_funcs) &&
590 : 114 : JS_DefineProperties(cx, module, private_module_props);
591 : : }
|