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: 2012 Red Hat, Inc.
4 : :
5 : : #include <config.h>
6 : :
7 : : #include <sstream>
8 : :
9 : : #include <girepository.h>
10 : : #include <glib-object.h>
11 : :
12 : : #include <js/TypeDecls.h>
13 : :
14 : : #include "gi/function.h"
15 : : #include "gi/wrapperutils.h"
16 : : #include "gjs/jsapi-util.h"
17 : :
18 : : /* Default spidermonkey toString is worthless. Replace it
19 : : * with something that gives us both the introspection name
20 : : * and a memory address.
21 : : */
22 : 186 : bool gjs_wrapper_to_string_func(JSContext* context, JSObject* this_obj,
23 : : const char* objtype, GIBaseInfo* info,
24 : : GType gtype, const void* native_address,
25 : : JS::MutableHandleValue rval) {
26 : 186 : std::ostringstream out;
27 : 186 : out << '[' << objtype;
28 [ + + ]: 186 : if (!native_address)
29 : 2 : out << " prototype of";
30 : : else
31 : 184 : out << " instance wrapper";
32 : :
33 [ + + ]: 186 : if (info) {
34 : : out << " GIName:" << g_base_info_get_namespace(info) << "."
35 : 157 : << g_base_info_get_name(info);
36 : : } else {
37 : 29 : out << " GType:" << g_type_name(gtype);
38 : : }
39 : :
40 : 186 : out << " jsobj@" << this_obj;
41 [ + + ]: 186 : if (native_address)
42 : 184 : out << " native@" << native_address;
43 : :
44 : 186 : out << ']';
45 : :
46 : 186 : return gjs_string_from_utf8(context, out.str().c_str(), rval);
47 : 186 : }
48 : :
49 : 2 : bool gjs_wrapper_throw_nonexistent_field(JSContext* cx, GType gtype,
50 : : const char* field_name) {
51 : 2 : gjs_throw(cx, "No property %s on %s", field_name, g_type_name(gtype));
52 : 2 : return false;
53 : : }
54 : :
55 : 2 : bool gjs_wrapper_throw_readonly_field(JSContext* cx, GType gtype,
56 : : const char* field_name) {
57 : 2 : gjs_throw(cx, "Property %s.%s is not writable", g_type_name(gtype),
58 : : field_name);
59 : 2 : return false;
60 : : }
61 : :
62 : : // These policies work around having separate g_foo_info_get_n_methods() and
63 : : // g_foo_info_get_method() functions for different GIInfoTypes. It's not
64 : : // possible to use GIFooInfo* as the template parameter, because the GIFooInfo
65 : : // structs are all typedefs of GIBaseInfo. It's also not possible to use the
66 : : // GIInfoType enum value as the template parameter, because GI_INFO_TYPE_BOXED
67 : : // could be either a GIStructInfo or GIUnionInfo.
68 : : template <typename InfoT>
69 : 742 : static inline GIStructInfo* no_type_struct(InfoT*) {
70 : 742 : return nullptr;
71 : : }
72 : :
73 : : template <InfoType::Tag TAG, typename InfoT = void,
74 : : int (*NMethods)(InfoT*) = nullptr,
75 : : GIFunctionInfo* (*Method)(InfoT*, int) = nullptr,
76 : : GIStructInfo* (*TypeStruct)(InfoT*) = &no_type_struct<InfoT>>
77 : : struct InfoMethodsPolicy {
78 : : static constexpr decltype(NMethods) n_methods = NMethods;
79 : : static constexpr decltype(Method) method = Method;
80 : : static constexpr decltype(TypeStruct) type_struct = TypeStruct;
81 : : };
82 : :
83 : : template <>
84 : : struct InfoMethodsPolicy<InfoType::Enum>
85 : : : InfoMethodsPolicy<InfoType::Enum, GIEnumInfo, &g_enum_info_get_n_methods,
86 : : &g_enum_info_get_method> {};
87 : : template <>
88 : : struct InfoMethodsPolicy<InfoType::Interface>
89 : : : InfoMethodsPolicy<
90 : : InfoType::Interface, GIInterfaceInfo, &g_interface_info_get_n_methods,
91 : : &g_interface_info_get_method, &g_interface_info_get_iface_struct> {};
92 : : template <>
93 : : struct InfoMethodsPolicy<InfoType::Object>
94 : : : InfoMethodsPolicy<InfoType::Object, GIObjectInfo,
95 : : &g_object_info_get_n_methods, &g_object_info_get_method,
96 : : &g_object_info_get_class_struct> {};
97 : : template <>
98 : : struct InfoMethodsPolicy<InfoType::Struct>
99 : : : InfoMethodsPolicy<InfoType::Struct, GIStructInfo,
100 : : &g_struct_info_get_n_methods,
101 : : &g_struct_info_get_method> {};
102 : : template <>
103 : : struct InfoMethodsPolicy<InfoType::Union>
104 : : : InfoMethodsPolicy<InfoType::Union, GIUnionInfo,
105 : : &g_union_info_get_n_methods, &g_union_info_get_method> {
106 : : };
107 : :
108 : : template <InfoType::Tag TAG>
109 : 1424 : bool gjs_define_static_methods(JSContext* cx, JS::HandleObject constructor,
110 : : GType gtype, GIBaseInfo* info) {
111 : 1424 : int n_methods = InfoMethodsPolicy<TAG>::n_methods(info);
112 : :
113 [ + - + + ]: 56900 : for (int ix = 0; ix < n_methods; ix++) {
114 : 27738 : GjsAutoFunctionInfo meth_info =
115 : : InfoMethodsPolicy<TAG>::method(info, ix);
116 : 27738 : GIFunctionInfoFlags flags = g_function_info_get_flags(meth_info);
117 : :
118 : : // Anything that isn't a method we put on the constructor. This
119 : : // includes <constructor> introspection methods, as well as static
120 : : // methods. We may want to change this to use
121 : : // GI_FUNCTION_IS_CONSTRUCTOR and GI_FUNCTION_IS_STATIC or the like
122 : : // in the future.
123 [ + + ]: 27738 : if (!(flags & GI_FUNCTION_IS_METHOD)) {
124 [ - + ]: 4629 : if (!gjs_define_function(cx, constructor, gtype, meth_info))
125 : 0 : return false;
126 : : }
127 : : }
128 : :
129 : : // Also define class/interface methods if there is a gtype struct
130 : :
131 : 1424 : GjsAutoStructInfo type_struct = InfoMethodsPolicy<TAG>::type_struct(info);
132 : : // Not an error for it to be null even in the case of Object and Interface;
133 : : // documentation says g_object_info_get_class_struct() and
134 : : // g_interface_info_get_iface_struct() can validly return a null pointer.
135 [ + + ]: 1424 : if (!type_struct)
136 : 847 : return true;
137 : :
138 : 577 : n_methods = g_struct_info_get_n_methods(type_struct);
139 : :
140 [ + - + + ]: 1489 : for (int ix = 0; ix < n_methods; ix++) {
141 : 456 : GjsAutoFunctionInfo meth_info =
142 : : g_struct_info_get_method(type_struct, ix);
143 : :
144 [ - + ]: 456 : if (!gjs_define_function(cx, constructor, gtype, meth_info))
145 : 0 : return false;
146 : : }
147 : :
148 : 577 : return true;
149 : 1424 : }
150 : :
151 : : // All possible instantiations are needed
152 : : template bool gjs_define_static_methods<InfoType::Enum>(
153 : : JSContext* cx, JS::HandleObject constructor, GType gtype, GIBaseInfo* info);
154 : : template bool gjs_define_static_methods<InfoType::Interface>(
155 : : JSContext* cx, JS::HandleObject constructor, GType gtype, GIBaseInfo* info);
156 : : template bool gjs_define_static_methods<InfoType::Object>(
157 : : JSContext* cx, JS::HandleObject constructor, GType gtype, GIBaseInfo* info);
158 : : template bool gjs_define_static_methods<InfoType::Struct>(
159 : : JSContext* cx, JS::HandleObject constructor, GType gtype, GIBaseInfo* info);
160 : : template bool gjs_define_static_methods<InfoType::Union>(
161 : : JSContext* cx, JS::HandleObject constructor, GType gtype, GIBaseInfo* info);
|