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.
Files changed (51) hide show
  1. package/README.md +45 -161
  2. package/bin/node-gtk.js +12 -1
  3. package/binding.gyp +21 -0
  4. package/lib/binding/node-v127-linux-x64/node_gtk.node +0 -0
  5. package/lib/bootstrap.js +43 -11
  6. package/lib/esm/hooks.mjs +49 -0
  7. package/lib/esm/register.mjs +17 -0
  8. package/lib/index.js +1 -2
  9. package/lib/index.mjs +25 -0
  10. package/lib/inspect.js +1 -1
  11. package/lib/loop.js +5 -0
  12. package/lib/module.js +8 -2
  13. package/lib/overrides/Gtk-4.0.js +6 -27
  14. package/lib/register-class.js +86 -3
  15. package/lib/styles.d.ts +81 -0
  16. package/lib/styles.js +428 -0
  17. package/package.json +15 -2
  18. package/src/boxed.cc +13 -5
  19. package/src/closure.cc +19 -6
  20. package/src/closure.h +8 -4
  21. package/src/function.cc +59 -5
  22. package/src/fundamental.cc +451 -0
  23. package/src/fundamental.h +71 -0
  24. package/src/gi.cc +21 -1
  25. package/src/gobject.cc +268 -9
  26. package/src/gobject.h +5 -0
  27. package/src/modules/cairo/context.cc +103 -103
  28. package/src/modules/cairo/font-extents.cc +6 -2
  29. package/src/modules/cairo/generator.js +1 -1
  30. package/src/modules/cairo/glyph.cc +6 -2
  31. package/src/modules/cairo/path.cc +6 -2
  32. package/src/modules/cairo/rectangle-int.cc +6 -2
  33. package/src/modules/cairo/rectangle.cc +6 -2
  34. package/src/modules/cairo/text-cluster.cc +6 -2
  35. package/src/modules/cairo/text-extents.cc +6 -2
  36. package/src/modules/system.cc +4 -4
  37. package/src/util.h +3 -3
  38. package/src/value.cc +44 -8
  39. package/src/value.h +2 -2
  40. package/tools/README.md +52 -2
  41. package/tools/create-app.js +246 -0
  42. package/tools/generate-types.js +80 -3
  43. package/tools/list-libraries.js +125 -0
  44. package/tools/templates/app/README.md.tmpl +97 -0
  45. package/tools/templates/app/gitignore.tmpl +10 -0
  46. package/tools/templates/app/package.json.tmpl +26 -0
  47. package/tools/templates/app/src/main.ts.tmpl +110 -0
  48. package/tools/templates/app/src/welcome.ts.tmpl +41 -0
  49. package/tools/templates/app/style.css.tmpl +19 -0
  50. package/tools/templates/app/tsconfig.json.tmpl +19 -0
  51. /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
- auto klass = GNodeJS::MakeClass(*gi_info);
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());