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: 2010 litl, LLC
4 : :
5 : : #include <config.h>
6 : :
7 : : #include <string.h> // for strcmp
8 : : #include <string>
9 : :
10 : : #include <girepository.h>
11 : : #include <glib.h>
12 : :
13 : : #include <js/TypeDecls.h>
14 : :
15 : : #include "gi/foreign.h"
16 : : #include "gjs/context-private.h"
17 : : #include "gjs/jsapi-util.h"
18 : :
19 : : static struct {
20 : : const char* gi_namespace;
21 : : bool loaded;
22 : : } foreign_modules[] = {
23 : : // clang-format off
24 : : {"cairo", false},
25 : : {nullptr}
26 : : // clang-format on
27 : : };
28 : :
29 : : static GHashTable* foreign_structs_table = NULL;
30 : :
31 : 22 : [[nodiscard]] static GHashTable* get_foreign_structs() {
32 : : // FIXME: look into hasing on GITypeInfo instead.
33 [ + + ]: 22 : if (!foreign_structs_table) {
34 : 2 : foreign_structs_table = g_hash_table_new_full(g_str_hash, g_str_equal,
35 : : (GDestroyNotify)g_free,
36 : : NULL);
37 : : }
38 : :
39 : 22 : return foreign_structs_table;
40 : : }
41 : :
42 : 0 : [[nodiscard]] static bool gjs_foreign_load_foreign_module(
43 : : JSContext* context, const char* gi_namespace) {
44 : : int i;
45 : :
46 [ # # ]: 0 : for (i = 0; foreign_modules[i].gi_namespace; ++i) {
47 [ # # ]: 0 : if (strcmp(gi_namespace, foreign_modules[i].gi_namespace) != 0)
48 : 0 : continue;
49 : :
50 [ # # ]: 0 : if (foreign_modules[i].loaded)
51 : 0 : return true;
52 : :
53 : : // FIXME: Find a way to check if a module is imported
54 : : // and only execute this statement if isn't
55 : 0 : std::string script = "imports." + std::string(gi_namespace) + ';';
56 : 0 : JS::RootedValue retval(context);
57 : 0 : GjsContextPrivate* gjs = GjsContextPrivate::from_cx(context);
58 [ # # ]: 0 : if (!gjs->eval_with_scope(nullptr, script.c_str(), script.length(),
59 : : "<internal>", &retval)) {
60 : 0 : g_critical("ERROR importing foreign module %s\n", gi_namespace);
61 : 0 : return false;
62 : : }
63 : 0 : foreign_modules[i].loaded = true;
64 : 0 : return true;
65 : 0 : }
66 : :
67 : 0 : return false;
68 : : }
69 : :
70 : 6 : void gjs_struct_foreign_register(const char* gi_namespace,
71 : : const char* type_name, GjsForeignInfo* info) {
72 : : char *canonical_name;
73 : :
74 : 6 : g_return_if_fail(info);
75 : 6 : g_return_if_fail(info->to_func);
76 : 6 : g_return_if_fail(info->from_func);
77 : :
78 : 6 : canonical_name = g_strdup_printf("%s.%s", gi_namespace, type_name);
79 : 6 : g_hash_table_insert(get_foreign_structs(), canonical_name, info);
80 : : }
81 : :
82 : 16 : [[nodiscard]] static GjsForeignInfo* gjs_struct_foreign_lookup(
83 : : JSContext* context, GIBaseInfo* interface_info) {
84 : : GHashTable* hash_table;
85 : :
86 : 32 : auto key = std::string(g_base_info_get_namespace(interface_info)) + '.' +
87 : 32 : g_base_info_get_name(interface_info);
88 : 16 : hash_table = get_foreign_structs();
89 : : auto* retval = static_cast<GjsForeignInfo*>(
90 : 16 : g_hash_table_lookup(hash_table, key.c_str()));
91 [ - + ]: 16 : if (!retval) {
92 [ # # ]: 0 : if (gjs_foreign_load_foreign_module(context, g_base_info_get_namespace(interface_info))) {
93 : : retval = static_cast<GjsForeignInfo*>(
94 : 0 : g_hash_table_lookup(hash_table, key.c_str()));
95 : : }
96 : : }
97 : :
98 [ - + ]: 16 : if (!retval) {
99 : 0 : gjs_throw(context, "Unable to find module implementing foreign type %s",
100 : : key.c_str());
101 : : }
102 : :
103 : 32 : return retval;
104 : 16 : }
105 : :
106 : 4 : bool gjs_struct_foreign_convert_to_g_argument(
107 : : JSContext* context, JS::Value value, GIBaseInfo* interface_info,
108 : : const char* arg_name, GjsArgumentType argument_type, GITransfer transfer,
109 : : GjsArgumentFlags flags, GArgument* arg) {
110 : : GjsForeignInfo *foreign;
111 : :
112 : 4 : foreign = gjs_struct_foreign_lookup(context, interface_info);
113 [ - + ]: 4 : if (!foreign)
114 : 0 : return false;
115 : :
116 [ - + ]: 4 : if (!foreign->to_func(context, value, arg_name, argument_type, transfer,
117 : : flags, arg))
118 : 0 : return false;
119 : :
120 : 4 : return true;
121 : : }
122 : :
123 : : bool
124 : 6 : gjs_struct_foreign_convert_from_g_argument(JSContext *context,
125 : : JS::MutableHandleValue value_p,
126 : : GIBaseInfo *interface_info,
127 : : GIArgument *arg)
128 : : {
129 : : GjsForeignInfo *foreign;
130 : :
131 : 6 : foreign = gjs_struct_foreign_lookup(context, interface_info);
132 [ - + ]: 6 : if (!foreign)
133 : 0 : return false;
134 : :
135 [ - + ]: 6 : if (!foreign->from_func(context, value_p, arg))
136 : 0 : return false;
137 : :
138 : 6 : return true;
139 : : }
140 : :
141 : : bool
142 : 6 : gjs_struct_foreign_release_g_argument(JSContext *context,
143 : : GITransfer transfer,
144 : : GIBaseInfo *interface_info,
145 : : GArgument *arg)
146 : : {
147 : : GjsForeignInfo *foreign;
148 : :
149 : 6 : foreign = gjs_struct_foreign_lookup(context, interface_info);
150 [ - + ]: 6 : if (!foreign)
151 : 0 : return false;
152 : :
153 [ - + ]: 6 : if (!foreign->release_func)
154 : 0 : return true;
155 : :
156 [ - + ]: 6 : if (!foreign->release_func(context, transfer, arg))
157 : 0 : return false;
158 : :
159 : 6 : return true;
160 : : }
161 : :
|