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