node-gtk 2.2.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -161
- package/bin/node-gtk.js +12 -1
- package/binding.gyp +21 -0
- package/lib/binding/node-v127-linux-x64/node_gtk.node +0 -0
- package/lib/bootstrap.js +43 -11
- package/lib/esm/hooks.mjs +49 -0
- package/lib/esm/register.mjs +17 -0
- package/lib/index.js +1 -2
- package/lib/index.mjs +25 -0
- package/lib/inspect.js +1 -1
- package/lib/loop.js +5 -0
- package/lib/module.js +8 -2
- package/lib/overrides/Gtk-4.0.js +6 -27
- package/lib/register-class.js +86 -3
- package/lib/styles.d.ts +81 -0
- package/lib/styles.js +428 -0
- package/package.json +15 -2
- package/src/boxed.cc +13 -5
- package/src/closure.cc +19 -6
- package/src/closure.h +8 -4
- package/src/function.cc +59 -5
- package/src/fundamental.cc +451 -0
- package/src/fundamental.h +71 -0
- package/src/gi.cc +21 -1
- package/src/gobject.cc +268 -9
- package/src/gobject.h +5 -0
- package/src/modules/cairo/context.cc +103 -103
- package/src/modules/cairo/font-extents.cc +6 -2
- package/src/modules/cairo/generator.js +1 -1
- package/src/modules/cairo/glyph.cc +6 -2
- package/src/modules/cairo/path.cc +6 -2
- package/src/modules/cairo/rectangle-int.cc +6 -2
- package/src/modules/cairo/rectangle.cc +6 -2
- package/src/modules/cairo/text-cluster.cc +6 -2
- package/src/modules/cairo/text-extents.cc +6 -2
- package/src/modules/system.cc +4 -4
- package/src/util.h +3 -3
- package/src/value.cc +44 -8
- package/src/value.h +2 -2
- package/tools/README.md +52 -2
- package/tools/create-app.js +246 -0
- package/tools/generate-types.js +80 -3
- package/tools/list-libraries.js +125 -0
- package/tools/templates/app/README.md.tmpl +97 -0
- package/tools/templates/app/gitignore.tmpl +10 -0
- package/tools/templates/app/package.json.tmpl +26 -0
- package/tools/templates/app/src/main.ts.tmpl +110 -0
- package/tools/templates/app/src/welcome.ts.tmpl +41 -0
- package/tools/templates/app/style.css.tmpl +19 -0
- package/tools/templates/app/tsconfig.json.tmpl +19 -0
- /package/{COPYING → LICENSE} +0 -0
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* fundamental.cc
|
|
3
|
+
*
|
|
4
|
+
* See fundamental.h. Wraps fundamental (non-GObject) ref-counted types such as
|
|
5
|
+
* GskRenderNode. The wrapper owns exactly one reference (taken via the type's
|
|
6
|
+
* introspected ref function, or adopted from a transfer-full return) and drops
|
|
7
|
+
* it on garbage collection via the unref function. Unlike GObject wrappers this
|
|
8
|
+
* uses no toggle-ref / qdata / weak-ref machinery — a fundamental type is not a
|
|
9
|
+
* GObject and those calls would fail their G_IS_OBJECT assertions (#468).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
#include <girepository.h>
|
|
13
|
+
#include <glib.h>
|
|
14
|
+
|
|
15
|
+
#include "fundamental.h"
|
|
16
|
+
#include "gi.h"
|
|
17
|
+
#include "macros.h"
|
|
18
|
+
#include "util.h"
|
|
19
|
+
#include "value.h"
|
|
20
|
+
|
|
21
|
+
using v8::External;
|
|
22
|
+
using v8::FunctionTemplate;
|
|
23
|
+
using v8::Isolate;
|
|
24
|
+
using v8::Object;
|
|
25
|
+
using Nan::New;
|
|
26
|
+
using Nan::Persistent;
|
|
27
|
+
using Nan::WeakCallbackType;
|
|
28
|
+
|
|
29
|
+
namespace GNodeJS {
|
|
30
|
+
|
|
31
|
+
/* Per-instance bookkeeping so the GC weak callback can drop our reference. */
|
|
32
|
+
struct FundamentalInstance {
|
|
33
|
+
void *data;
|
|
34
|
+
GIObjectInfoUnrefFunction unref;
|
|
35
|
+
Persistent<Object> *persistent;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
bool IsFundamentalObjectInfo (GIObjectInfo *info) {
|
|
39
|
+
if (g_base_info_get_type (info) != GI_INFO_TYPE_OBJECT)
|
|
40
|
+
return false;
|
|
41
|
+
if (!g_object_info_get_fundamental (info))
|
|
42
|
+
return false;
|
|
43
|
+
|
|
44
|
+
/* GParamSpec is also a fundamental (non-GObject) type, but it has its own
|
|
45
|
+
* dedicated wrapper (param_spec.cc) that predates this one and is used by
|
|
46
|
+
* the value.cc / V8ToGIArgumentInterface param paths; keep it on that
|
|
47
|
+
* path rather than diverting it here. */
|
|
48
|
+
GType gtype = g_registered_type_info_get_g_type (info);
|
|
49
|
+
if (g_type_is_a (gtype, G_TYPE_PARAM))
|
|
50
|
+
return false;
|
|
51
|
+
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/*
|
|
56
|
+
* The ref/unref functions are declared on the root fundamental type (e.g.
|
|
57
|
+
* GskRenderNode) and are not repeated on derived infos (GskColorNode), so walk
|
|
58
|
+
* up the parent chain until we find them.
|
|
59
|
+
*/
|
|
60
|
+
static void GetRefFunctions (GIObjectInfo *info,
|
|
61
|
+
GIObjectInfoRefFunction *refOut,
|
|
62
|
+
GIObjectInfoUnrefFunction *unrefOut) {
|
|
63
|
+
*refOut = NULL;
|
|
64
|
+
*unrefOut = NULL;
|
|
65
|
+
|
|
66
|
+
GIObjectInfo *current = g_base_info_ref (info);
|
|
67
|
+
while (current != NULL) {
|
|
68
|
+
auto ref = g_object_info_get_ref_function_pointer (current);
|
|
69
|
+
auto unref = g_object_info_get_unref_function_pointer (current);
|
|
70
|
+
if (ref != NULL || unref != NULL) {
|
|
71
|
+
*refOut = ref;
|
|
72
|
+
*unrefOut = unref;
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
GIObjectInfo *parent = g_object_info_get_parent (current);
|
|
76
|
+
g_base_info_unref (current);
|
|
77
|
+
current = parent;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (current != NULL)
|
|
81
|
+
g_base_info_unref (current);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
void RefFundamentalForTransferFullIn (GITypeInfo *type_info, GIArgument *arg) {
|
|
85
|
+
if (arg->v_pointer == NULL)
|
|
86
|
+
return;
|
|
87
|
+
|
|
88
|
+
if (g_type_info_get_tag (type_info) != GI_TYPE_TAG_INTERFACE)
|
|
89
|
+
return;
|
|
90
|
+
|
|
91
|
+
GIBaseInfo *iface = g_type_info_get_interface (type_info);
|
|
92
|
+
|
|
93
|
+
/* The callee takes ownership of one reference (transfer-full). The JS
|
|
94
|
+
* wrapper keeps its own single reference and drops it on GC, so without an
|
|
95
|
+
* extra reference here the object would be finalized out from under the
|
|
96
|
+
* callee. This is the fundamental counterpart of RefObjectForTransferFullIn
|
|
97
|
+
* (GObjects, #439) and CopyBoxedForTransferFullIn (boxed, #409). */
|
|
98
|
+
if (IsFundamentalObjectInfo (iface)) {
|
|
99
|
+
GIObjectInfoRefFunction ref;
|
|
100
|
+
GIObjectInfoUnrefFunction unref;
|
|
101
|
+
GetRefFunctions (iface, &ref, &unref);
|
|
102
|
+
if (ref != NULL)
|
|
103
|
+
ref (arg->v_pointer);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
g_base_info_unref (iface);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
static void FundamentalDestroyed (const Nan::WeakCallbackInfo<FundamentalInstance> &info) {
|
|
110
|
+
FundamentalInstance *self = info.GetParameter ();
|
|
111
|
+
|
|
112
|
+
if (self->data != NULL && self->unref != NULL)
|
|
113
|
+
self->unref (self->data);
|
|
114
|
+
|
|
115
|
+
/* Nan's kParameter weak callback already Reset()s the handle in its first
|
|
116
|
+
* pass (nan_weak.h); calling Reset() again here would double-destroy the
|
|
117
|
+
* global handle (V8 "IsInUse" fatal). Just free our bookkeeping, matching
|
|
118
|
+
* BoxedDestroyed. */
|
|
119
|
+
delete self->persistent;
|
|
120
|
+
delete self;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
static void FundamentalConstructor (const Nan::FunctionCallbackInfo<Value> &info) {
|
|
124
|
+
if (!info.IsConstructCall ()) {
|
|
125
|
+
Nan::ThrowTypeError ("Not a construct call");
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
Local<Object> self = info.This ();
|
|
130
|
+
GIObjectInfo *gi_info = (GIObjectInfo *) External::Cast (*info.Data ())->Value ();
|
|
131
|
+
GType gtype = g_registered_type_info_get_g_type (gi_info);
|
|
132
|
+
|
|
133
|
+
if (!info[0]->IsExternal ()) {
|
|
134
|
+
/* Fundamental types can't be created with g_object_new; they are
|
|
135
|
+
* obtained from function returns or their static constructors
|
|
136
|
+
* (e.g. `Gsk.ColorNode.new(...)`). */
|
|
137
|
+
char *message = g_strdup_printf (
|
|
138
|
+
"Cannot construct fundamental type %s directly; use its static constructor (e.g. .new())",
|
|
139
|
+
g_type_name (gtype));
|
|
140
|
+
Nan::ThrowError (message);
|
|
141
|
+
g_free (message);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
void *ptr = External::Cast (*info[0])->Value ();
|
|
146
|
+
auto ownership = (ResourceOwnership) Nan::To<int32_t> (info[1]).ToChecked ();
|
|
147
|
+
|
|
148
|
+
GIObjectInfoRefFunction ref;
|
|
149
|
+
GIObjectInfoUnrefFunction unref;
|
|
150
|
+
GetRefFunctions (gi_info, &ref, &unref);
|
|
151
|
+
|
|
152
|
+
/* Own exactly one reference for the lifetime of the wrapper. A
|
|
153
|
+
* transfer-full return (kTransfer) already handed us one; otherwise add our
|
|
154
|
+
* own so the instance stays alive while JS holds the wrapper. */
|
|
155
|
+
if (ownership != kTransfer && ref != NULL)
|
|
156
|
+
ptr = ref (ptr);
|
|
157
|
+
|
|
158
|
+
FundamentalInstance *instance = new FundamentalInstance ();
|
|
159
|
+
instance->data = ptr;
|
|
160
|
+
instance->unref = unref;
|
|
161
|
+
instance->persistent = new Persistent<Object> (self);
|
|
162
|
+
instance->persistent->SetWeak (instance, FundamentalDestroyed, WeakCallbackType::kParameter);
|
|
163
|
+
|
|
164
|
+
Nan::SetInternalFieldPointer (self, 0, ptr);
|
|
165
|
+
SET_OBJECT_GTYPE (self, gtype);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
static void FundamentalToString (const Nan::FunctionCallbackInfo<Value> &info) {
|
|
169
|
+
Local<Object> self = info.This ();
|
|
170
|
+
|
|
171
|
+
if (!ValueHasInternalField (self)) {
|
|
172
|
+
Nan::ThrowTypeError ("Object is not a fundamental type");
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
GType gtype = GET_OBJECT_GTYPE (self);
|
|
177
|
+
void *address = Nan::GetInternalFieldPointer (self, 0);
|
|
178
|
+
char *str = g_strdup_printf ("[%s %#zx]", g_type_name (gtype), (size_t) address);
|
|
179
|
+
info.GetReturnValue ().Set (UTF8 (str));
|
|
180
|
+
g_free (str);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
static Local<FunctionTemplate> GetFundamentalBaseTemplate () {
|
|
184
|
+
static Persistent<FunctionTemplate> baseTemplate;
|
|
185
|
+
|
|
186
|
+
if (baseTemplate.IsEmpty ()) {
|
|
187
|
+
auto tpl = New<FunctionTemplate> ();
|
|
188
|
+
tpl->SetClassName (UTF8 ("FundamentalBaseClass"));
|
|
189
|
+
Nan::SetPrototypeMethod (tpl, "toString", FundamentalToString);
|
|
190
|
+
baseTemplate.Reset (tpl);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return New (baseTemplate);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
static void FundamentalClassDestroyed (const Nan::WeakCallbackInfo<GIBaseInfo> &info) {
|
|
197
|
+
GIBaseInfo *gi_info = info.GetParameter ();
|
|
198
|
+
GType gtype = g_registered_type_info_get_g_type (gi_info);
|
|
199
|
+
|
|
200
|
+
auto *persistentTpl = (Persistent<FunctionTemplate> *) g_type_get_qdata (gtype, GNodeJS::template_quark ());
|
|
201
|
+
auto *persistentFn = (Persistent<Function> *) g_type_get_qdata (gtype, GNodeJS::function_quark ());
|
|
202
|
+
delete persistentTpl;
|
|
203
|
+
delete persistentFn;
|
|
204
|
+
|
|
205
|
+
g_type_set_qdata (gtype, GNodeJS::template_quark (), NULL);
|
|
206
|
+
g_type_set_qdata (gtype, GNodeJS::function_quark (), NULL);
|
|
207
|
+
|
|
208
|
+
g_base_info_unref (gi_info);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
static Local<FunctionTemplate> GetFundamentalTemplate (GIObjectInfo *info, GType gtype) {
|
|
212
|
+
void *data = g_type_get_qdata (gtype, GNodeJS::template_quark ());
|
|
213
|
+
|
|
214
|
+
if (data) {
|
|
215
|
+
auto *persistent = (Persistent<FunctionTemplate> *) data;
|
|
216
|
+
return New<FunctionTemplate> (*persistent);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/* The External holds a borrowed pointer; the owned ref is taken by the
|
|
220
|
+
* SetWeak below and released in FundamentalClassDestroyed. `info` stays
|
|
221
|
+
* alive for the template's whole lifetime, so the borrow is safe (mirrors
|
|
222
|
+
* boxed.cc's GetBoxedTemplate). */
|
|
223
|
+
auto tpl = New<FunctionTemplate> (FundamentalConstructor, New<External> (info));
|
|
224
|
+
tpl->SetClassName (UTF8 (g_type_name (gtype)));
|
|
225
|
+
tpl->InstanceTemplate ()->SetInternalFieldCount (1);
|
|
226
|
+
Nan::SetPrototypeTemplate (
|
|
227
|
+
tpl, "__gtype__", v8::BigInt::NewFromUnsigned (Isolate::GetCurrent (), gtype));
|
|
228
|
+
|
|
229
|
+
GType parent_type = g_type_parent (gtype);
|
|
230
|
+
if (parent_type == G_TYPE_INVALID) {
|
|
231
|
+
tpl->Inherit (GetFundamentalBaseTemplate ());
|
|
232
|
+
} else {
|
|
233
|
+
GIObjectInfo *parent_info = (GIObjectInfo *) g_irepository_find_by_gtype (NULL, parent_type);
|
|
234
|
+
if (parent_info != NULL) {
|
|
235
|
+
tpl->Inherit (GetFundamentalTemplate (parent_info, parent_type));
|
|
236
|
+
g_base_info_unref (parent_info);
|
|
237
|
+
} else {
|
|
238
|
+
tpl->Inherit (GetFundamentalBaseTemplate ());
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
auto *persistentTpl = new Persistent<FunctionTemplate> (tpl);
|
|
243
|
+
auto *persistentFn = new Persistent<Function> (Nan::GetFunction (tpl).ToLocalChecked ());
|
|
244
|
+
persistentTpl->SetWeak (
|
|
245
|
+
g_base_info_ref (info), FundamentalClassDestroyed, WeakCallbackType::kParameter);
|
|
246
|
+
|
|
247
|
+
g_type_set_qdata (gtype, GNodeJS::template_quark (), persistentTpl);
|
|
248
|
+
g_type_set_qdata (gtype, GNodeJS::function_quark (), persistentFn);
|
|
249
|
+
|
|
250
|
+
return tpl;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
MaybeLocal<Function> MakeFundamentalClass (GIObjectInfo *info) {
|
|
254
|
+
GType gtype = g_registered_type_info_get_g_type (info);
|
|
255
|
+
|
|
256
|
+
if (gtype == G_TYPE_NONE || gtype == G_TYPE_INVALID)
|
|
257
|
+
return MaybeLocal<Function> ();
|
|
258
|
+
|
|
259
|
+
void *data = g_type_get_qdata (gtype, GNodeJS::function_quark ());
|
|
260
|
+
if (data == NULL) {
|
|
261
|
+
GetFundamentalTemplate (info, gtype);
|
|
262
|
+
data = g_type_get_qdata (gtype, GNodeJS::function_quark ());
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
auto *persistent = (Persistent<Function> *) data;
|
|
266
|
+
return New<Function> (*persistent);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
Local<Value> WrapperFromFundamental (GIObjectInfo *info, void *ptr, ResourceOwnership ownership) {
|
|
270
|
+
if (ptr == NULL)
|
|
271
|
+
return Nan::Null ();
|
|
272
|
+
|
|
273
|
+
/* Resolve the *actual* runtime type of the instance (e.g. GskColorNode)
|
|
274
|
+
* rather than the static return type (GskRenderNode), mirroring how
|
|
275
|
+
* WrapperFromGObject uses G_OBJECT_TYPE. Introspected fundamental types are
|
|
276
|
+
* classed GTypeInstances, so G_TYPE_FROM_INSTANCE is valid here. */
|
|
277
|
+
GIObjectInfo *resolved = NULL;
|
|
278
|
+
GType instance_gtype = G_TYPE_FROM_INSTANCE (ptr);
|
|
279
|
+
if (instance_gtype != G_TYPE_INVALID) {
|
|
280
|
+
GIBaseInfo *found = g_irepository_find_by_gtype (NULL, instance_gtype);
|
|
281
|
+
if (found != NULL) {
|
|
282
|
+
if (IsFundamentalObjectInfo (found))
|
|
283
|
+
resolved = found;
|
|
284
|
+
else
|
|
285
|
+
g_base_info_unref (found);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
auto maybeConstructor = MakeFundamentalClass (resolved != NULL ? resolved : info);
|
|
290
|
+
|
|
291
|
+
if (resolved != NULL)
|
|
292
|
+
g_base_info_unref (resolved);
|
|
293
|
+
|
|
294
|
+
if (maybeConstructor.IsEmpty ())
|
|
295
|
+
return Nan::Null ();
|
|
296
|
+
|
|
297
|
+
Local<Value> args[] = {
|
|
298
|
+
New<External> (ptr),
|
|
299
|
+
New<v8::Int32> ((int32_t) ownership),
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
auto instance = Nan::NewInstance (maybeConstructor.ToLocalChecked (), 2, args);
|
|
303
|
+
if (instance.IsEmpty ())
|
|
304
|
+
return Nan::Null ();
|
|
305
|
+
|
|
306
|
+
return instance.ToLocalChecked ();
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
/*
|
|
311
|
+
* GVariant
|
|
312
|
+
*
|
|
313
|
+
* GVariant is a fundamental ref-counted type, but GI classes it as a
|
|
314
|
+
* GIStructInfo (g_type == G_TYPE_VARIANT), so the object-info machinery above
|
|
315
|
+
* (G_TYPE_FROM_INSTANCE, introspected ref/unref functions) does not apply. It
|
|
316
|
+
* uses the shared FundamentalInstance lifetime with hardcoded g_variant_ref/
|
|
317
|
+
* unref and floating-reference handling (g_variant_ref_sink / take_ref).
|
|
318
|
+
*/
|
|
319
|
+
|
|
320
|
+
/* Matches GIObjectInfoUnrefFunction's signature so FundamentalInstance can call
|
|
321
|
+
* it uniformly; avoids a function-pointer cast. */
|
|
322
|
+
static void VariantUnref (void *data) {
|
|
323
|
+
g_variant_unref ((GVariant *) data);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
bool IsVariantInfo (GIBaseInfo *info) {
|
|
327
|
+
GIInfoType type = g_base_info_get_type (info);
|
|
328
|
+
if (type != GI_INFO_TYPE_STRUCT
|
|
329
|
+
&& type != GI_INFO_TYPE_BOXED
|
|
330
|
+
&& type != GI_INFO_TYPE_UNION
|
|
331
|
+
&& type != GI_INFO_TYPE_OBJECT)
|
|
332
|
+
return false;
|
|
333
|
+
return g_registered_type_info_get_g_type (info) == G_TYPE_VARIANT;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
bool IsVariantTypeInfo (GITypeInfo *type_info) {
|
|
337
|
+
if (g_type_info_get_tag (type_info) != GI_TYPE_TAG_INTERFACE)
|
|
338
|
+
return false;
|
|
339
|
+
GIBaseInfo *iface = g_type_info_get_interface (type_info);
|
|
340
|
+
bool result = IsVariantInfo (iface);
|
|
341
|
+
g_base_info_unref (iface);
|
|
342
|
+
return result;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
static void VariantConstructor (const Nan::FunctionCallbackInfo<Value> &info) {
|
|
346
|
+
if (!info.IsConstructCall ()) {
|
|
347
|
+
Nan::ThrowTypeError ("Not a construct call");
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
Local<Object> self = info.This ();
|
|
352
|
+
|
|
353
|
+
if (!info[0]->IsExternal ()) {
|
|
354
|
+
/* Like the object fundamentals, variants are obtained from function
|
|
355
|
+
* returns or their static constructors (e.g. GLib.Variant.newString),
|
|
356
|
+
* not built with `new`. */
|
|
357
|
+
Nan::ThrowError (
|
|
358
|
+
"Cannot construct GLib.Variant directly; use a static constructor (e.g. GLib.Variant.newString())");
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
void *ptr = External::Cast (*info[0])->Value ();
|
|
363
|
+
auto ownership = (ResourceOwnership) Nan::To<int32_t> (info[1]).ToChecked ();
|
|
364
|
+
|
|
365
|
+
/* Own exactly one full (non-floating) reference for the wrapper's lifetime.
|
|
366
|
+
* A transfer-full return already handed us a reference to adopt (take_ref
|
|
367
|
+
* sinks it if it was floating); otherwise add our own (ref_sink sinks a
|
|
368
|
+
* fresh floating variant, or refs a shared one). */
|
|
369
|
+
if (ownership == kTransfer)
|
|
370
|
+
ptr = g_variant_take_ref ((GVariant *) ptr);
|
|
371
|
+
else
|
|
372
|
+
ptr = g_variant_ref_sink ((GVariant *) ptr);
|
|
373
|
+
|
|
374
|
+
FundamentalInstance *instance = new FundamentalInstance ();
|
|
375
|
+
instance->data = ptr;
|
|
376
|
+
instance->unref = VariantUnref;
|
|
377
|
+
instance->persistent = new Persistent<Object> (self);
|
|
378
|
+
instance->persistent->SetWeak (instance, FundamentalDestroyed, WeakCallbackType::kParameter);
|
|
379
|
+
|
|
380
|
+
Nan::SetInternalFieldPointer (self, 0, ptr);
|
|
381
|
+
SET_OBJECT_GTYPE (self, G_TYPE_VARIANT);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
static Local<FunctionTemplate> GetVariantTemplate () {
|
|
385
|
+
GType gtype = G_TYPE_VARIANT;
|
|
386
|
+
void *data = g_type_get_qdata (gtype, GNodeJS::template_quark ());
|
|
387
|
+
|
|
388
|
+
if (data) {
|
|
389
|
+
auto *persistent = (Persistent<FunctionTemplate> *) data;
|
|
390
|
+
return New<FunctionTemplate> (*persistent);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
auto tpl = New<FunctionTemplate> (VariantConstructor);
|
|
394
|
+
tpl->SetClassName (UTF8 (g_type_name (gtype)));
|
|
395
|
+
tpl->InstanceTemplate ()->SetInternalFieldCount (1);
|
|
396
|
+
Nan::SetPrototypeTemplate (
|
|
397
|
+
tpl, "__gtype__", v8::BigInt::NewFromUnsigned (Isolate::GetCurrent (), gtype));
|
|
398
|
+
tpl->Inherit (GetFundamentalBaseTemplate ());
|
|
399
|
+
|
|
400
|
+
/* G_TYPE_VARIANT is a static built-in fundamental that never unloads, so
|
|
401
|
+
* (unlike the per-namespace fundamental object templates) there is no
|
|
402
|
+
* class-destroyed weak callback to tear the cache down. */
|
|
403
|
+
auto *persistentTpl = new Persistent<FunctionTemplate> (tpl);
|
|
404
|
+
auto *persistentFn = new Persistent<Function> (Nan::GetFunction (tpl).ToLocalChecked ());
|
|
405
|
+
g_type_set_qdata (gtype, GNodeJS::template_quark (), persistentTpl);
|
|
406
|
+
g_type_set_qdata (gtype, GNodeJS::function_quark (), persistentFn);
|
|
407
|
+
|
|
408
|
+
return tpl;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
Local<Function> MakeVariantClass (GIBaseInfo *info) {
|
|
412
|
+
void *data = g_type_get_qdata (G_TYPE_VARIANT, GNodeJS::function_quark ());
|
|
413
|
+
if (data == NULL) {
|
|
414
|
+
GetVariantTemplate ();
|
|
415
|
+
data = g_type_get_qdata (G_TYPE_VARIANT, GNodeJS::function_quark ());
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
auto *persistent = (Persistent<Function> *) data;
|
|
419
|
+
return New<Function> (*persistent);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
Local<Value> WrapperFromVariant (void *ptr, ResourceOwnership ownership) {
|
|
423
|
+
if (ptr == NULL)
|
|
424
|
+
return Nan::Null ();
|
|
425
|
+
|
|
426
|
+
Local<Function> constructor = MakeVariantClass (NULL);
|
|
427
|
+
|
|
428
|
+
Local<Value> args[] = {
|
|
429
|
+
New<External> (ptr),
|
|
430
|
+
New<v8::Int32> ((int32_t) ownership),
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
auto instance = Nan::NewInstance (constructor, 2, args);
|
|
434
|
+
if (instance.IsEmpty ())
|
|
435
|
+
return Nan::Null ();
|
|
436
|
+
|
|
437
|
+
return instance.ToLocalChecked ();
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
void RefVariantForTransferFullIn (GITypeInfo *type_info, GIArgument *arg) {
|
|
441
|
+
if (arg->v_pointer == NULL)
|
|
442
|
+
return;
|
|
443
|
+
|
|
444
|
+
/* The callee takes ownership of one reference; keep our own so the JS
|
|
445
|
+
* wrapper isn't unref'd out from under it (counterpart of the boxed/object
|
|
446
|
+
* transfer-full helpers). */
|
|
447
|
+
if (IsVariantTypeInfo (type_info))
|
|
448
|
+
arg->v_pointer = g_variant_ref ((GVariant *) arg->v_pointer);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* fundamental.h
|
|
3
|
+
*
|
|
4
|
+
* Wrapping of GLib *fundamental* ref-counted types that are not GObjects —
|
|
5
|
+
* e.g. GskRenderNode, which has its own gsk_render_node_ref()/unref() instead
|
|
6
|
+
* of the GObject machinery. GObject-Introspection reports these as
|
|
7
|
+
* GI_INFO_TYPE_OBJECT (a GIObjectInfo) with g_object_info_get_fundamental()
|
|
8
|
+
* == TRUE, but running the GObject wrapper path over them fires G_IS_OBJECT
|
|
9
|
+
* assertions (#468). They get their own thin wrapper here.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
#pragma once
|
|
13
|
+
|
|
14
|
+
#include <node.h>
|
|
15
|
+
#include <nan.h>
|
|
16
|
+
#include <girepository.h>
|
|
17
|
+
#include <glib-object.h>
|
|
18
|
+
|
|
19
|
+
#include "value.h"
|
|
20
|
+
|
|
21
|
+
using v8::Function;
|
|
22
|
+
using v8::Local;
|
|
23
|
+
using v8::MaybeLocal;
|
|
24
|
+
using v8::Value;
|
|
25
|
+
|
|
26
|
+
namespace GNodeJS {
|
|
27
|
+
|
|
28
|
+
/* True when the GIObjectInfo describes a fundamental (non-GObject) type. */
|
|
29
|
+
bool IsFundamentalObjectInfo (GIObjectInfo *info);
|
|
30
|
+
|
|
31
|
+
/* Build (or fetch the cached) constructor for a fundamental type. Mirrors
|
|
32
|
+
* MakeClass()/MakeBoxedClass(); JS attaches the introspected methods to it. */
|
|
33
|
+
MaybeLocal<Function> MakeFundamentalClass (GIObjectInfo *info);
|
|
34
|
+
|
|
35
|
+
/* Wrap a fundamental instance for return to JS, taking a reference according
|
|
36
|
+
* to `ownership` (kTransfer: adopt the incoming ref; otherwise add our own). */
|
|
37
|
+
Local<Value> WrapperFromFundamental (GIObjectInfo *info, void *ptr, ResourceOwnership ownership);
|
|
38
|
+
|
|
39
|
+
/* Add the reference a transfer-full IN argument's callee will own, so the
|
|
40
|
+
* instance isn't finalized out from under it when the JS wrapper is GC'd.
|
|
41
|
+
* Fundamental counterpart of RefObjectForTransferFullIn / CopyBoxedForTransferFullIn. */
|
|
42
|
+
void RefFundamentalForTransferFullIn (GITypeInfo *type_info, GIArgument *arg);
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
/*
|
|
46
|
+
* GVariant is also a fundamental (non-GObject) ref-counted type, but GObject-
|
|
47
|
+
* Introspection reports it as a GI_INFO_TYPE_STRUCT (a GIStructInfo) with
|
|
48
|
+
* g_type == G_TYPE_VARIANT, not as a fundamental GIObjectInfo. It is refcounted
|
|
49
|
+
* with g_variant_ref/unref (and has floating references), so it gets the same
|
|
50
|
+
* single-owned-reference wrapper as the object fundamentals above rather than
|
|
51
|
+
* the boxed copy/free path. Its JS class is still built from the struct info
|
|
52
|
+
* (so its introspected methods attach), just with this ref/unref lifetime.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
/* True when `info` is a registered type whose g_type is G_TYPE_VARIANT. */
|
|
56
|
+
bool IsVariantInfo (GIBaseInfo *info);
|
|
57
|
+
|
|
58
|
+
/* True when `type_info` is an interface referring to G_TYPE_VARIANT. */
|
|
59
|
+
bool IsVariantTypeInfo (GITypeInfo *type_info);
|
|
60
|
+
|
|
61
|
+
/* Build (or fetch the cached) constructor for GLib.Variant. */
|
|
62
|
+
Local<Function> MakeVariantClass (GIBaseInfo *info);
|
|
63
|
+
|
|
64
|
+
/* Wrap a GVariant for return to JS, taking a reference according to `ownership`
|
|
65
|
+
* (kTransfer: adopt the incoming reference; otherwise add our own). */
|
|
66
|
+
Local<Value> WrapperFromVariant (void *ptr, ResourceOwnership ownership);
|
|
67
|
+
|
|
68
|
+
/* Transfer-full IN counterpart for GVariant (adds the callee's reference). */
|
|
69
|
+
void RefVariantForTransferFullIn (GITypeInfo *type_info, GIArgument *arg);
|
|
70
|
+
|
|
71
|
+
};
|
package/src/gi.cc
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#include "async_call_environment.h"
|
|
6
6
|
#include "boxed.h"
|
|
7
7
|
#include "debug.h"
|
|
8
|
+
#include "fundamental.h"
|
|
8
9
|
#include "function.h"
|
|
9
10
|
#include "gi.h"
|
|
10
11
|
#include "gobject.h"
|
|
@@ -170,7 +171,11 @@ NAN_METHOD(MakeFunction) {
|
|
|
170
171
|
|
|
171
172
|
NAN_METHOD(MakeObjectClass) {
|
|
172
173
|
BaseInfo gi_info(info[0]);
|
|
173
|
-
|
|
174
|
+
// Fundamental (non-GObject) types such as GskRenderNode need their own
|
|
175
|
+
// ref/unref-based wrapper rather than the GObject machinery (#468).
|
|
176
|
+
auto klass = GNodeJS::IsFundamentalObjectInfo(*gi_info)
|
|
177
|
+
? GNodeJS::MakeFundamentalClass(*gi_info)
|
|
178
|
+
: GNodeJS::MakeClass(*gi_info);
|
|
174
179
|
if (!klass.IsEmpty())
|
|
175
180
|
info.GetReturnValue().Set(klass.ToLocalChecked());
|
|
176
181
|
}
|
|
@@ -405,6 +410,14 @@ NAN_METHOD(GetModuleCache) {
|
|
|
405
410
|
info.GetReturnValue().Set(Nan::New<Object>(GNodeJS::moduleCache));
|
|
406
411
|
}
|
|
407
412
|
|
|
413
|
+
NAN_METHOD(SetLazyClassRegister) {
|
|
414
|
+
GNodeJS::ObjectClass::SetLazyClassRegister(info);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
NAN_METHOD(SetInterfaceMethodsApplier) {
|
|
418
|
+
GNodeJS::SetInterfaceMethodsApplier(info);
|
|
419
|
+
}
|
|
420
|
+
|
|
408
421
|
NAN_METHOD(RegisterClass) {
|
|
409
422
|
GNodeJS::ObjectClass::RegisterClass(info);
|
|
410
423
|
}
|
|
@@ -413,6 +426,10 @@ NAN_METHOD(RegisterVFunc) {
|
|
|
413
426
|
GNodeJS::ObjectClass::RegisterVFunc(info);
|
|
414
427
|
}
|
|
415
428
|
|
|
429
|
+
NAN_METHOD(CallVFunc) {
|
|
430
|
+
GNodeJS::ObjectClass::CallVFunc(info);
|
|
431
|
+
}
|
|
432
|
+
|
|
416
433
|
void InitModule(Local<Object> exports, Local<Value> module, void *priv) {
|
|
417
434
|
GNodeJS::AsyncCallEnvironment::Initialize();
|
|
418
435
|
|
|
@@ -431,8 +448,11 @@ void InitModule(Local<Object> exports, Local<Value> module, void *priv) {
|
|
|
431
448
|
Nan::Export(exports, "StartLoop", StartLoop);
|
|
432
449
|
Nan::Export(exports, "IsRunningMicrotasks", IsRunningMicrotasks);
|
|
433
450
|
Nan::Export(exports, "GetLoopStack", GetLoopStack);
|
|
451
|
+
Nan::Export(exports, "SetLazyClassRegister", SetLazyClassRegister);
|
|
452
|
+
Nan::Export(exports, "SetInterfaceMethodsApplier", SetInterfaceMethodsApplier);
|
|
434
453
|
Nan::Export(exports, "RegisterClass", RegisterClass);
|
|
435
454
|
Nan::Export(exports, "RegisterVFunc", RegisterVFunc);
|
|
455
|
+
Nan::Export(exports, "CallVFunc", CallVFunc);
|
|
436
456
|
|
|
437
457
|
Nan::Set(exports, UTF8("System"), GNodeJS::System::GetModule());
|
|
438
458
|
Nan::Set(exports, UTF8("Cairo"), GNodeJS::Cairo::GetModule());
|